Verificación del portal de servicios públicos regionales bajo carga a través de titiritero

Hola Habr! Usted, curiosamente, está viendo la "epopeya del Salvaje Oeste estadounidense sobre la distribución de las parcelas de tierra: vaya primero y pegue una bandera para apostar" o quizás incluso participe en ella. Más precisamente en su versión moderna: sea el primero en solicitar servicios públicos para recibir dinero para los niños u obtener un pase para salir de la casa. Mirando todo esto, me gustaría compartir la experiencia de nuestro equipo en las pruebas y participar en la preparación de un portal regional de servicios para la prestación del servicio "Registro de primera clase". También es muy similar al efecto habra y, creo, estuvo cerca de lo que sucedió hace un par de días con el portal federal gosuslugi.ru, pero a escala regional.

Superamos este desafío en Khabarovsk en enero de este año y recientemente participamos en la preparación de un servicio similar para emitir permisos de caza en otra región. A continuación se muestra una pequeña experiencia que le dará la oportunidad de analizar el tema de la preparación del trabajo de los portales de servicios públicos regionales para los períodos pico desde otra perspectiva.

Y para empezar, una foto de un autobús negro, que estuvo de servicio en la escuela durante tres días las 24 horas, en el que el autor de estas líneas confirmó su turno entre sus padres hace tres años. Al menos nuestros padres se han unido. Ver en invierno en Khabarovsk a -30 grados sigue siendo un placer.

imagen

En el proceso de preparación para el registro máximo en el primer grado, varios equipos trabajaron, porque participa de una forma u otra: el operador del centro de datos, el operador y el desarrollador del sistema de información del portal regional, el operador y el desarrollador del sistema de información educativo integrado, soporte técnico para los usuarios del portal regional. En iondv realizamos la última tarea, monitoreando independientemente el estado del portal y brindando soporte a los usuarios.

Nuestro papel en la preparación es organizar pruebas y recomendaciones sobre configuraciones de almacenamiento en caché en nginx, bueno, también preparamos instrucciones para los usuarios con el "comportamiento" recomendado.

Para aquellos que no conocen el problema de la escritura en el 1er grado
, . . , , - ( , — ), , - , , . , , , – , . .

1- , . 0:00 , 10:00 26 . , – . 10:00 , — , - .

. . 2017 . . , , . .

Un servicio para un recurso demandado como tarea técnica.


El problema en servicios como "escribir a 1er grado" en el indicador integral de la carga (o probabilidad de consultas) que tiende a la "función delta" (función δ, función Dirac) es claramente visible en los gráficos en forma de picos. En este momento, hay un aumento múltiple de llamadas en un corto período de tiempo.

Función δ y estadísticas de consulta pico

Nuestra experiencia dice que la tarea principal de la capacitación no es aumentar los recursos. La tarea es minimizar el número potencial de solicitudes por segundo, estirarlas durante un período y preparar el sistema para la carga restante. En este caso, es necesario encontrar y acelerar los cuellos de botella; esto dará el mayor efecto de acuerdo con los principios de la teoría de sistemas acotados (principios de Goldratt). Y de lo contrario, es el cuello de botella que fallará. Todo el sistema debería funcionar de él: el principio de "drum-buffer-rope".

Es físicamente imposible derramar todo el volumen en 10 minutos de reloj de arena en 1 minuto; es obvio que colapsarán. Del mismo modo para la prestación de servicios. No sorprende a nadie, cuando es el turno del MFC y los escándalos de recibir servicios, pero sorprende a todos, por qué el portal se cayó.

Existen diferentes patrones de comportamiento de manejo de carga de la teoría de colas :

  • Puede poner a los usuarios en espera, es decir aumentar la cola;
  • simplemente puede negarse a atender a los que vinieron después, por ejemplo, hasta que se procesen los anteriores;
  • Puede intentar aumentar sin fin la productividad.

