Alibaba 2: ¿Cuántos nodos implementas? ¿Cómo implementar concurrencia de 1000W?

lo dijo de frente

En el grupo de intercambio de lectores ( mayores de 50 años) del arquitecto Nien, de 40 años , algunos amigos obtuvieron recientemente calificaciones para entrevistas de empresas de Internet de primer nivel como Alibaba, NetEase, Youzan, Xiyin, Baidu, NetEase y Didi. preguntas muy importantes de la entrevista:

  • Concurrencia de 1000W, ¿cuántos nodos se deben implementar?
  • ¿Cómo piensa cuántos nodos implementar? ¿Cómo los estima y los implementa?

Nien recordó que las cuestiones relacionadas con la arquitectura de implementación y la planificación de nodos son el conocimiento central de la arquitectura y son problemas clave en línea.

Por lo tanto, aquí Nien le brindará una revisión sistemática y sistemática, para que pueda demostrar plenamente sus fuertes "músculos técnicos" y hacer que el entrevistador "no pueda evitarlo y babee" .

Esta pregunta y las respuestas de referencia también se incluyen en la versión V102 de nuestra " Guía de entrevistas de Nien Java " como referencia para amigos posteriores para mejorar la arquitectura, el diseño y los niveles de desarrollo de 3 niveles de todos.

Para obtener los archivos PDF de "Notas de arquitectura de Nien", "Trilogía de alta concurrencia de Nien" y " Guía de entrevistas de Java de Nien ", vaya a la cuenta oficial [Technical Freedom Circle] para obtener

Pensemos primero en una pregunta, que también es una pregunta que se encuentra a menudo durante el proceso de entrevista.

Si el producto actual de su empresa vende máscaras, normalmente puede admitir un acceso de usuario de 10 W.

En caso de emergencias, como una epidemia,

Se espera que el número de usuarios alcance los 1000 W en un mes. Si te asignan esta tarea, ¿qué debes hacer?

Directorio de artículos

Cómo analizar el problema de la concurrencia de usuarios de 1000W

La cuestión de cómo dar soporte a 10 millones de usuarios es en realidad una cuestión bastante abstracta.

Para los desarrolladores de tecnología, la cuantificación es necesaria.

¿Qué es la cuantificación? Es necesario tener datos claros de los indicadores de desempeño como referencia al ejecutar tareas clave.

Por ejemplo, durante las horas pico, el tiempo de respuesta de las transacciones del sistema, la cantidad de usuarios simultáneos, la tasa de consultas por segundo (QPS), la tasa de éxito, etc.

El requisito básico para la cuantificación es que todos los indicadores sean claros.

Sólo así se podrá guiar eficazmente la mejora y optimización de toda la arquitectura.

Por lo tanto, si se enfrenta a un problema de este tipo, primero debe encontrar el núcleo del problema, que es comprender algunos indicadores de datos cuantificables.

  • Si tiene datos históricos relevantes de transacciones comerciales, debe consultar estos datos tanto como sea posible y procesar los datos sin procesar recopilados (registros) para analizar el período pico y el comportamiento de las transacciones, la escala y otra información durante este período, a fin de actualizarlos. Comprenda claramente los detalles de los requisitos.
  • Si no tiene indicadores de datos relevantes a los que referirse, entonces debe confiar en la experiencia para el análisis. Por ejemplo, puede consultar algunos modelos de transacciones comerciales maduros en industrias similares (como las actividades de transacciones diarias en la industria bancaria o las transacciones de inspección y venta de boletos en la industria del transporte), o adoptar directamente el principio "2/8" y el " Principio de 2/5/8". Empiece a practicar.
    Cuando los usuarios puedan obtener una respuesta del sistema en 2 segundos, sentirán que el sistema responde;
    cuando obtengan una respuesta en 2 a 5 segundos, sentirán que la velocidad de respuesta del sistema es aceptable; cuando obtengan una respuesta dentro de 2 a 5 segundos, sentirán que la velocidad de respuesta del sistema es aceptable;
    cuando obtengan una respuesta dentro de 2 a 5 segundos, sentirán que la velocidad de respuesta del sistema es aceptable 5-8 segundos, sentirán que el sistema responde. Sentirán que la velocidad de respuesta del sistema es lenta, pero aún es aceptable;
    sin embargo, cuando los usuarios no reciben una respuesta después de más de 8 segundos, sentirán que el rendimiento del sistema es extremadamente pobre, o piensan que el sistema no responde, por lo que optan por abandonar el sitio web o iniciar una segunda solicitud.

Al estimar indicadores clave como el tiempo de respuesta, la cantidad de usuarios simultáneos, la tasa de consultas por segundo (QPS) y la tasa de éxito, también debe prestar atención a los requisitos funcionales comerciales específicos.

Cada función empresarial tiene sus propias características únicas. Por ejemplo:

  • En algunos escenarios, no es necesario devolver resultados de ejecución claros de forma sincrónica;
  • En algunos escenarios empresariales, es aceptable devolver un mensaje como "El sistema está ocupado, ¡espere!" para evitar una parálisis del sistema a gran escala causada por un tráfico de procesamiento excesivo.

Por tanto, es necesario aprender a equilibrar la relación entre estos indicadores.

acuerdo de nivel de servicio

En la mayoría de los casos, es mejor establecer un orden de prioridad para estas métricas y centrarse sólo en unos pocos requisitos de métricas de alta prioridad siempre que sea posible.

SLA : La abreviatura de Service-Level Agreement significa acuerdo de nivel de servicio.

El SLA de un servicio es el compromiso formal del proveedor del servicio con el consumidor del servicio y es un elemento clave para medir el nivel de capacidad del servicio.

Los elementos definidos en el SLA de servicio deben ser medibles y tener métodos de medición claros.

Artículos SLA significado Métodos de medición Ejemplo nivel de servicio nivel de interfaz
Tasa de éxito de la solicitud El porcentaje de solicitudes respondidas exitosamente por el servicio respecto del número total de solicitudes durante el período de medición. (número de solicitudes respondidas con éxito/solicitudes totales)*100 >99% No
Disponibilidad Dentro del periodo de medición, el porcentaje de tiempo de disponibilidad del servicio se divide en tres niveles.
1.99.999%-99.9999%. Este es el servicio con mayor disponibilidad. El tiempo acumulado de indisponibilidad en un año es de 5.256 minutos-31.536 segundos. La indisponibilidad de dichos servicios afectará el uso del usuario. Por ejemplo, iniciar sesión 2.99.99%% -99.999%
, El tiempo de indisponibilidad acumulado en un año es 52.56 horas-5.256 minutos. Cuando ocurre indisponibilidad, las operaciones del usuario se verán afectadas. El servicio indirecto orientado al usuario es 3.99.9%-99.99%. El tiempo de
indisponibilidad acumulado en un año es de 8,76 horas a 52,56 minutos.Cuando se produce el servicio, no afectará el uso del usuario cuando no esté disponible.
(tiempo de servicio en línea/tiempo total del período estadístico)*100 Nivel 1 No
consistencia de los datos Después de que el consumidor del servicio llama a la interfaz del servicio para escribir datos, inmediatamente llama a la interfaz del servicio para leer, si el contenido de los datos escritos se puede leer, incluidos tres niveles: 1.
Consistencia fuerte
2. Consistencia débil
3. Consistencia final
Llame a la interfaz de creación de recursos y llame a la interfaz de consulta de recursos para obtener los datos creados. eventual consenso No
Rendimiento El número de solicitudes procesadas por segundo. Para los clústeres de servicios, se recomienda proporcionar el método de cálculo del rendimiento general, como rendimiento del clúster = rendimiento * número de instancias de servicio. Si es difícil darlo, al menos proporcione el rendimiento general típico. número de instancias de clúster. Cuenta la cantidad de solicitudes que maneja el servicio por segundo. 200 Opcional
Retraso de solicitud TP50 El valor definido por la región de retraso de solicitud del 50 % durante el ciclo de operación del servicio. Utilice cálculos percentiles 100 ms Opcional
Retraso de solicitud TP99.9 El valor definido por la región para el 99,9% de los retrasos en las solicitudes durante el ciclo de operación del servicio. Utilice cálculos percentiles 200 ms Opcional

