Inteligencia de negocios en ruso - Quintetos

En una de las notas de nuestro blog, cubrimos el enfoque del almacenamiento y procesamiento de datos , sobre el cual recibimos varias preguntas bastante esperadas de dicho plan: "En general, estamos esperando la implementación, ahora vuela ...". Con base en los resultados de varias implementaciones, hablaré sobre los pros y los contras de este enfoque utilizando uno de nuestros desarrollos como ejemplo.


Por lo general, ofrecemos a nuestros clientes una herramienta de BI bastante potente y flexible que puede resolver todos sus problemas, sin embargo, este es un producto comercial extranjero y los clientes están cada vez más interesados ​​en el tema de la sustitución de importaciones. Como parte de la exploración de nuestras perspectivas a este respecto, comenzamos a probar nuestro propio conjunto de herramientas de BI utilizando soluciones de código abierto y una plataforma de desarrollo basada en quintetos.




Tomamos nuestro producto comercial existente como referencia, por lo que realizaremos una comparación con él siempre que sea posible.


La tarea consistía en crear los siguientes componentes:


  • una base de datos para almacenar marts de datos e información de servicio (usuarios, configuraciones, etc.);
  • interfaz web del sistema y su ORM;
  • Funcionalidad de BI: carga de datos, informes personalizados, gráficos, tablas dinámicas.

Como base, tomamos una plataforma de desarrollo que incluye un modelo de datos, un diseñador de consultas, un motor de plantillas y admite un modelo a seguir para el control de acceso de los usuarios.


El objeto de la orden es la conciliación de los extractos bancarios y el análisis de sus datos acumulados durante los últimos 7 años. Los datos de origen se almacenan en HDFS, los informes se calculan en el mismo lugar, luego sus resultados caen en la ventana de la base de datos relacional. Los escaparates contienen aproximadamente 300 GB de datos para varias docenas de formularios de informes diferentes y varios cientos de informes relacionados. El sistema debe atender a 20 usuarios con carga máxima, el tiempo de respuesta de la interfaz debe ser de 1 segundo.


La creación de una estructura de datos no nos llevó mucho tiempo: el editor de tipos de plataforma le permite crear y describir objetos de negocio tal cual, sin la necesidad de adaptar los requisitos del usuario a los detalles del entorno (tipos y dimensiones de datos, claves, restricciones, nombres de campos de datos, identificadores, etc.). Esta es la primera ventaja de los quintetos que podemos solucionar.


Así es como se crea la estructura de datos: definimos los términos necesarios y a partir de ellos formamos los objetos de nuestra área temática:



Después de varios minutos de actividad en formato copiar / pegar, obtuvimos la estructura de datos requerida para un formulario y varios directorios auxiliares. La estructura de los datos del formulario (después de la descomposición por parte del analista) se ve así:




Un analista familiarizado con el sentido comercial de los datos presentados aquí lee lo siguiente: cada instancia F110 (Formulario 110 en terminología CB) tiene una precisión dada (puede ser "exacta" o "redondeada") e incluye un conjunto de códigos, para cada uno de los cuales se indican cantidades en rublos y moneda.


En el navegador de datos, donde los datos se presentan de acuerdo con la estructura especificada, vemos una tabla sobre las instancias de formularios existentes en el sistema:




El valor de identificación del formulario es su fecha de informe, los códigos de informe se almacenan en forma de una matriz subordinada, cuyo tamaño vemos entre paréntesis.


Como se mencionó, descomponemos un poco los datos, en comparación con la estructura original, para no almacenar largas filas de valores repetidos en la base de datos, como lo que ve un programador o administrador de base de datos:


Tabla con datos en el sistema de referencia:


Por cierto, es por eso que estamos posicionando la plataforma (en adelante la llamaremos Integral) como una herramienta de desarrollo para el analista, no para el programador.


La estructura de datos auxiliares es inconmensurablemente más grande, porque almacena todos los datos iniciales, la configuración del informe, las reglas para verificar la integridad de los datos dentro del informe y en los informes relacionados, el historial de cálculos y conciliaciones, así como algunas reglas para la transformación del negocio de datos durante la construcción del informe:



(la estructura no se da en su totalidad)


Cuando la estructura de datos está lista, puede cargar datos en ella. La manera más fácil aquí es cargar un archivo preparado en el formato Integral (análogo a .csv, pero con marcado de tipo). Este formato contiene una descripción de los datos y los datos en sí.


Ver archivo

En el ejemplo a continuación, las primeras 3 líneas del archivo describen la estructura del formulario (si no está en el sistema, se creará), y luego los datos en sí, los parámetros del formulario y los parámetros de los objetos de informe subordinados a él.