La experiencia está en algún punto intermedio. De hecho, para un servicio con un recurso limitado proporcionado por una región o estado, no solo la velocidad es importante, sino, en primer lugar, la preservación de la justicia social, es decir, condiciones iguales para todos. Al mismo tiempo, si el usuario no ha recibido lo que necesita, inicia una nueva solicitud. En este caso, las solicitudes crecen en una avalancha, formando un modelo de ataque " efecto de acumulación de perros " (efecto de acumulación de perros, estampida de caché, tormenta de aciertos): el usuario ya canceló la solicitud e inició una nueva, mientras que la anterior aún está en la cola para ser procesada.

Este proceso refuerza el hecho de que familias enteras participan en la presentación: papá y mamá llenan las solicitudes al mismo tiempo, y a menudo envían solicitudes varias veces para mayor confiabilidad. Y además, a menudo también en varias pestañas y varios navegadores. Por lo tanto, la carga máxima esperada generalmente tiene sentido multiplicarse por 2-3 veces, del número de aquellos que realmente solicitan dichos servicios.

Retiro de justicia
, «», . ? «» , . . — , . « ». . .

Organización de la prestación de servicios.


Calculamos el número esperado de solicitantes con base en una combinación de datos sobre el número total de solicitudes presentadas el año pasado y datos por minuto para otras regiones. Por lo general, el pico de aplicaciones cae en 5-10 minutos, incluso porque los portales casi no responden durante los primeros tres a cinco minutos, y los usuarios posteriores completan el formulario de 1 a 5 minutos (no se sorprendan, muchos lo completan desde el teléfono incluso en condiciones "nerviosas") .

Un modelo de cálculo aproximado para las 1000 aplicaciones condicionales por hora es el siguiente:

  • pico de 5 a 10 minutos desde el inicio y el 80% de las solicitudes se presentarán bajo la regla de Paretto
  • Convencionalmente, planificamos 160 aplicaciones por minuto o 3 aplicaciones por segundo.

De hecho, la primera presentación se produjo después de un minuto y 45 segundos, y el pico de solicitudes pasó de 4 minutos.

Para reducir la carga en ESIA y en el sistema al generar sesiones de autorización, las instrucciones sugieren que los usuarios inicien sesión con anticipación y alarguen la vida útil de la sesión. De hecho, 50% fueron autorizados en 1 hora y ~ 90% en media hora. Descubrimos anteriormente que los usuarios comenzaron a iniciar sesión en el portal 10 minutos antes del inicio del servicio, y la autorización comenzó a funcionar de manera inestable. Es difícil decir por qué. Quizás la razón es que cuando el trabajo técnico se lleva a cabo en Moscú por la noche, en Khabarovsk tenemos apenas el comienzo de la jornada laboral.

Retiro sobre instrucción y arreglos organizacionales
.

, « » . .. . , - ..

, , , . - . , , .

Es imposible eliminar la "función delta" cuando el formulario se vuelve a cargar a las 00:00. El objetivo de este procedimiento es que el servicio aparece en un momento dado. Pero puede intentar reducir el número de solicitudes del navegador en todas las rutas de usuario esperadas y, por lo tanto, dejar la carga en el sistema solo de las necesarias: formulario, directorios dinámicos y envío de aplicaciones.

La configuración de nginx en sí misma es bastante estándar. Aquí es más importante elegir las limitaciones que el sistema puede soportar. Recógelos, es decir comenzará a poner en cola las solicitudes cuando se espera que el servidor llegue al límite de sus capacidades.

Bueno, y lo más importante, forzamos el almacenamiento en caché (proxy_cache) y aumentamos la vida útil de los datos "caduca" en nginx para todas las rutas estáticas y, cuando sea posible, las páginas dinámicas en las que no hay sesiones. Por cierto, este es un error común al almacenar en caché: escribir en los datos de caché (a veces incluso estáticos) en los que se almacena la sesión de otra persona, el resultado suele ser eliminar estas cookies de los encabezados si el servidor no puede separar los tipos de datos.