1. Explicación de conceptos relacionados en concurrencia.

Antes de profundizar en los temas anteriores, me gustaría presentarles algunas métricas de evaluación clave relacionadas con el sistema:

  • SWC
  • tps
  • dau
  • pv
  • ultravioleta

Nien ha escrito un artículo especial para presentar estos conceptos clave . Para obtener más información, consulte el siguiente artículo:

¿Cuál es el QPS de su sistema y cómo se implementa? Suponiendo decenas de millones de solicitudes cada día, ¿cómo implementarlas?

2. Calcula el número de visitas de 10 millones de usuarios según la regla 80/20

Volvamos a la pregunta original: ¿cuántos nodos se deben implementar para una concurrencia de 1000 W?

Suponiendo que no tenemos datos históricos a los que referirnos, podemos usar la regla 80/20 para estimar.

  • Suponiendo que hay 10 millones de usuarios y la proporción de usuarios que visitan el sitio web todos los días es del 20%, entonces hay aproximadamente 2 millones de usuarios que visitan el sitio web todos los días.
  • Suponiendo que cada usuario hace clic 50 veces en promedio, el valor total de visitas a la página es de 100 millones.
  • El día tiene 24 horas. Según la regla 80/20, la mayoría de los usuarios están activos todos los días en (24 * 0,2), lo que equivale aproximadamente a 5 horas, y la mayoría de los usuarios hacen referencia a (100 millones de clics * 80% ), que es aproximadamente igual a 8000 W. (PV), lo que significa que dentro de 5 horas, habrá aproximadamente 8000 W de clics, lo que equivale aproximadamente a 4500 (8000 W/5 horas) solicitudes por segundo.
  • 4500 es solo un valor promedio. Durante estas 5 horas, el volumen de solicitudes no es necesariamente uniforme y puede haber una situación en la que una gran cantidad de usuarios visiten juntos (por ejemplo, para sitios web como Taobao, las horas pico de visitas diarias se concentran a las 14:00 p. m. y 21:00 horas, de las cuales las 21:00 horas es el pico de visitas en un día). Normalmente, el volumen de solicitudes durante las horas pico de tráfico es de 3 a 4 veces el volumen de solicitudes promedio (este es un valor empírico) y lo calculamos como 4 veces. Entonces, durante estas 5 horas, puede haber 18.000 solicitudes por segundo. Por tanto, el problema original de soportar 10 millones de usuarios se ha convertido en un problema específico, es decir, el servidor debe poder soportar 18.000 solicitudes por segundo (QPS = 18.000).

3. Estimación de la presión del servidor

Después de estimar aproximadamente el pico de concurrencia más alto que el servidor backend debe soportar, debemos realizar una prueba de esfuerzo desde la perspectiva de toda la arquitectura del sistema y luego configurar razonablemente la cantidad de servidores y la arquitectura.

En primer lugar, debemos comprender cuánta concurrencia puede soportar un servidor, entonces, ¿cómo analizarla?

Dado que nuestra aplicación está implementada en Tomcat, debemos comenzar con el rendimiento de Tomcat.

El siguiente es un diagrama que describe cómo funciona Tomcat y se explica de la siguiente manera:

  • LimitLatch es un controlador de conexión, que se encarga de controlar el número máximo de conexiones que Tomcat puede manejar simultáneamente. En el modo NIO/NIO2, el valor predeterminado es 10000; en el modo APR/nativo, el valor predeterminado es 8192.
  • El aceptador es un hilo independiente que llama al método socket.accept en el bucle while del método de ejecución para recibir la solicitud de conexión del cliente. Cada vez que llega una nueva solicitud, aceptar devolverá un objeto de Canal y luego entregará el objeto de Canal a Poller para su procesamiento.
    Poller es esencialmente un selector, que también implementa subprocesos. Poller mantiene una matriz de canales internamente y detecta continuamente el estado de preparación de los datos del canal en un bucle infinito. Una vez que el Canal sea legible, generará un objeto de tarea SocketProcessor y lo entregará al Ejecutor para su procesamiento.
  • SocketProcessor implementa la interfaz Runnable. Cuando el grupo de subprocesos ejecuta la tarea SocketProcessor, maneja la solicitud actual a través del Http11Processor. Http11Processor lee los datos del Canal para generar un objeto ServletRequest.
  • Executor es un grupo de subprocesos responsable de ejecutar tareas de SocketProcessor. El método de ejecución de SocketProcessor llamará a Http11Processor para leer y analizar los datos de la solicitud. Sabemos que Http11Processor es una encapsulación del protocolo de la capa de aplicación, llama al contenedor para obtener la respuesta y luego escribe la respuesta a través del Canal.

De esta figura podemos saber que hay cuatro factores principales que afectan la cantidad de solicitudes de Tomcat.

3.1 Factor de influencia 1 de Tomcat: recursos actuales del sistema del servidor

Creo que es posible que haya encontrado una excepción similar a "Socket/Archivo: no se pueden abrir tantos archivos", que es la representación del límite de manejo de archivos en el sistema Linux.

En el sistema operativo Linux, cada conexión TCP ocupa un descriptor de archivo (fd). Cuando el descriptor de archivo excede el límite actual del sistema Linux, aparecerá este mensaje de error.

Podemos usar el siguiente comando para ver el límite superior de la cantidad de archivos que un proceso puede abrir.

ulimit -a 或者 ulimit -n

archivos abiertos (-n) 1024 es el límite del sistema operativo Linux en la cantidad de identificadores de archivos abiertos por un proceso (también incluye la cantidad de sockets abiertos)

Esto es solo una restricción a nivel de usuario. De hecho, también existe una restricción general en el sistema. Verifique el sistema de bus del sistema:

cat /proc/sys/fs/file-max

file-max establece el número total de archivos que pueden abrir todos los procesos del sistema.

Al mismo tiempo, se pueden llamar algunos programas a través de setrlimit para establecer límites para cada proceso. Si recibimos una gran cantidad de mensajes de error de identificadores de archivos fuera de uso, deberíamos considerar aumentar este valor.

Al encontrarnos con el error anterior, podemos modificarlo de las siguientes maneras (límite en la cantidad de archivos abiertos para un solo proceso)

vi /etc/security/limits.conf
  root soft nofile 65535
  root hard nofile 65535
  * soft nofile 65535
  * hard nofile 65535
  • *Representa a todos los usuarios y rootrepresenta al usuario raíz.
  • noproc representa el número máximo de procesos
  • nofile representa el número máximo de archivos abiertos.
  • Suave/duro, el primero generará una advertencia cuando se alcance el umbral y el segundo informará un error.

Además, también debe asegurarse de que el límite en la cantidad de archivos abiertos a nivel de proceso sea menor o igual que el límite total del sistema, de lo contrario, entonces debemos modificar el límite total del sistema.

vi /proc/sys/fs/file-max

La mayor sobrecarga de las conexiones TCP en los recursos del sistema es la memoria.

Dado que una conexión TCP requiere que ambas partes reciban y envíen datos, es necesario configurar un búfer de lectura y un búfer de escritura.

En los sistemas Linux, el tamaño mínimo de estos dos buffers es de 4096 bytes. La información se puede obtener viendo /proc/sys/net/ipv4/tcp_rmem y /proc/sys/net/ipv4/tcp_wmem.

Por lo tanto, la memoria mínima ocupada por una conexión TCP es 4096+4096 = 8k. Para una máquina con memoria 8G, si no se consideran otras restricciones, el número máximo de concurrencias es aproximadamente: 8 * 1024 * 1024/8, que es aproximadamente igual a 1 millón.

Este número es el máximo teórico. En aplicaciones reales, debido a las restricciones del kernel de Linux en algunos recursos y al impacto del procesamiento comercial del programa, es difícil alcanzar 1 millón de conexiones con 8 GB de memoria.

Por supuesto, podemos aumentar la cantidad de concurrencias aumentando la memoria.

3.2 Factor de influencia 2 de Tomcat: configuración de la JVM de la que depende Tomcat

Todos sabemos que Tomcat es un programa Java que se ejecuta en JVM.