268:110:DATE;277;270; 277::SHORT; 270:  :SHORT;  :SIGNED;   :SIGNED; 268::20121231;281;; 270::A/5.2;1233682389.47;; 277:281:; 270::A/5.3;622836720.22;; 270::A/6.4;19800;; 270::A/9.2;27125165.14;; 270::S16203/1.2;608607846.309999;; 270::S16305/4;2727510994.84;; 270::S16305/4.1;32049069.51;; 270::S16305/14;2737711.65;; 270::S25302/4;2725748122.98999;; 270::S25302/4.1;40952511.36;; 270::IL/2;87429694.5699999;62717458.21; 270::IL/4;33517212.95;; 270::IL/9;1423281.69;8278.24; 270::IL/11;86433534.5699999;519956.63; 270::IA/1;147792224.509999;4517060.94; 270::IA/2;737704.92;; 270::IA/3;27099836.07;2637.79; 270::IA/6;5607868.86;408410.4; 270::IA/8;103837028.49;48841202.69; 270::IA/10;112302573.56;; 268::20121231;280;; 270::A/5.2;1233682;; 277:280:; 270::A/5.3;622837;; 270::A/6.4;20;; 270::A/9.2;27125;; 270::S16203/1.2;608608;; 

Para este formulario, la base de datos tiene 4470 fechas de informes, que, cuando se descargan en un archivo plano, ocupan un poco más de 1 MB. En la base de datos original (Oracle), ocupan 3.1 MB (sin índices) en forma normalizada y 4.2 MB en un escaparate desnormalizado, que estamos tratando de repetir como quintetos. Los quintetos están indexados y normalizados, y en su formato estos datos ya ocupan 10 MB.


Las cantidades de datos para comparación se resumen en la tabla (en megabytes):
TextoRDBMSQuintetos
Datos1.13.15.1
Desnormalizado4.2 4.2
Índices6.25.1
Datos + Índices9.310,2

En este punto, se debe prestar atención al tamaño ocupado por las bases para los enfoques comparados. Debido a la normalización adicional de quintetos y gastos para índices compuestos en la base de referencia, el tamaño total ocupado por las bases de datos es casi el mismo.


Base de referencia:


Quintetos:


Además, en Integral, indexamos inmediatamente todos los campos de la tabla y del sistema de referencia, solo la fecha, el código y la cantidad en rublos, lo que requerirá costos adicionales cuando surjan nuevas necesidades.


Como referencia: en la base de datos, el tamaño total de este formulario, incluidos los informes y la configuración de soporte, es de aproximadamente 400 MB (es relativamente pequeño).


Entonces, los datos se cargan y la parte más difícil del proyecto está por venir: crear una interfaz. La interfaz del sistema de referencia le permite ver los datos de los formularios, informes de respaldo, configuraciones y el ciclo de vida de los formularios. Para administrar el acceso y comunicarse con la base de datos, utilizamos las capacidades básicas de nuestra plataforma: un modelo a seguir y un diseñador de informes.


La lista de usuarios con sus roles se ve así:




Si hace clic en el nombre del rol (marcado con un óvalo rojo en la figura anterior), puede ver su contenido:




Los objetos de rol se pueden establecer en 3 niveles de acceso; se puede usar la máscara:




La edición de datos también se realiza mediante la interfaz básica. Aquí, por ejemplo, hay un formulario de edición de usuario:




Presentamos el menú específico de nuestra aplicación y sus lugares de trabajo en un archivo compacto, ya que todos son del mismo tipo: un formulario de solicitud de 2-3 elementos y una tabla con los resultados de las solicitudes.




La arquitectura resultó ser muy simple: creamos muchas consultas de datos (vistas) y escribimos un complemento que implementa muestras de datos arbitrarias dentro de las tablas y campos incluidos en estas vistas.


Por ejemplo, tenemos un llamado informe de descifrado para formar 110, que contiene datos no agregados sobre los que se basa. Así es como se ve este informe:




Para verificar la exactitud del formulario, el usuario debe poder hacer cualquier selección, ordenar, filtrar, agrupar, transponer, así como crear sus propios campos calculados. Nuestro complemento se llama mediante el botón "Acciones" en la parte superior de la tabla.




El complemento repite la funcionalidad del generador de consultas Integral, pero además de obtener datos, puede dibujar gráficos y tablas dinámicas. Por ejemplo, necesitamos filtrar por Sección, agregar un par de columnas calculadas y hacer una selección de las cantidades agrupadas por ellas. Establecemos todo esto:




Las nuevas columnas se agregan a la lista mediante el enlace del mismo nombre. Mediante el botón "Cálculos" establecemos las fórmulas para ellos utilizando un constructor simple:




Establecemos un nuevo orden de columnas y hacemos clic en "Aplicar" y nuestro informe se modifica según sea necesario; en lugar de 7 columnas base, vemos tres, dos de las cuales acabamos de crear:




¿Cómo funciona debajo del capó?

El complemento se comunica con el servicio web de la aplicación a través de la API, realizó la siguiente solicitud:


 api/neo/report/1392573?FR_date=20181231&FR_%D0%A0%D0%B0%D0%B7%D0%B4%D0%B5%D0%BB=&FR_%D0%9A%D0%BE%D0%B4_%D0%BE%D0%B1%D0%BE%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D1%8F=&SELECT=LEFT(\:1392578\:\,5),SUBSTRING(\:1392578\:\,6\,3),1392617:SUM&ORDER=1392617&FR_%D0%A0%D0%B0%D0%B7%D0%B4%D0%B5%D0%BB=1&TOTALS=1392617:SUM&LIMIT=10 

Y obtuve esta respuesta:


 { «columns»: [ «LEFT(:1392578:,5)», «SUBSTRING(:1392578:,6,3)», «1392617» ], «formats»: [ «SHORT», «SHORT», «SIGNED» ], «data»: { «LEFT(:1392578:,5)»: [ «60324», «40817», «47425», «47404», «60302», «47404» ], «SUBSTRING(:1392578:,6,3)»: [ «810», «810», «810», «840», «810», «978» ], «  »: [ «153 825.71», «527 901.11», «2 415 189.23», «3 000 000.02», «5 588 330.88», «58 000 000.00» ] }, «totals»: [ «„, “», «69 685 246.95» ] } 

Si alguien está interesado en qué consulta SQL real se ejecutó en la base de datos de quintetos, aquí está:


Ver SQL

El analista no ve este SQL; utiliza el generador de consultas que se describe a continuación.


 SELECT LEFT(a182088.val, 5) v13, SUBSTRING(a182088.val, 6, 3) v14, SUM(round(a182090.val, 2)) '  ' FROM neo a182081 LEFT JOIN neo a182083 ON a182083.up=a182081.id AND a182083.t=182083 LEFT JOIN neo a182088 ON a182088.up=a182083.id AND a182088.t=182088 LEFT JOIN neo a182090 ON a182090.up=a182083.id AND a182090.t=182090 LEFT JOIN neo a182091 ON a182091.up=a182083.id AND a182091.t=182091 LEFT JOIN neo a182092 ON a182092.up=a182083.id AND a182092.t=182092 LEFT JOIN neo a299 ON a299.t=299 AND a182083.val=a299.val LEFT JOIN neo a328 ON a328.up=a299.id AND a328.t=328 LEFT JOIN neo a303 ON a303.up=a299.id AND a303.t=303 LEFT JOIN neo a304 ON a304.up=a299.id AND a304.t=304 LEFT JOIN neo a182089 ON a182089.up=a182083.id AND a182089.t=182089 WHERE a182081.up!=0 AND length(a182081.val)!=0 AND a182081.t=182081 AND a182081.val='20181231′ AND a328.val ='1AND a303.val>='19000101′ AND a303.val<='20181231AND a304.val>='20181231′ AND a304.val<='20991231GROUP BY v13, v14 ORDER BY CAST(SUM(round(a182090.val, 2)) AS SIGNED) LIMIT 10 

La solicitud puede parecer un poco más complicada de lo esperado, ya que selecciona los datos actuales de los códigos de informes en función de su validez. En el generador de informes integrales, esta consulta consta de columnas de informes, parámetros y condiciones de unión de tabla, si es necesario.




La integral en sí misma puede generar condiciones de unión a la tabla, ya que todas ellas están determinadas por las relaciones de quinteto, sin embargo, en el caso de las versiones, tuvimos que combinar las tablas manualmente y especificar explícitamente la condición para la UNIÓN. Los códigos en la cláusula ON son identificadores para columnas y objetos de consulta.


La consulta combina tres tablas, eligiendo de ellas los siguientes campos de datos ("columnas de consulta" necesarias):



(imagen a tamaño completo)

Las columnas del informe, los campos calculados, los filtros, etc., que conforman la consulta SQL, se enumeran aquí. Report Builder le permite implementar casi cualquier diseño del lenguaje SQL, incluidas las consultas de unión y las consultas anidadas.