En el navegador para el usuario, parece actualizar páginas de archivos descargados del disco o memoria. Pero incluso cuando el usuario los obtiene del servidor, se toman del caché nginx. Los directorios mismos, por supuesto, se almacenan en caché en el propio sistema.

imagen

Esto redujo el número de solicitudes potenciales de 89 solicitudes a 14 y el volumen de 2.1 MB (para 1000 usuarios que actualizaron la página, este es un pico potencial de 4-8 Gbit / s) a 38 Kb (todos recordamos webpack, pero para plataformas empresariales esto no es siempre fácil de hacer). Según los resultados del pasaje, aún era necesario almacenar en caché no solo en el sistema, sino también en nginx algunos de los directorios de los clasificadores de formularios y dinámicos que no se utilizan en el momento pico y para forzar la vida útil de los mismos. Y con un aumento en la carga, generalmente tiene sentido colocar en la página principal totalmente estática con el enrutamiento de los usuarios al servicio deseado o crear un recurso separado para el servicio.

Para reducir la carga en el envío, se desactivaron los borradores y el llenado automático de datos para el niño. Todos los usuarios tienen diferentes velocidades de entrada de datos, lo que elimina la apariencia de un formulario que está completamente listo para enviar y evita la función delta para enviar aplicaciones, todas 1000 en un minuto. Al mismo tiempo, se mantiene la justicia social, aunque, por supuesto, aparecen quejas.

No describiré la optimización del sistema en sí mismo: durante las pruebas de carga, se identificaron cuellos de botella, principalmente en las consultas DBMS y los índices y consultas en sí se optimizaron.

Probablemente la optimización más importante es simplificar el formulario. ¿Qué afecta más a la velocidad cuando se implementa en un formulario?

  • — , , . — 5-10 ( iPhone ) 5- 375 / (1 10 , application/x-www-form-urlencoded – 20 ), 100 625 /. 100/ — . , « ». — ? , . , ?
  • Guías sofisticados. La carga generalmente aumenta al usar el directorio de direcciones FIAS o CLADR. Los problemas aquí se deben al tamaño: FIAS ocupa hasta 40 GB en la base de datos y lleva tiempo buscarlo. Décimas de segundo, pero multiplicado por 1000 solicitudes simultáneas, cargue cualquier sistema. Sin una preparación especial, posiblemente en forma de un servicio web separado y en un recurso separado, es difícil soportar la carga; por lo tanto, a menudo usan un campo de texto sin formato para la dirección.

Bueno, pasemos a las pruebas.

Prueba de carga en preparación


Las pruebas se realizaron a través de titiriteros, emulando las acciones del usuario en el navegador Crominium. Yanedeks.tank y JMeter superaron la protección contra ataques, ya que generan muchas de las mismas solicitudes. Además, estas pruebas coinciden débilmente con el perfil de consultas reales al cambiar el comportamiento del sistema bajo carga. Además, los servidores almacenan en caché las solicitudes, y es difícil reproducir parte de los procesos en ellos (por ejemplo, autorización). Por cierto, de uno de los seminarios devDV tenemos una presentación con una presentación sobre el uso del titiritero para las pruebas, que incluye cargar, enlace al video .

Para comenzar, compilamos un perfil de comportamiento del usuario y dividimos el procedimiento en etapas clave:

  1. autorización masiva en ESIA
  2. actualización única del formulario de servicio,
  3. alimentación masiva

Para cada una de las etapas hicimos una prueba por separado.