Por lo tanto, optimizar la JVM también es la clave para mejorar el rendimiento de Tomcat. Presentemos brevemente la situación básica de JVM, como se muestra en la siguiente figura.

En la JVM, la memoria se divide en montón, contador de programas, pila de métodos locales, área de métodos (metaespacio) y pila de máquinas virtuales.

3.2.1 Descripción del espacio del montón

La memoria del montón es el área más grande de la memoria JVM, la mayoría de los objetos y matrices se asignan aquí y todos los subprocesos la comparten. El espacio del montón se divide en la nueva generación y la antigua generación, y la nueva generación se divide aún más en las áreas Eden y Survivor, como se muestra en la siguiente figura.

La relación entre la nueva generación y la antigua generación es 1: 2, lo que significa que la nueva generación ocupa 1/3 del espacio del montón y la antigua generación ocupa 2/3.

Además, en la nueva generación, la proporción de asignación de espacio es Eden:Survivor0:Survivor1=8:1:1.

Por ejemplo, si el tamaño de la memoria del área de Eden es 40 M, entonces la memoria de las dos áreas de Survivor representa cada una 5 M, la memoria total de la nueva generación es 50 M y luego se calcula que el tamaño de la memoria de la generación anterior es 100 M, lo que significa el espacio total del montón. El tamaño de la memoria es 150 M.

Puede ver los parámetros predeterminados a través de java -XX:PrintFlagsFinal -version

uintx InitialSurvivorRatio                      = 8
uintx NewRatio                                  = 2

InitialSurvivorRatio: la proporción inicial del espacio Eden/Survivor de nueva generación

NewRatio: relación de memoria del área antigua/área joven

El mecanismo de funcionamiento específico de la memoria dinámica es el siguiente:

  • La mayoría de los objetos se colocarán en el área del Edén después de su creación. Cuando el área del Edén esté llena, se activará YGC (Young GC). La mayoría de los objetos se reciclarán y los objetos supervivientes se copiarán en Survivor0. En este momento, el área del Edén fue vaciada.
  • Si se activa YGC nuevamente, los objetos supervivientes se copiarán del área Eden+Survivor0 al área Survivor1, y las áreas Eden y Survivor0 se borrarán.
  • Cuando se activa YGC nuevamente, los objetos en Eden + Survivor1 se copiarán al área Survivor0. Este ciclo continúa hasta que la edad del objeto alcanza el umbral y luego se moverá a la generación anterior. (Este diseño se debe a que la mayoría de los objetos del área del Edén serán reciclados).
  • Los objetos que no se puedan acomodar en el área de Survivor se ingresarán directamente en la generación anterior.
  • Cuando la generación anterior esté llena, se activará Full GC.

¿El algoritmo de barrido de marcas de GC suspende otros subprocesos durante la ejecución?

3.2.2 Contador de programa

El contador del programa se utiliza para registrar información como la dirección del código de bytes ejecutado por cada subproceso. Cuando el contexto de un subproceso cambia, se confía en él para registrar la posición de ejecución actual para que la ejecución pueda continuar desde la última posición de ejecución cuando se reanude la ejecución la próxima vez. .

3.2.3 Área de método

El área de método es un concepto lógico: en la versión 1.8 de la máquina virtual HotSpot, su implementación específica es el metaespacio.

El área de métodos se utiliza principalmente para almacenar información relacionada con las clases que han sido cargadas por la máquina virtual, incluida la metainformación de la clase, el grupo constante de tiempo de ejecución y el grupo constante de cadenas. La información de la clase también incluye la versión de la clase, los campos, los métodos, las interfaces y los padres. información de clase.

El área de método es similar al espacio del montón: es un área de memoria compartida, por lo que el área de método es compartida por subprocesos.

Pila de implementación local y pila de máquinas virtuales

La pila de la máquina virtual Java es un espacio de memoria privado de subprocesos. Cuando se crea un subproceso, se asigna una pila de subprocesos en la máquina virtual para almacenar información como variables locales de métodos, pilas de operandos y métodos de enlace dinámico. Cada vez que se llama a un método, irá acompañado de una operación de inserción del marco de la pila. Cuando el método regrese, será una operación emergente del marco de la pila.

La pila de métodos locales es similar a la pila de máquinas virtuales: la pila de métodos locales se utiliza para gestionar la invocación de métodos locales, es decir, métodos nativos.

Método de configuración de memoria JVM

Después de comprender los conocimientos básicos anteriores, analicemos cómo se debe configurar la memoria JVM y qué parámetros se pueden usar para configurarla.

En la JVM, los parámetros principales que deben configurarse incluyen:

  • -Xms,Tamaño de la memoria del montón de Java
  • -Xmx, Tamaño máximo de memoria dinámica de Java
  • -Xmn, El tamaño de la nueva generación en la memoria del montón de Java. Después de deducir la nueva generación, el resto es la memoria de la generación anterior. Si la memoria de la nueva generación se establece demasiado pequeña, el GC menor se
    activará con frecuencia. La activación frecuente del GC afectará la estabilidad del sistema.
  • -XX:MetaspaceSize, tamaño del metaespacio, 128M
  • -XX:MaxMetaspaceSize, el tamaño máximo del espacio en la nube (si no se especifican estos dos parámetros, el metaespacio se ajustará dinámicamente según sea necesario durante el tiempo de ejecución). 256M
    Básicamente, no hay forma de calcular el metaespacio de un nuevo sistema, generalmente se establece en unos pocos cien megabytes Es suficiente, porque almacena principalmente información de clase.
  • -XssBásicamente, no es necesario estimar el tamaño de la memoria de la pila de subprocesos, simplemente configúrelo de 512 KB a 1 M, porque cuanto menor sea el valor, más subprocesos se pueden asignar.

El tamaño de la memoria JVM se ve afectado por la configuración del servidor. Por ejemplo, para un servidor con 2 núcleos y 4G de memoria, la memoria asignada al proceso JVM es de aproximadamente 2G.

Esto se debe a que el propio servidor también requiere memoria y la memoria debe reservarse para otros procesos. Esta memoria 2G también debe asignarse a memoria de pila, memoria de montón y metaespacio, por lo que la memoria de montón disponible es de aproximadamente 1G.

Luego, la memoria del montón también debe dividirse en la nueva generación y la antigua generación.

3.3 Factor de influencia 3 de Tomcat: configuración del propio Tomcat

La configuración principal de Tomcat es la siguiente:

Referencia de configuración de Apache Tomcat 8 (8.0.53): el conector HTTP

El número máximo de subprocesos de procesamiento de solicitudes que creará este conector , que por lo tanto determina el número máximo de solicitudes simultáneas que se pueden manejar. Si no se especifica, este atributo se establece en 200. Si un ejecutor está asociado con este conector, este atributo se ignora ya que el conector ejecutará tareas utilizando el ejecutor en lugar de un grupo de subprocesos interno. Tenga en cuenta que si se configura un ejecutor, cualquier valor establecido para este atributo se registrará correctamente pero se informará (por ejemplo, a través de JMX) para -1dejar claro que no se utiliza.