Además de las selecciones con agrupaciones, el usuario puede usar el mecanismo de tablas dinámicas. Hemos agregado la popular herramienta de tabla pivottable.js.org a nuestro complemento.
Seleccione las columnas de interés para nosotros y cambie al modo de tabla dinámica:




Aquí, usando arrastrar y soltar, podemos analizar los datos recibidos por la muestra que configuramos, incluidos nuestros campos arbitrarios. Además, aquí también puede filtrar datos por cualquier campo.




Utilizamos el producto gratuito www.amcharts.com para dibujar gráficos. Con él, como con pivottable, todo es bastante simple: seleccionamos el tipo de gráfico e inicializamos el componente con nuestra matriz de datos obtenida de Integral:




Con esto, de hecho, completamos la tarea en la medida que satisfaga a los usuarios del producto existente. Ahora tenemos un sistema que cumple con los requisitos de sustitución de importaciones: todos los productos son gratuitos y reemplazables. Sí, nos hemos dado cuenta de todas las posibilidades que ofrece el sistema existente, pero solo de las que son necesarias para este cliente. ¡Pero acabamos de empezar!



¿Entonces voló o no?


También deberíamos discutir el rendimiento del sistema resultante. En este problema, con una cantidad de datos suficientemente grande (cientos de gigabytes), las muestras afectan a pequeños fragmentos, cuyos quintetos siempre se recopilan mediante índices. Esto lleva al hecho de que, en cualquier tamaño de la base de datos, las consultas se procesan a una velocidad aceptable, sin provocar una degradación del rendimiento similar a una avalancha.


Registramos 20 acciones del usuario en un script de prueba y lo ejecutamos en el servicio loadimpact.com . Resultó 27 solicitudes diferentes, porque algunas acciones se realizan en 2 solicitudes al servidor (por ejemplo, para crear una página visualizada).