El año pasado, hubo dificultades en la etapa de autorización en ESIA, pero probarlo a gran escala es difícil. El sistema es externo, se activa la protección contra ataques y prohibiciones de autorización. Sin embargo, es posible formular un perfil de prueba para probar con precisión los cuellos de botella del sistema bajo prueba; por lo general, este es el número de sesiones autorizadas simultáneamente y los valores de autorización planificados por minuto, que pueden regularse mediante recomendaciones.
En la prueba, el contenedor es importante para organizar varios hilos, utilizamos el 'puppeteer-cluster'. Pero generalmente es más complicado manejar excepciones y cambiar el comportamiento del portal bajo carga: a menudo se revelan elementos de diseño que aparecen dos veces. O los elementos no aparecen si algunos datos no se cargaron como se esperaba. Estos son todos los errores que los usuarios verán y volverán a cargar la página, lo que significa que crearán una carga adicional. Hay dos formas: implementar el manejo de excepciones en la prueba. O modificar el portal.

La prueba en sí es simple. A continuación se muestra un fragmento de hacer clic en el botón "Iniciar sesión" en el portal de servicios para ingresar datos en ESIA.

await page.waitForSelector(AUTH_AVAIL,{timeout:OPT_ELEM_WAIT_TIME});
const needAuth = await page.$(ELEM_AUTH_IN);
if (!needAuth) throw (new Error(`  `));
        
await page.waitForSelector(AUTH_BUT, OPT_ELEMENT_VISIBLE);
await page.click(AUTH_BUT);
await waitNewUrl(page, 'https://esia.gosuslugi.ru/idp/rlogin?cc=bp', OPT_PAGE_WAIT_TIME);
await page.waitForSelector('#mobileOrEmail', OPT_ELEMENT_VISIBLE);
let text = await elemGetText(page, '#authnFrm > div.login-slils-box > div > div.detected > div.left > div.this-user');
if (text) 
   text = text.replace(/ -\(\)/g, '');        
if (text && text.indexOf(user) === -1) {
  await page.click('div.click-to-another > a');
  await page.waitForSelector('#authnFrm > div.login-slils-box > div >' +
                ' div.detected > div.left > div.this-user', OPT_ELEMENT_INVISIBLE);
}
await page.waitForSelector('#password', OPT_ELEMENT_VISIBLE);
await page.type('#mobileOrEmail', user);
await page.type('#password', pwd);
await page.click('#loginByPwdButton');

Verificación de la actualización del formulario de solicitud de usuarios pendientes "abriendo el registro". La prueba de reinicio es esencialmente un paso, pero es importante verificar los tipos de errores devueltos: la red es un problema, un error de nginx, un error del servidor y si el formulario cumple con los criterios. Y la dificultad es generar el volumen máximo de solicitudes en la menor cantidad de tiempo y no caer bajo las restricciones de protección (sin embargo, durante las pruebas se puede cambiar, por otro lado, también es una verificación de la configuración de infraestructura de red y servidor y WAF).

Tales pruebas en titiriteros requieren muchos recursos para funcionar. De hecho, resultó que necesita al menos 2 núcleos contra el primer núcleo del subsistema front-end y un canal muy amplio. Pero al alquilarlos en la nube, esto es bastante asequible. Utilizamos Yandex.cloud.

En la prueba, la autorización se implementa primero en ESIA para cada flujo por separado. Después de eso, se inicia un navegador separado para cada hilo y en el marco de una instancia se lleva a cabo un número determinado de actualizaciones. Después de eso, la instancia se reinicia. La verificación en sí misma puede incluir una ruta típica, por ejemplo, la página principal, la forma del servicio. Pero más a menudo es suficiente solo actualizar completamente el servicio y verificar el directorio necesario para que el servicio se pueda enviar, todo como en las instrucciones para los usuarios.

imagen

Un fragmento de la prueba para abrir la página principal y actualizar la página.