server:
  tomcat:
    uri-encoding: UTF-8
    #最大工作线程数,默认200, 4核8g内存,线程数经验值800
    #操作系统做线程之间的切换调度是有系统开销的,所以不是越多越好。
    max-threads: 1000
    # 等待队列长度,默认100,
    accept-count: 1000
    max-connections: 20000
    # 最小工作空闲线程数,默认10, 适当增大一些,以便应对突然增长的访问量
    min-spare-threads: 100
  • Accept-Count : este es el número máximo de espera. Cuando el número de solicitudes HTTP alcanza el número máximo de subprocesos de Tomcat, si llega una nueva solicitud HTTP, Tomcat colocará la solicitud en la cola de espera. Este AcceptCount se refiere al número máximo de esperas que se pueden aceptar y el valor predeterminado es 100. Si la cola de espera también se llena, Tomcat rechazará las nuevas solicitudes (conexión rechazada).
  • maxThreads : este es el número máximo de subprocesos. Cada vez que llega una solicitud HTTP al servicio web, Tomcat creará un subproceso para manejar la solicitud. maxThreads determina cuántas solicitudes puede manejar el contenedor de servicios web al mismo tiempo. El valor predeterminado de maxThreads es 200, se recomienda aumentarlo. Sin embargo, agregar subprocesos tendrá costos: más subprocesos no solo generarán más costos de cambio de contexto de subprocesos, sino que también consumirán más memoria. De forma predeterminada, la JVM asigna un tamaño de pila de subprocesos de 1 M al crear un nuevo subproceso, por lo que más subprocesos significan más memoria. El valor de experiencia para la cantidad de subprocesos es: 1 núcleo, 2 g de memoria, 200 valor de experiencia para la cantidad de subprocesos; 4 núcleos, 8 g de memoria, el valor de experiencia para la cantidad de subprocesos, 800.
  • maxConnections : Este es el número máximo de conexiones. Este parámetro especifica el número máximo de conexiones que Tomcat puede aceptar al mismo tiempo. Para el BIO de bloqueo de Java, el valor predeterminado es el valor de maxthreads; si se utiliza un Ejecutor personalizado en modo BIO, el valor predeterminado será el valor de maxthreads en el ejecutor. Para el nuevo modo NIO de Java, el valor predeterminado de maxConnections es 10000. Para el modo APR/IO nativo en Windows, el valor predeterminado de maxConnections es 8192.
    Si se establece en -1, la función maxconnections está deshabilitada, lo que indica que la cantidad de conexiones al contenedor Tomcat no está limitada. La relación entre maxConnections y Accept-Count es: cuando el número de conexiones alcanza el valor máximo de maxConnections, el sistema continuará recibiendo conexiones, pero no excederá el valor de AcceptCount.

3.4 Factor de influencia 4 de Tomcat: presión ejercida por la aplicación

En nuestro análisis anterior, aprendimos que cuando NIOEndPoint recibe la conexión de solicitud del cliente, generará una tarea SocketProcessor y la enviará al grupo de subprocesos para su procesamiento.

El método de ejecución en SocketProcessor llamará al componente HttpProcessor para analizar el protocolo de la capa de aplicación y generar un objeto de solicitud.

Finalmente, llame al método de servicio del adaptador para pasar la solicitud al contenedor.

El contenedor es el principal responsable de procesar las solicitudes internas, es decir, después de que el conector actual obtenga información a través del Socket, obtendrá una solicitud de Servlet, y el contenedor es responsable de procesar esta solicitud de Servlet.

Tomcat usa el componente Mapper para ubicar la URL solicitada por el usuario a un Serlvet específico, y luego DispatcherServlet en Spring intercepta la solicitud de Servlet y la ubica en nuestro Controlador específico según el mapeo del propio Mapper de Spring.

Cuando la solicitud llega al Responsable, es el inicio real de la solicitud para nuestro negocio.

El controlador llama al servicio y el servicio llama a DAO. Después de completar la operación de la base de datos, la solicitud se devuelve al cliente a través de la ruta original para completar una sesión general.

Por lo tanto, el tiempo de procesamiento de la lógica empresarial en el Controlador tendrá un impacto en el rendimiento de concurrencia de todo el contenedor.

4. Evaluación de la cantidad de servidores

Hagamos algunos cálculos simples:

Supongamos que el QPS de un nodo Tomcat es 500. Si desea admitir el QPS de 18 000 durante los períodos pico, se necesitan 40 servidores.

Estos 40 servidores necesitan distribuir solicitudes a través del equilibrio de carga del software Nginx.

El rendimiento de Nginx es muy bueno y la declaración oficial afirma que su capacidad concurrente para procesar archivos estáticos puede alcanzar los 5 W/s.

Dado que Nginx no puede ser un punto único, podemos usar LVS para equilibrar la carga de Nginx. LVS (Linux VirtualServer) utiliza tecnología de equilibrio de carga IP para lograr el equilibrio de carga.

A través de dicho conjunto de arquitectura, nuestro servidor actual puede manejar QPS = 18000 al mismo tiempo, pero no es suficiente. Volvamos a las dos fórmulas mencionadas anteriormente.

  • QPS=concurrencia/tiempo de respuesta promedio
  • Simultaneidad = QPS * tiempo de respuesta promedio

Supongamos que nuestro RT es 3, entonces el número de concurrencia en el lado del servidor = 18000 * 3 = 54000, es decir, hay 54000 conexiones al lado del servidor al mismo tiempo. Por lo tanto, la cantidad de conexiones que el servidor debe admitir al mismo tiempo es 54.000.

Si el RT es mayor, significa que hay más conexiones atrasadas, que ocuparán recursos de memoria/recursos de CPU, etc., y pueden provocar que el sistema falle fácilmente.

Al mismo tiempo, cuando el número de conexiones excede el umbral, las solicitudes posteriores no pueden ingresar y el usuario obtendrá un resultado de tiempo de espera de solicitud, que no es lo que queremos ver. Por tanto, debemos acortar el valor de RT.

5. ¿Cómo reducir el valor de RT?

Si continúa mirando la imagen de arriba, una solicitud debe esperar a que la aplicación en el contenedor Tomcat complete su ejecución antes de poder devolverla.

¿Qué operaciones realizará la solicitud durante la ejecución?

  • Consultar base de datos
  • Acceder a los datos del disco
  • Realizar operaciones de memoria.
  • llamar al servicio remoto

Estas operaciones consumirán tiempo y la solicitud del cliente debe esperar a que se completen antes de regresar.

Por tanto, la forma de reducir el tiempo de respuesta es optimizar el procesamiento de la lógica empresarial.

5.1 Optimización de la base de datos

Cuando 18.000 solicitudes ingresan al servidor y se reciben, comienza el procesamiento de la lógica de negocios, lo que inevitablemente implicará consultas a la base de datos.

Cada solicitud realiza al menos una operación de consulta de base de datos y se requieren más de 3 a 5 consultas.

Suponiendo 3 cálculos, se realizarán 54.000 solicitudes a la base de datos por segundo.

Suponiendo que un servidor de base de datos admite 10,000 solicitudes por segundo (hay muchos factores que afectan la cantidad de solicitudes de base de datos, como la cantidad de datos en la tabla de la base de datos, el rendimiento del sistema del servidor de la base de datos y la complejidad de la declaración de la consulta) Entonces se necesitan 6 servidores de bases de datos para admitir cada solicitud, 10,000 solicitudes por segundo.

Además, existen otras soluciones de optimización a nivel de base de datos.

  • La primera es la configuración del número máximo de conexiones para MySQL. Cuando el número de visitas es demasiado alto, puedes encontrarte con el problema MySQL: ERROR 1040: Demasiadas conexiones, la razón es que el número de conexiones está agotado. Si el servidor tiene una gran cantidad de solicitudes de conexión simultáneas, se recomienda aumentar este valor para aumentar la cantidad de conexiones paralelas. Sin embargo, se debe considerar la capacidad de carga de la máquina, porque cuantas más conexiones haya, más memoria ocupará el búfer de conexión proporcionado por cada conexión, por lo que el valor debe ajustarse adecuadamente y el valor de configuración no se puede aumentar a ciegas.
  • Introducción de componentes de almacenamiento en caché. La cantidad de datos en la tabla de datos es demasiado grande, por ejemplo, alcanza decenas de millones o incluso cientos de millones. En este caso, la optimización de SQL tiene poca importancia, porque las consultas con una cantidad tan grande de datos inevitablemente implicarán cálculos. El problema de la excesiva concurrencia de solicitudes de lectura se puede resolver mediante el almacenamiento en caché. En términos generales, las solicitudes de lectura y escritura de bases de datos siguen la regla 80-20. De las 54.000 solicitudes por segundo, aproximadamente 43.200 son solicitudes de lectura y aproximadamente el 90 % de estas solicitudes de lectura se pueden resolver a través de la memoria caché.