El guión de prueba resultó así
 import { group, sleep } from 'k6′; import http from 'k6/http'; // Version: 1.3 // Creator: Load Impact URL test analyzer export let options = { stages: [ { «duration»: «3m0s», «target»: 25 } ], maxRedirects: 0, discardResponseBodies: true, }; export default function() { group("page_1 — https://*****.ru/neo/dict«, function() { let req, res; req = [{ «method»: «get», «url»: «https://*****.ru/neo/info», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «upgrade-insecure-requests»: «1», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8» } } }]; res = http.batch(req); sleep(0.62); req = [{ «method»: «get», «url»: «https://*****.ru/neo/info», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «upgrade-insecure-requests»: «1», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8» } } },{ «method»: «get», «url»: «https://*****.ru/neo/report/1392573?FR_date=20181231&LIMIT=10», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «image/webp,image/apng,image/*,*/*;q=0.8», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/neo/report/1392573?FR_date=20181130&ORDER=1392617&LIMIT=10&RECORD_COUNT», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «text/css,*/*;q=0.1», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/neo/report/1392573?FR_date=20181031», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «text/css,*/*;q=0.1», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/neo/report/1392573?FR_date=20180930&RECORD_COUNT», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «*/*», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/neo/report/1387723?&LIMIT=10», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «*/*», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/neo/report/1387723?&LIMIT=10&RECORD_COUNT», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «*/*», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/neo/report/1392741?», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «image/webp,image/apng,image/*,*/*;q=0.8», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/neo/report/1392757?&LIMIT=10», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «image/webp,image/apng,image/*,*/*;q=0.8», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/neo/report/1392768?&LIMIT=10», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «text/css,*/*;q=0.1», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/download/neo/img/nav_dropdown_arrow.svg», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «image/webp,image/apng,image/*,*/*;q=0.8», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/download/neo/img/nav_detailed_report.svg», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «image/webp,image/apng,image/*,*/*;q=0.8», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/download/neo/img/nav_classifiers.svg», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «image/webp,image/apng,image/*,*/*;q=0.8», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/download/neo/img/nav_launch_report.svg», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «image/webp,image/apng,image/*,*/*;q=0.8», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/download/neo/img/nav_manage_form_status.svg», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «image/webp,image/apng,image/*,*/*;q=0.8», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/download/neo/img/nav_quality_management.svg», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «image/webp,image/apng,image/*,*/*;q=0.8», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/download/neo/img/nav_download.svg», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «image/webp,image/apng,image/*,*/*;q=0.8», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/download/neo/css/variables.css», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «text/css,*/*;q=0.1», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/neo/report/1392779?&LIMIT=10», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «text/css,*/*;q=0.1», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/neo/report/1392538?&LIMIT=10&RECORD_COUNT», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «text/css,*/*;q=0.1», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/neo/edit_obj/1392129», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «text/css,*/*;q=0.1», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/neo/edit_obj/1390552», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «text/css,*/*;q=0.1», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/neo/object/18», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «text/css,*/*;q=0.1», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/neo/report/1387723?&LIMIT=140,10», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «text/css,*/*;q=0.1», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/neo/report/1387723?&LIMIT=140,10&RECORD_COUNT», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «text/css,*/*;q=0.1», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/neo/report/1392573?FR_date=20180731&FR_%D0%A0%D0%B0%D0%B7%D0%B4%D0%B5%D0%BB=&FR_%D0%9A%D0%BE%D0%B4_%D0%BE%D0%B1%D0%BE%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D1%8F=&SELECT=1392576,1392617:SUM,1392589&LIMIT=100», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «text/css,*/*;q=0.1», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/neo/report/1392678?FR_date=20180831&FR_section=1&SELECT=1392698,1392685,1392690&LIMIT=10», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «text/css,*/*;q=0.1», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/neo/report/1392678?FR_date=20180630&FR_section=1&SELECT=1392698,1392685,1392690&LIMIT=10&RECORD_COUNT», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «text/css,*/*;q=0.1», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/neo/report/1392678?FR_date=20180531&FR_section=1&SELECT=1392698,1392685,1392690&LIMIT=500», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «text/css,*/*;q=0.1», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/neo/report/1392678?FR_date=20181231&FR_section=2&SELECT=1392698,1392685,1392690&LIMIT=500», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «text/css,*/*;q=0.1», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/neo/report/1392678?FR_date=20181231&FR_section=4&SELECT=1392698,1392685,1392690,1392694&LIMIT=20», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «text/css,*/*;q=0.1», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/neo/report/1392678?FR_date=20181231&FR_section=4&SELECT=1392698,1392685,1392690,1392694&LIMIT=20&RECORD_COUNT», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «text/css,*/*;q=0.1», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/neo/info», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «text/css,*/*;q=0.1», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/api/neo/report/1392678?FR_date=20190131&FR_section=1&FR_precision=280&SELECT=1392698,1392685,1392715&LIMIT=50», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «text/css,*/*;q=0.1», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/api/neo/report/1392678?FR_date=20190131&FR_section=1&FR_precision=280&SELECT=1392698,1392685,1392715&LIMIT=50&RECORD_COUNT», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «text/css,*/*;q=0.1», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/api/neo/report/1392573?FR_date=20190131&FR_section=1&FR_precision=280&FR_%D0%9A%D0%BE%D0%B4_%D0%BE%D0%B1%D0%BE%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D1%8F=A60302/9&LIMIT=10», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «text/css,*/*;q=0.1», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://*****.ru/api/neo/report/1392573?FR_date=20190131&FR_section=1&FR_precision=280&ORDER=1392617&FR_%D0%9A%D0%BE%D0%B4_%D0%BE%D0%B1%D0%BE%D0%B7%D0%BD%D0%B0%D1%87%D0%B5%D0%BD%D0%B8%D1%8F=A60302/9&LIMIT=10», «params»: { «headers»: { «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «text/css,*/*;q=0.1», «referer»: «https://*****.ru/neo/dict» } } },{ «method»: «get», «url»: «https://fonts.gstatic.com/s/roboto/v19/KFOmCnqEu92Fr1Mu4mxP.ttf», «params»: { «headers»: { «origin»: «https://*****.ru», «accept-encoding»: «gzip, deflate», «accept-language»: «en-US», «user-agent»: «Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/62.0.3183.0 Safari/537.36», «accept»: «*/*», «referer»: «https://fonts.googleapis.com/css?family=Roboto» } } }]; res = http.batch(req); // Random sleep between 5s and 10s sleep(Math.floor(Math.random()*5+5)); }); } 


Esto es lo que vimos cuando ejecutamos el script: el generador de carga envió a nuestra aplicación un número creciente de solicitudes por segundo, obtuvimos una escalera clásica para buscar el rendimiento máximo / máximo:




Este generador envía solicitudes en lotes, y no de manera uniforme, como sería el caso con usuarios simultáneos. Por lo tanto, el gráfico muestra picos de carga, y el rendimiento general también se ve peor en este modo.


:




, - SQL-. , , 8 33 SQL- : , -, SQL- ( , ) .


, 20-25 ( 20 ), — 1 . , : 1 2.4 1 .


( 10 ) 0.1-0.3 , .


, .

Source: https://habr.com/ru/post/451218/


All Articles