try {
  await page.setViewport(PUP_OPT);
  await page.goto(BASE_URL);
  await page.setCookie(...cookies[worker.id]);
  await page.goto(`${BASE_URL}/nd/lk/form/dnv.htm`);
  rdyRefresh++;
} catch (err) {
  console.error(`#       ${data}: ${err.message}`);
  getErr++;
  await page.screenshot({path: filename});
}
for (let i = 0; i < AMOUNT_REFRESH - 1; i++) {
  const filenameIter = path.join(BASE_DIR, PIC_DIR, `${data}-${i}.png`);
   try {
       await page.reload({waitUntil: ["networkidle0", "domcontentloaded"]});
        rdyRefresh++;
    } catch (err) {
        if (!err.message.includes('Navigation failed because browser')) {
           console.error(`#     ${data}-${i}: ${err.message}`);
           getErr++;
           await page.screenshot({path: filenameIter});
        }
   }
}

Para la carga mediante el envío de aplicaciones, se implementó todo el ciclo de verificación, con una recarga del formulario y la verificación de la entrada de todos los datos.

Fragmento.

for (let i = 0; i < AMOUNT_RESEND; i++) {
   const filename = path.join(BASE_DIR, PIC_DIR, `${data}-${i}.png`);
  try {
     await page.goto('https://uslugi27.ru/nd/lk/form/dnv.htm');
  } catch (err) {
      console.error(`#      1  ${data}-${i}: ${err.message}`);
      await page.screenshot({path: filename});
      getErr++;
      continue;
 }
 try {
     const FORM_PREF = '#createForm > div:nth-child(4) > ';
     await clickDelayed(page,`${FORM_PREF}fieldset.petgroup.ungroupped-attrs > div > div:nth-child(4) > div.col-md-9.attr-data`);
// <…>
     await page.type(`${FORM_PREF}fieldset:nth-child(2) > div > div:nth-child(1) > div.col-md-9.attr-data > input`, '');
// <…>
  } catch (err) {
      console.error(`#      ${data}-${i}: ${err.message}`);
      await page.screenshot({path: filename});
     continue;
  }
  try {
      await page.click('#createForm > div.col_100.controls > button.btn.btn-primary.pull-right.next');
      await clickDelayed(page,`#createForm > div:nth-child(5) > fieldset > div > div:nth-child(1) > div > div`);
       await page.click('#createForm > div:nth-child(5) > fieldset > div > div:nth-child(2) > div > div');
       await page.click('#createForm > div.col_100.controls > button.btn.btn-success.pull-right.submit');
  } catch (err) {
    console.error(`#     ${data}-${i}: ${err.message}`);
    await page.screenshot({path: filename});
    sendErr++;
    continue;
  }

Por cierto, la prueba puede acelerarse si ingresa todos los datos no del titiritero mediante el constructo page.type de wait, pero transfiere esta lógica al navegador en sí. Pero luego aumenta la complejidad de los errores de captura. Al igual que

document.querySelector('#createForm > div:nth-child(4) > fieldset.petgroup.ungroupped-attrs > div > div:nth-child(4) > div.col-md-9.attr-data').click();
 document.querySelector('#createForm > div:nth-child(4) > fieldset:nth-child(2) > div > div:nth-child(1) > div.col-md-9.attr-data > input').value = '';

Durante las pruebas, proporcionamos varios miles de autorizaciones de ESIA y unas 16 mil solicitudes enviadas. ¿Cómo fue la restauración de un sistema productivo de información educativa después de tantas declaraciones? Ni siquiera pregunte. Esta es una historia completamente diferente.

El principal resultado visible de este proceso fue que los medios locales estaban aburridos ahora en los días de inscripción en primer grado. El servicio ha abandonado el área de medios.

Paralelamente, creamos un panel para monitorear el desempeño del formulario basado en Grafana: la cantidad de aplicaciones, la cantidad de llamadas, las métricas de Yandex, etc. Pero dejaremos este tema para la próxima vez.

Bueno, me gustaría felicitar a todos los que están relacionados con el tema de mejorar la calidad de la prestación de servicios estatales y municipales en forma electrónica. Este trabajo preparatorio sin fin no fue en vano; después de todo, en abril y mayo, el número de solicitudes presentadas aumentó significativamente.

All Articles