Las razones por las que colocar datos de la base de datos MySQL en la caché de Redis puede mejorar el rendimiento son las siguientes:

  1. Redis almacena datos en formato clave-valor y su complejidad de tiempo de búsqueda es O (1) (orden constante), mientras que la implementación subyacente del motor MySQL es B + Tree y su complejidad de tiempo es O (logn) (orden logarítmico). . Por lo tanto, Redis tiene una velocidad de consulta más rápida que MySQL.
  2. Los datos de MySQL se almacenan en tablas. Al buscar datos, es necesario realizar un escaneo global de la tabla o una búsqueda basada en el índice, lo que implica una búsqueda en el disco. Redis no necesita ser tan complicado porque busca directamente según la ubicación de los datos en la memoria.
  3. Redis es un IO multiplexado de un solo subproceso, que evita la sobrecarga del cambio de subprocesos y la espera de IO, mejorando así la eficiencia del uso del procesador en procesadores de múltiples núcleos.
  • La división de bases de datos y tablas reduce la cantidad de datos en una sola tabla. Con menos datos en una sola tabla, el rendimiento de las consultas naturalmente mejora de manera efectiva.
  • La separación de lectura y escritura evita el impacto en el rendimiento de las operaciones de transacción en las operaciones de consulta. La operación de escritura en sí consume recursos, y la operación de escritura de la base de datos es escritura IO. El proceso de escritura generalmente implica verificación de unicidad, creación de índices, clasificación de índices y otras operaciones, lo que consume muchos recursos. El tiempo de respuesta de una operación de escritura suele ser varias veces o incluso decenas de veces mayor que el de una operación de lectura. Contención de bloqueos, las operaciones de escritura a menudo requieren bloqueos, incluidos bloqueos a nivel de tabla, bloqueos a nivel de fila, etc. Este tipo de bloqueo es un bloqueo exclusivo: después de que una sesión ocupa un bloqueo exclusivo, otras sesiones no pueden leer datos, lo que afectará en gran medida el rendimiento de la lectura de datos. Por lo tanto, la implementación de MySQL generalmente adopta un método de separación de lectura y escritura. La base de datos maestra se usa para escribir datos y algunas operaciones de lectura urgentes, y la base de datos esclava se usa para realizar la mayoría de las operaciones de lectura. De esta manera, el rendimiento general del La base de datos se puede mejorar mucho.
  • Almacenamiento heterogéneo sql+nosql. Se utilizan diferentes bibliotecas de almacenamiento para datos con diferentes características, como MongoDB (almacenamiento documentado NoSQL), Redis (almacenamiento de valores clave NoSQL), HBase (almacenamiento en columnas NoSQL), estas bases de datos son similares a las bases de datos de valores clave hasta cierto punto. NoSQL es altamente escalable y adecuado para gestionar grandes cantidades de datos no estructurados.

  • La tecnología de agrupación de clientes reduce la pérdida de rendimiento al crear conexiones de bases de datos con frecuencia. Antes de cada operación de la base de datos, primero se establece la conexión, luego se realiza la operación de la base de datos y finalmente se libera la conexión. Este proceso implica retrasos en la comunicación de la red y la sobrecarga de rendimiento de la creación y destrucción frecuente de objetos de conexión. Cuando el volumen de solicitudes es grande, esta pérdida de rendimiento será muy obvia. Al utilizar la tecnología de agrupación de conexiones, puede reutilizar conexiones ya creadas y reducir esta pérdida de rendimiento.

5.2 Optimización del acceso a datos del disco

Para las operaciones de disco, incluye principalmente lectura y escritura. Por ejemplo, en el escenario de un sistema comercial, normalmente es necesario analizar y escribir archivos de conciliación. Los métodos de optimización para operaciones de disco incluyen:

  • Utilice la caché de disco y las E/S de caché para aprovechar al máximo la caché del sistema y reducir la cantidad de E/S reales.
  • Se utiliza lectura y escritura secuencial, y se utiliza escritura adjunta en lugar de escritura aleatoria para reducir la sobrecarga de direccionamiento y mejorar la velocidad de escritura de E/S.
  • Al utilizar SSD en lugar de HDD, la eficiencia de E/S de SSD es mucho mayor que la del disco duro mecánico.
  • Cuando se lee y escribe con frecuencia el mismo espacio en disco, se puede utilizar mmap (mapeo de memoria) en lugar de lectura/escritura para reducir la cantidad de copias de memoria.
  • En escenarios donde se requiere escritura sincrónica, intente fusionar solicitudes de escritura en lugar de escribir cada solicitud en el disco de forma sincrónica. Puede usar fsync() en lugar de O_SYNC.

5.3 Uso adecuado de la memoria

Aproveche al máximo la memoria caché para almacenar datos y objetos a los que se accede con frecuencia en la memoria para evitar cargas repetidas o reducir las pérdidas de rendimiento causadas por el acceso a la base de datos.

5.4 Llamar a servicios remotos

Las llamadas de servicio remoto afectarán el rendimiento de E/S, principalmente incluyendo:

  • Bloqueo de llamadas remotas en espera de resultados
    • Comunicación asíncrona
  • tiempo de comunicación de red
    • comunicación interna
    • Aumentar el ancho de banda de la red
  • Estabilidad de las comunicaciones de servicio remoto.

5.5 Arquitectura asincrónica

En los microservicios, para situaciones en las que el tiempo de procesamiento es largo y la lógica es compleja, la alta concurrencia puede provocar que se agoten los subprocesos del servicio y que no se puedan crear nuevos subprocesos para procesar las solicitudes.

En respuesta a esta situación, además de optimizar a nivel del programa (como ajuste de base de datos, ajuste de algoritmo, almacenamiento en caché, etc.), también puede considerar realizar ajustes arquitectónicos, como devolver los resultados al cliente primero para que los usuarios puedan continuar. para utilizar otras operaciones en el cliente y luego procesar de forma asincrónica el módulo de procesamiento lógico complejo en el lado del servidor.

Este método de procesamiento asincrónico es adecuado para escenarios donde el cliente no es sensible a los resultados del procesamiento y no requiere tiempo real, como correo electrónico masivo, mensajes masivos, etc.

Las soluciones para el diseño asincrónico incluyen:

  • subprocesos múltiples
  • Cola de mensajes (MQ)

6. División de servicios de aplicaciones.

Además de los métodos anteriores, también es necesario dividir el sistema empresarial en microservicios por las siguientes razones:

  • El desarrollo empresarial conduce a un aumento en la complejidad de los programas de aplicación, lo que resulta en un aumento de la entropía.
  • Los sistemas empresariales tienen cada vez más funciones y cada vez más personas participan en iteraciones de desarrollo. Mantener un proyecto enorme es propenso a causar problemas.
  • Es difícil para un solo sistema de aplicación lograr una expansión horizontal y los recursos del servidor son limitados, lo que puede hacer que todas las solicitudes se concentren en un determinado nodo del servidor, lo que resulta en un consumo excesivo de recursos e inestabilidad del sistema.
  • Los costos de prueba e implementación aumentan gradualmente.

Lo más importante es que es difícil superar el cuello de botella de rendimiento de una sola aplicación.

Por ejemplo, para admitir 18.000 QPS, un solo nodo de servicio definitivamente no podrá admitirlo. Por lo tanto, la ventaja de la división de servicios es que se pueden utilizar varias computadoras para formar una red informática distribuida a gran escala y toda la lógica empresarial se puede completar a través de la comunicación de red.

6.1 Cómo dividir servicios

En cuanto a cómo dividir servicios, aunque parece simple, encontrará algunos problemas de límites en la operación real.

Por ejemplo, algunos modelos de datos se aplican tanto al módulo A como al módulo B. ¿Cómo trazar la línea? Además, ¿cómo debería determinarse la granularidad de la división de servicios?

Por lo general, la división de servicios se lleva a cabo según el negocio y la división de límites de los microservicios se guía de acuerdo con el diseño impulsado por dominio (DDD).

El diseño impulsado por dominio es una metodología que determina los límites comerciales y los límites de las aplicaciones mediante la definición de modelos de dominio para garantizar la coherencia de los modelos comerciales y los modelos de código .

Ya sea DDD o microservicios, debemos seguir los principios básicos del diseño de software: alta cohesión y bajo acoplamiento .

Debería haber una alta cohesión dentro de los servicios y un bajo acoplamiento entre ellos.

De hecho, un servicio de dominio corresponde a un conjunto de funciones y estas funciones tienen ciertos puntos en común.

Por ejemplo, los servicios de pedidos incluyen funciones como crear pedidos, modificar pedidos y consultar listas de pedidos. Cuanto más claros sean los límites del dominio, más fuerte será la cohesión de las funciones y menor será el acoplamiento entre los servicios.

La división del servicio también debe realizarse en función del equipo técnico actual y las condiciones de la empresa.

Para los equipos de nueva creación, no se deben buscar excesivamente los microservicios, para no causar que la lógica de negocios esté demasiado dispersa y la arquitectura técnica sea demasiado compleja. Además, la infraestructura no es perfecta, lo que puede llevar a un tiempo de entrega prolongado. y tener un mayor impacto en el desarrollo de la empresa. Por lo tanto, al realizar la división de servicios, también se deben considerar los siguientes factores:

  • Debido a la naturaleza de mercado del campo comercial de la empresa, si se trata de un proyecto sensible al mercado, el producto debe lanzarse primero y luego iterarse y optimizarse.
  • La madurez del equipo de desarrollo y si la tecnología del equipo puede manejarlo.
  • Si las capacidades básicas son suficientes, como DevOps, operación y mantenimiento, automatización de pruebas y otras capacidades básicas. Si el equipo tiene la capacidad de soportar la complejidad de operación y mantenimiento causada por la ejecución de una gran cantidad de instancias de servicio y si puede hacer un buen trabajo en el monitoreo del servicio.
  • La eficiencia de ejecución del equipo de pruebas: si el equipo de pruebas no puede soportar pruebas automatizadas, regresión automática, pruebas de estrés y otros medios para mejorar la eficiencia de las pruebas, inevitablemente conducirá a un aumento significativo en la carga de trabajo de pruebas y retrasará el ciclo de lanzamiento del proyecto.

Para la modernización de sistemas antiguos, puede haber más riesgos y problemas involucrados. Antes de comenzar la renovación, se deben considerar los siguientes pasos: la etapa de preparación previa a la división, el diseño del plan de renovación dividida y la implementación del plan dividido.

  • Antes de comenzar a descomponerse, es necesario tener una comprensión clara de la arquitectura general actual y las dependencias entre varios módulos, y al mismo tiempo, en la etapa de preparación, es necesario comprender principalmente las dependencias y las interfaces. De esta manera, se puede saber cómo operar durante la descomposición, por ejemplo, dónde hacer el primer corte, para convertir rápidamente un sistema único complejo en dos sistemas más pequeños, y al mismo tiempo también es necesario minimizar el impacto en el negocio existente del sistema. Evite crear una aplicación monolítica distribuida que contenga muchos servicios que estén estrechamente acoplados entre sí pero que deban implementarse juntos: esto se denomina sistema distribuido. Si se descompone a la fuerza sin realizar un análisis en profundidad, puede cortar accidentalmente dependencias importantes, lo que provocará una falla importante de Clase A con consecuencias desastrosas.
  • En diferentes etapas, el enfoque de la descomposición es diferente y cada etapa tiene sus cuestiones centrales que requieren atención. La descomposición en sí se puede dividir en tres etapas: descomposición de las partes principales y no comerciales, ajuste y diseño del negocio principal y descomposición interna del negocio principal. En la primera etapa, es necesario racionalizar el negocio principal y eliminar las partes no esenciales para reducir la escala del sistema que necesita ser procesado; en la segunda etapa, es necesario reconstruir la parte del negocio principal de acuerdo con las concepto de diseño de microservicios, en la tercera etapa En esta etapa, se debe implementar el diseño de refactorización de la parte central del negocio. Hay tres métodos de descomposición: descomposición de código, descomposición de implementación y descomposición de datos.

Además, cada etapa debe centrarse en uno o dos objetivos específicos, si hay demasiados objetivos es posible que no se consiga nada. Por ejemplo, la descomposición de microservicios de un determinado sistema tiene los siguientes objetivos:

  1. Indicadores de rendimiento (rendimiento y latencia): el rendimiento de las transacciones principales se duplica con creces (TPS: 1000->10000), la latencia del negocio A se reduce a la mitad (Latencia: 250 ms->125 ms) y la latencia del negocio B se reduce a la mitad (Latencia: 70 ms->35 ms).
  2. Indicadores de estabilidad (disponibilidad, tiempo de recuperación de fallas): Disponibilidad >=99.99%, tiempo de recuperación de fallas Clase A <=15 minutos, número de fallas en un trimestre <=1.
  3. Indicadores de calidad: redacte documentos completos de requisitos de producto, documentos de diseño, documentos de implementación y operación, más del 90 % de cobertura de prueba única del código de pieza de transacción principal y casos de prueba y cobertura de escenarios 100 % automatizados, para lograr un entorno de referencia de pruebas de rendimiento sostenible y prolongado. -término Mecanismo de optimización continua del rendimiento.
  4. Índice de escalabilidad : complete la descomposición razonable del código, la implementación, el tiempo de ejecución y los datos en múltiples dimensiones. Para cada módulo comercial y de transacción después de la reconstrucción del sistema central, así como el almacenamiento de datos correspondiente, la escalabilidad se puede lograr en cualquier momento agregando recursos de la máquina Extensión.
  5. Indicadores de mantenibilidad : Establezca indicadores de monitoreo integrales y completos, especialmente datos de indicadores de desempeño en tiempo real para todo el enlace, que cubra todos los negocios y estados clave, acorte el tiempo de monitoreo y respuesta de alarmas y coopere con el equipo de operación y mantenimiento para lograr la planificación de capacidad y Cuando surgen problemas, el sistema se puede iniciar en un minuto o retroceder a la última versión disponible (tiempo de inicio <= 1 minuto).
  6. Índice de facilidad de uso : La nueva interfaz API implementada mediante reconstrucción es razonable y simple, lo que satisface en gran medida las necesidades de los usuarios en todos los niveles y la satisfacción del cliente continúa aumentando.
  7. Indicadores de apoyo empresarial : Para el desarrollo de nuevas funciones de requisitos comerciales, bajo la premisa de garantizar la calidad, la eficiencia del desarrollo se duplica y los recursos y el ciclo de desarrollo se reducen a la mitad.

Por supuesto, no esperes completar todos los objetivos a la vez: puedes elegir uno o dos objetivos de alta prioridad para ejecutar en cada etapa.

6.2 Después de los microservicios, ¿cómo llevar a cabo la gobernanza de servicios?

La arquitectura de microservicios primero se manifiesta como una arquitectura distribuida, en segundo lugar, debemos demostrar y proporcionar capacidades de servicios comerciales y, a continuación, debemos considerar varias capacidades no funcionales relacionadas con estas capacidades comerciales. Estos servicios dispersos en diferentes ubicaciones deben gestionarse de manera uniforme sin dejar de ser transparentes para quienes llaman al servicio, lo que crea requisitos funcionales para el registro y descubrimiento de servicios.

De manera similar, cada servicio puede implementarse en múltiples instancias en múltiples máquinas, por lo que necesitamos tener capacidades de enrutamiento y direccionamiento para lograr el equilibrio de carga y mejorar la escalabilidad del sistema. Frente a tantas interfaces de servicios proporcionadas externamente, necesitamos un mecanismo para unificar el control de acceso y aplicar algunas políticas no comerciales a esta capa de acceso, como políticas relacionadas con permisos: esta es la función de la puerta de enlace de servicios. Al mismo tiempo, descubrimos que con el desarrollo de negocios y actividades operativas específicas (como ventas flash, grandes ventas, etc.), el tráfico puede aumentar más de diez veces. En este momento, debemos considerar el sistema. capacidad y las dependencias fuertes y débiles entre servicios, e implementar medidas tales como degradación del servicio, disyuntores y protección contra sobrecarga del sistema.

Debido a la complejidad que traen los microservicios, la configuración de aplicaciones y la configuración empresarial están dispersas en varios lugares, por lo que también surge la necesidad de un centro de configuración distribuido.

Finalmente, una vez que el sistema se implementa de manera descentralizada, todas las llamadas involucran procesos cruzados. También necesitamos un conjunto de tecnologías que puedan realizar el seguimiento de enlaces y el monitoreo del rendimiento en línea para que podamos comprender el estado interno y los indicadores del sistema en cualquier momento. tiempo, de manera que podamos monitorizar el sistema en cualquier momento, realizar análisis e intervención.

6.3 Diagrama de arquitectura general

A través de un análisis integral de micro a macro, básicamente podemos construir un diagrama de arquitectura completo.

  • Capa de acceso, que es el portal para que las solicitudes externas ingresen al sistema interno. Todas las solicitudes deben pasar por la puerta de enlace API.
  • La capa de aplicación, también conocida como capa de agregación, proporciona interfaces de agregación para negocios relacionados y llama a servicios de extremo medio para su combinación.
  • Los servicios atómicos incluyen servicios técnicos atómicos y servicios comerciales atómicos, que proporcionan interfaces relevantes según las necesidades comerciales.

Los servicios atómicos proporcionan capacidades reutilizables para toda la arquitectura.

Por ejemplo, el servicio de comentarios, como servicio atómico, es requerido por los videos, artículos y comunidades de Bilibili. Para mejorar la reutilización, el servicio de comentarios puede ser un servicio atómico independiente y no puede estar estrechamente vinculado con requisitos específicos.

En este caso, el servicio de comentarios debe proporcionar una capacidad de reutilización que pueda adaptarse a diferentes escenarios.

De manera similar, funciones como el almacenamiento de archivos, el almacenamiento de datos, los servicios push y los servicios de autenticación se precipitarán en los servicios atómicos. Los desarrolladores empresariales pueden crear rápidamente aplicaciones comerciales organizándolas, configurándolas y combinándolas en función de los servicios atómicos.

7. ¿Cómo cuantificar y medir 3-alto?

3¿Cómo cuantificar y medir lo alto?

No existe una definición exacta de alta concurrencia, que describe principalmente la situación de enfrentar una gran cantidad de tráfico en un corto período de tiempo.

Cuando esté en una entrevista o en el trabajo y su líder o entrevistador le pregunte cómo diseñar un sistema que pueda soportar decenas de millones de tráfico, puede seguir los pasos que le proporcioné para el análisis.

  • Primero, debe establecer algunos indicadores de datos cuantificables, como la tasa de consultas por segundo (QPS), los usuarios activos diarios (DAU), el número total de usuarios, las transacciones por segundo (TPS) y los picos de acceso.
  • Luego, basándose en estos datos, se comienza a diseñar la arquitectura del sistema.
  • Entonces impleméntelo

7.1 Indicadores macroscópicos en alta concurrencia

Un sistema que puede cumplir con altos requisitos de concurrencia no solo busca el rendimiento, sino que necesita cumplir al menos tres objetivos macro:

  • Alto rendimiento , que es la encarnación de las capacidades de procesamiento paralelo del sistema. Con una inversión limitada en hardware, mejorar el rendimiento significa ahorrar costos. Al mismo tiempo, el rendimiento también está relacionado con la experiencia del usuario: ya sea que el tiempo de respuesta sea de 100 milisegundos o 1 segundo, la experiencia del usuario es completamente diferente.
  • Alta disponibilidad , este es el momento en que el sistema puede brindar servicios con normalidad. Los usuarios definitivamente elegirán lo primero entre un sistema que no tiene problemas y no se detiene durante todo el año y un sistema que a menudo se estropea y deja de funcionar. Además, si la disponibilidad del sistema sólo puede alcanzar el 90%, también tendrá un impacto significativo en el negocio.
  • La alta escalabilidad se refiere a la escalabilidad del sistema, es decir, si puede completar la expansión en poco tiempo durante los períodos de mayor tráfico para resistir de manera más estable el tráfico pico, como eventos del Doble 11, divorcios de celebridades y otros eventos candentes.

7.2 Microindicadores

Actuación

A través de indicadores de desempeño, podemos medir los problemas de desempeño actuales y servir como base para la evaluación del desempeño optimizado. Normalmente utilizamos el tiempo de respuesta de la interfaz durante un período de tiempo como criterio de medición.

  1. Tiempo medio de respuesta : Esta es la medida más utilizada, pero tiene la desventaja de ser insensible a solicitudes lentas. Por ejemplo, de 10.000 solicitudes, 9.900 son de 1 milisegundo y 100 son de 100 milisegundos, entonces el tiempo de respuesta promedio es de 1,99 milisegundos. Aunque el tiempo promedio transcurrido solo aumentó en 0,99 milisegundos, el tiempo de respuesta para el 1% de las solicitudes se incrementó en un factor de 100.
  2. TP90, TP99 y otros valores cuantiles : este es un indicador que clasifica el tiempo de respuesta de pequeño a grande. TP90 representa el tiempo de respuesta clasificado en el cuantil 90. Cuanto mayor sea el valor cuantil, más sensible será a las solicitudes lentas.

métricas de disponibilidad

Alta disponibilidad significa que el sistema tiene una alta capacidad para ejecutarse sin fallas. Disponibilidad = tiempo medio de falla/tiempo total de ejecución del sistema. Generalmente usamos varios 9 para describir la disponibilidad del sistema.

Para sistemas de alta concurrencia, el requisito mínimo es garantizar 3 9 o 4 9. La razón es muy intuitiva. Si solo puedes hacer dos nueves, significa que hay un tiempo de falla del 1%. Para algunas grandes empresas con cientos de miles de millones de GMV o ingresos por año, el 1% del tiempo de falla conducirá a mil millones. -Impacto empresarial a nivel.

Índice de escalabilidad

Cuando nos enfrentamos a un tráfico intenso, no podemos modificar temporalmente la arquitectura, por lo que agregar máquinas para aumentar linealmente las capacidades de procesamiento del sistema es la forma más rápida.

Para grupos de negocios o componentes básicos, escalabilidad = relación de mejora del rendimiento / relación de adición de máquinas La escalabilidad ideal es: aumentar los recursos varias veces y mejorar el rendimiento varias veces. En términos generales, la escalabilidad debe mantenerse por encima del 70%.

Sin embargo, desde la perspectiva de la arquitectura general de un sistema de alta concurrencia, el objetivo de la expansión no es solo diseñar el servicio para que no tenga estado, porque cuando el tráfico aumenta 10 veces, el servicio comercial puede expandirse rápidamente 10 veces, sino la base de datos puede convertirse en un nuevo cuello de botella.

Los servicios de almacenamiento con estado como MySQL suelen ser técnicamente difíciles de ampliar. Si la arquitectura no se planifica con antelación (división vertical y horizontal), puede implicar la migración de una gran cantidad de datos.

Por lo tanto, una alta escalabilidad debe considerar: clústeres de servicios, middleware como bases de datos, cachés y colas de mensajes, equilibrio de carga, ancho de banda, terceros dependientes, etc. Cuando la concurrencia alcanza un cierto nivel, cada uno de los factores anteriores puede volverse escalable. .

7.3 Plan de práctica

enfoque de diseño universal

Aumentar proporcionalmente

Su objetivo es mejorar las capacidades de procesamiento de una sola máquina y el plan incluye:

  1. Mejore el rendimiento del hardware de una sola máquina: mejórelo aumentando la memoria, el número de núcleos de CPU, la capacidad de almacenamiento o actualizando el disco a SSD.
  2. Mejore el rendimiento del software de una sola máquina: use caché para reducir la cantidad de IO y use métodos concurrentes o asincrónicos para aumentar el rendimiento.

poner a escala

Dado que siempre existe un límite para el rendimiento de una sola máquina, en última instancia, es necesario introducir una expansión horizontal y mejorar aún más las capacidades de procesamiento concurrente mediante la implementación del clúster, incluidas las dos direcciones siguientes:

  1. Construya una arquitectura en capas: esta es la base para la expansión horizontal, porque los sistemas de alta concurrencia generalmente tienen negocios complejos y el procesamiento en capas puede simplificar problemas complejos y facilitar la expansión horizontal.
  2. Cada capa realiza una expansión horizontal: expansión horizontal sin estado y enrutamiento de fragmentos con estado. Los clústeres empresariales generalmente pueden diseñarse para que no tengan estado, mientras que las bases de datos y las cachés suelen tener estado. Por lo tanto, las claves de partición deben diseñarse para la fragmentación del almacenamiento. Por supuesto, el rendimiento de lectura también se puede mejorar mediante la sincronización maestro-esclavo y la separación de lectura y escritura.

7.3.1 Solución de práctica de alto rendimiento

  1. Implementación distribuida, compartiendo la presión de una sola máquina a través del equilibrio de carga.
  2. Almacenamiento en caché multinivel, incluido el uso de CDN, caché local, caché distribuido, etc. para datos estáticos, además de abordar problemas como teclas de acceso rápido, penetración de caché, concurrencia de caché y coherencia de datos en escenarios de caché.
  3. Optimización de bases de datos e índices, y uso de motores de búsqueda para resolver problemas de consultas complejas.
  4. Considere utilizar bases de datos NoSQL, como HBase, TiDB, etc., pero el equipo debe estar familiarizado con estos componentes y tener sólidas capacidades de operación y mantenimiento.
  5. Procesamiento asincrónico, el proceso secundario se procesa de forma asincrónica a través de subprocesos múltiples, colas de mensajes e incluso tareas retrasadas.
  6. Para el control del tráfico, considere si la empresa permite la limitación del tráfico (como escenarios de venta flash), incluida la limitación del tráfico de front-end, la limitación del tráfico de la capa de acceso de Nginx y la limitación del tráfico del lado del servidor.
  7. Los picos de tráfico se cortan y los valles se llenan, y el tráfico se recibe a través de colas de mensajes.
  8. Procesamiento concurrente, paralelizando la lógica en serie mediante subprocesos múltiples.
  9. Cálculo previo, como la escena de captura de sobres rojos, la cantidad del sobre rojo se puede calcular por adelantado y almacenar en caché, y usarse directamente al enviar sobres rojos.
  10. El precalentamiento de la caché utiliza tareas asincrónicas para precalentar los datos en la caché local o distribuida por adelantado.
  11. Reduzca la cantidad de IO, como la lectura y escritura por lotes de bases de datos y cachés, soporte de interfaz por lotes para RPC o reducción de llamadas RPC a través de datos redundantes.
  12. Reduzca el tamaño del paquete de datos durante la IO, incluido el uso de protocolos de comunicación livianos, estructuras de datos apropiadas, eliminación de campos redundantes en las interfaces, reducción del tamaño de la clave de caché, compresión del valor de la caché, etc.
  13. Optimice la lógica del programa, como la lógica de juicio de posicionamiento previo que tiene una alta probabilidad de bloquear el proceso de ejecución, optimice la lógica de cálculo del bucle For o adopte algoritmos más eficientes.
  14. Utilice varias tecnologías de agrupación, como el grupo de solicitudes HTTP, el grupo de subprocesos (considere el uso intensivo de CPU o IO para establecer los parámetros principales), la base de datos y el grupo de conexiones de Redis, etc.
  15. Optimización de JVM, incluido el tamaño de la nueva y antigua generación, la selección del algoritmo de GC, etc., para reducir la frecuencia y el consumo de tiempo del GC.
  16. Elija una estrategia de bloqueo, utilice el bloqueo optimista en escenarios donde hay más lecturas y menos escrituras, o considere reducir los conflictos de bloqueo mediante bloqueos segmentados.

7.3.2 Soluciones prácticas de alta disponibilidad

  1. La conmutación por error de nodo, Nginx y el marco de gobernanza de servicios admiten la conmutación por error de un nodo fallido a otro nodo.
  2. Conmutación por error de nodos que no son pares, mediante la detección de latidos y la implementación de la conmutación maestro-esclavo (como el modo centinela de Redis o el modo de clúster, la conmutación maestro-esclavo de MySQL, etc.).
  3. Establezca tiempos de espera, estrategias de reintento y diseños idempotentes en la capa de interfaz.
  4. Degradar el procesamiento, garantizar los servicios centrales, sacrificar los servicios no centrales y realizar disyuntores cuando sea necesario; o cuando hay un problema con el enlace central, hay un enlace alternativo.
  5. El control de flujo rechaza directamente o devuelve un código de error para las solicitudes que exceden las capacidades de procesamiento del sistema.
  6. La garantía de confiabilidad de la cola de mensajes incluye el mecanismo de reintento del lado del productor, la persistencia del agente de mensajes y el mecanismo de confirmación del lado del consumidor, etc.
  7. La versión en escala de grises admite la implementación de tráfico pequeño de acuerdo con la dimensión de la máquina, observando los registros del sistema y los indicadores comerciales, y luego impulsando el volumen completo una vez que la operación sea estable.
  8. El monitoreo y las alarmas incluyen monitoreo básico de CPU, memoria, disco, red, así como servidor web, JVM, base de datos, monitoreo de varios middleware y monitoreo de indicadores comerciales.
  9. Los simulacros de recuperación ante desastres, similares a la actual "ingeniería del caos", utilizan métodos destructivos en el sistema para observar si las fallas locales causarán problemas de disponibilidad.

La solución de alta disponibilidad considera principalmente tres aspectos: redundancia, compensaciones y operación y mantenimiento del sistema. También necesita tener un mecanismo de servicio de soporte y un proceso de manejo de fallas. Cuando ocurren problemas en línea, se pueden seguir y resolver en de manera oportuna.

7.3.3 Soluciones prácticas altamente escalables

  1. Una arquitectura en capas razonable, como la arquitectura en capas más común en Internet, puede superponer microservicios en capas de una manera más detallada de acuerdo con la capa de acceso a datos y la capa de lógica empresarial (pero es necesario evaluar el rendimiento y puede haber un salto más en la red)).
  2. La capa de almacenamiento se divide verticalmente según la dimensión empresarial y horizontalmente según la dimensión característica de los datos (subbase de datos y subtabla).
  3. La forma más común de dividir la capa empresarial se basa en dimensiones comerciales (como servicios de productos básicos, servicios de pedidos, etc. en escenarios de comercio electrónico), y también se puede dividir según interfaces centrales e interfaces no principales, y puede También se puede dividir según las solicitudes (como A C y A B, APP y H5).

Dilo al final

Las preguntas de la entrevista relacionadas con la arquitectura de implementación y la planificación de nodos son preguntas de entrevista muy comunes.

Si todos pueden responder el contenido anterior de manera fluida y completa, el entrevistador básicamente se sorprenderá y se sentirá atraído por usted.

Al final, al entrevistador le gustó tanto que "no puede evitarlo y se le hace la boca agua" . La oferta está por llegar.

Durante el proceso de aprendizaje, si tienes alguna duda, puedes venir a hablar con Nien, un arquitecto de 40 años.

referencias

https://zhuanlan.zhihu.com/p/422165687

Lectura recomendada

" Lado de NetEase: nodo único 2000Wtps, ¿cómo lo hace Kafka?"

" Lado del byte: compensación de transacción y reintento de transacción, ¿cuál es la relación?"

" Lado de NetEase: escritura Mysql de alto rendimiento de 25 Wqps, datos de 100 W se escriben en 4 segundos, ¿cómo lograrlo?"

" ¿ Cómo estructurar vídeos cortos de mil millones de niveles? "

" Explota, confía en" fanfarronear "para pasar por JD.com, salario mensual 40K "

" Es tan feroz que confío en" fanfarronear "para pasar por SF Express, y mi salario mensual es de 30.000 " .

" Explotó... Jingdong pidió 40 preguntas en un lado y, después de aprobarlas, fueron más de 500.000 " .

" Estoy tan cansado de hacer preguntas... Ali hizo 27 preguntas mientras preguntaba por su vida, y después de aprobarlas, son 600.000+ "

" Después de 3 horas de preguntas locas sobre Baidu, recibí una oferta de una gran empresa. ¡Este tipo es tan cruel!"

" Ele.me es demasiado cruel: frente a un Java avanzado, qué duro y cruel es el trabajo "

" Después de una hora de preguntas locas por parte de Byte, el tipo recibió la oferta, ¡es tan cruel!"

" Acepta la oferta de Didi: De tres experiencias de joven, ¿ves lo que necesitas aprender?"

"Notas de arquitectura de Nien", "Trilogía de alta concurrencia de Nien", "Guía de entrevistas de Nien Java" PDF, vaya a la siguiente cuenta oficial [Technical Freedom Circle] para obtener ↓↓↓

Supongo que te gusta

Origin blog.csdn.net/crazymakercircle/article/details/132526730
Recomendado
Clasificación