Configuración de tiempo de espera de RPC, ¡accidentalmente es un accidente en línea!

Autor | Luo Junwu

Fuente | Lugar de trabajo avanzado de personas de TI (ID: BestITer)

El cuadro de monitoreo anterior es familiar para los estudiantes de I + D en el lado del servidor. En el mantenimiento diario del sistema, el "tiempo de espera de servicio" debe pertenecer al tipo de problema con la mayoría de las alarmas de monitoreo.

Especialmente en la arquitectura de microservicios, una solicitud puede tener que pasar por un enlace muy largo, y el resultado solo puede devolverse después de múltiples llamadas de servicio. Cuando se produce un tiempo de espera de servicio, los estudiantes de I + D a menudo tienen que analizar el rendimiento de sus propios sistemas y confiar en el rendimiento de sus servicios, por lo que es más difícil investigar los tiempos de espera de servicio que los errores de servicio y las llamadas de servicio anormales.

Este artículo presentará sistemáticamente un verdadero accidente en línea: bajo la arquitectura del microservicio, cómo comprender correctamente y establecer el período de tiempo de espera de la interfaz RPC, para que todos tengan una perspectiva más global al desarrollar la interfaz del lado del servidor. El contenido se dividirá en las siguientes 4 partes:

  • De un accidente en línea causado por un tiempo de espera de la interfaz RPC

  • ¿Cuál es el principio de implementación del tiempo de espera?

  • ¿Qué problema establece el tiempo de espera para resolver?

  • ¿Cómo establecer un tiempo de espera razonable?

Hablando de un accidente en línea

El accidente ocurrió en el módulo de recomendación de la página de inicio de la aplicación de comercio electrónico, y un día de repente recibió comentarios de los usuarios al mediodía: a excepción del mapa de banner y el área de navegación en la página de inicio de la aplicación, el módulo de recomendación a continuación se convirtió en una página en blanco (el módulo de recomendación ocupa 2/3 del espacio de la página de inicio Es una lista de productos recomendados por el algoritmo en tiempo real según los intereses del usuario).

El escenario empresarial anterior se puede entender con la ayuda de la siguiente cadena de llamadas:

  • La aplicación inicia una solicitud HTTP a la puerta de enlace de servicio

  • La puerta de enlace de servicio RPC llama al servicio de recomendación para obtener una lista de productos recomendados

  • Si la llamada falla en el paso 2, el servicio se degrada y cambia a RPC para llamar al servicio de clasificación de mercancías y obtener una lista de las mercancías que se venden en caliente.

  • Si la llamada falla en el paso 3, vuelva a bajar de categoría y obtenga la lista de productos calientes en la memoria caché de Redis directamente

A primera vista, se tienen en cuenta las dos estrategias de degradación dependientes del servicio. En teoría, incluso si el servicio de recomendación o el servicio de pedidos de mercancías están colgados, el servidor debería poder devolver los datos a la aplicación. Sin embargo, el módulo de recomendación en el lado de la aplicación está en blanco, y la estrategia de degradación puede no ser efectiva. A continuación se describe el proceso de posicionamiento en detalle.

1. Proceso de localización del problema

Paso 1: El lado de la APLICACIÓN descubre a través de la captura de paquetes que la solicitud HTTP tiene un tiempo de espera de interfaz (el período de tiempo de espera se establece en 5 segundos).

Paso 2: La puerta de enlace de servicio encontró a través del registro que se produjo un tiempo de espera de área grande en la interfaz RPC que llama al servicio recomendado (el tiempo de espera se establece en 3 segundos), y el mensaje de error es el siguiente:

Paso 3: el servicio de recomendación que se encuentra a través del registro: el grupo de subprocesos de dubbo se agota y el mensaje de error es el siguiente:

A través de los tres pasos anteriores, el problema se ubicó básicamente en el servicio de recomendación y luego se investigó que la falta de disponibilidad del clúster redis de la que depende el servicio de recomendación causó un tiempo de espera que, a su vez, agotó el grupo de subprocesos. Las razones detalladas no se expanden aquí, y no son relevantes para el tema que se discutirá en este artículo.

2. Análisis de las razones por las cuales la estrategia de rebaja no tuvo efecto

Continuemos con el análisis a continuación: ¿Por qué la estrategia de degradación de la puerta de enlace de servicio no tiene efecto cuando falla la llamada de servicio de recomendación? Teóricamente, ¿no deberíamos rebajar la calificación para llamar al servicio de pedidos de productos para su respaldo?

El análisis de seguimiento final encontró la causa raíz: el tiempo de espera para que la aplicación llame a la puerta de enlace comercial es de 5 segundos, el tiempo de espera para que la puerta de enlace comercial llame al servicio recomendado es de 3 segundos, y también establece 3 reintentos de tiempo de espera, de modo que cuando la llamada de servicio recomendada falla, el primero Al volver a intentarlo dos veces, la solicitud HTTP ha excedido el tiempo de espera, por lo que todas las políticas de degradación de la puerta de enlace de servicio no tendrán efecto. El siguiente es un esquema más intuitivo:

3. Soluciones

  • Cambió el tiempo de espera para que la puerta de enlace de servicio llame al servicio recomendado a 800 ms (el servicio recomendado TP99 es de aproximadamente 540 ms), y cambió el tiempo de reintento de tiempo de espera a 2

  • Se modificó el período de tiempo de espera para que la puerta de enlace de servicio llame al servicio de pedido de productos a 600 ms (TP99 para el servicio de pedido de productos es de aproximadamente 400 ms), y el número de intentos de reintento de tiempo de espera se cambió a 2

En cuanto a la configuración del tiempo de espera y el número de reintentos, se deben considerar muchos factores, como el consumo de tiempo de todos los servicios dependientes en toda la cadena de llamadas y si cada servicio es un servicio central. No comenzaré aquí, y presentaré los métodos específicos en detalle más adelante.

¿Cuál es el principio de implementación del tiempo de espera?

Solo entendiendo el principio de tiempo de espera del marco RPC podemos configurarlo mejor. Ya sea dubbo, SpringCloud o un marco de microservicio desarrollado por un gran fabricante (como JSF en JD), el principio de implementación del tiempo de espera es básicamente similar. Tomemos el código fuente de Dubbo 2.8.4 como ejemplo para ver la implementación específica.

Los estudiantes que están familiarizados con dubbo saben que el período de tiempo de espera se puede configurar en dos lugares: el proveedor (servidor, proveedor de servicios) y el consumidor (consumidor, persona que llama al servicio). La configuración de tiempo de espera del servidor es la configuración predeterminada del consumidor, es decir, siempre que el servidor establezca el período de tiempo de espera, no es necesario que todos los consumidores lo establezcan, y se puede pasar al consumidor a través del centro de registro. De esta manera: por un lado, la configuración se simplifica, por otro lado Debido a que el servidor es más consciente del rendimiento de su interfaz, es razonable dejarlo al servidor para su configuración.

Dubbo admite configuraciones de tiempo de espera muy finas, que incluyen: nivel de método, nivel de interfaz y global. Si todos los niveles se configuran al mismo tiempo, la prioridad es: nivel del método del consumidor> nivel del método del servidor> nivel de la interfaz del consumidor> nivel de la interfaz del servidor> consumidor global> servidor global.

A través del código fuente, primero observamos la lógica de procesamiento del tiempo de espera del servidor

 1public class TimeoutFilter implements Filter { 2 3    public TimeoutFilter() { 4    } 5 6    public Result invoke(...) throws RpcException { 7        // 执行真正的逻辑调用,并统计耗时 8        long start = System.currentTimeMillis(); 9        Result result = invoker.invoke(invocation);10        long elapsed = System.currentTimeMillis() - start;1112        // 判断是否超时13        if (invoker.getUrl() != null && elapsed > timeout) {14            // 打印warn日志15            logger.warn("invoke time out...");16        }1718        return result;19    }20}


Se puede ver que incluso si el servidor agota el tiempo de espera, solo imprime un registro de advertencia. Por lo tanto, la configuración del tiempo de espera del servidor no afectará el proceso de llamada real, e incluso si se agota el tiempo de espera, se ejecutará toda la lógica de procesamiento .

Veamos la lógica de procesamiento del tiempo de espera del lado del consumidor

 1public class FailoverClusterInvoker { 2 3    public Result doInvoke(...)  { 4        ... 5        // 循环调用设定的重试次数 6        for (int i = 0; i < retryTimes; ++i) { 7            ... 8            try { 9                Result result = invoker.invoke(invocation);10                return result;11            } catch (RpcException e) {12                // 如果是业务异常,终止重试13                if (e.isBiz()) {14                    throw e;15                }1617                le = e;18            } catch (Throwable e) {19                le = new RpcException(...);20            } finally {21                ...22            }23        }2425        throw new RpcException("...");26    }27}

FailoverCluster es el modo predeterminado de tolerancia a fallas del clúster. Cuando la llamada falla, cambiará a llamar a otros servidores. Mire nuevamente el método doInvoke: cuando la llamada falla, primero determinará si se trata de una excepción comercial, si es así, luego finalizará el reintento, de lo contrario continuará reintentando hasta que se alcance el número de reintentos.

Continúe siguiendo el método de invocación de invocador, puede ver que el resultado se obtiene a través del método get de Future después de que se emite la solicitud, el código fuente es el siguiente:

 1public Object get(int timeout) { 2        if (timeout <= 0) { 3            timeout = 1000; 4        } 5 6        if (!isDone()) { 7            long start = System.currentTimeMillis(); 8            this.lock.lock(); 910            try {11                // 循环判断12                while(!isDone()) {13                    // 放弃锁,进入等待状态14                    done.await((long)timeout, TimeUnit.MILLISECONDS);1516                    // 判断是否已经返回结果或者已经超时17                    long elapsed = System.currentTimeMillis() - start;18                    if (isDone() || elapsed > (long)timeout) {19                        break;20                    }21                }22            } catch (InterruptedException var8) {23                throw new RuntimeException(var8);24            } finally {25                this.lock.unlock();26            }2728            if (!isDone()) {29                // 如果未返回结果,则抛出超时异常30                throw new TimeoutException(...);31            }32        }3334        return returnFromResponse();35    }


Después de ingresar el método, se inicia el temporizador. Si no se obtiene ningún resultado de retorno dentro del período de tiempo de espera establecido, se emite una TimeoutException. Por lo tanto, la lógica de tiempo de espera del consumidor está controlada por los dos parámetros del tiempo de espera y el número de tiempos de espera, como las excepciones de red y los tiempos de espera de respuesta, que siempre volverán a intentar hasta que se alcance el número de intentos.

¿Qué problema está configurado para resolver el tiempo de espera?

¿Qué problema resuelve el mecanismo de reintento de tiempo de espera del marco RPC? Desde la perspectiva macro de la arquitectura de microservicios, es para garantizar la estabilidad del enlace de servicio y proporcionar una tolerancia a fallas a nivel de marco. ¿Cómo entenderlo microscópicamente? Se puede ver a partir de los siguientes casos específicos:

1. El consumidor llama al proveedor. Si no se establece el tiempo de espera, el tiempo de respuesta del consumidor será definitivamente mayor que el tiempo de respuesta del proveedor. Cuando el desempeño del proveedor se deteriora, el desempeño del consumidor también se ve afectado porque debe esperar indefinidamente la devolución del proveedor. Si todo el enlace de la llamada pasa por múltiples servicios A, B, C y D, siempre que el rendimiento de D se deteriore, afectará a A, B y C de abajo hacia arriba, lo que eventualmente hará que todo el enlace se agote o incluso se paralice, así que configure El tiempo de espera es muy necesario.

2. Suponga que el consumidor es el servicio básico de productos básicos y el proveedor es un servicio de revisión no básico. Cuando el servicio de evaluación tiene problemas de rendimiento, el servicio de productos básicos no puede aceptar la devolución de la información de evaluación, asegurando así que puede continuar proporcionando servicios externos. En este caso, debe establecerse un período de tiempo de espera. Cuando el servicio de evaluación excede este umbral, el servicio de productos no necesita continuar esperando.

3. Lo más probable es que el proveedor se deba a una fluctuación momentánea de la red o a un tiempo de espera causado por una alta carga de la máquina. Si se da por vencido directamente después del tiempo de espera, algunos escenarios causarán pérdidas comerciales (como el tiempo de espera de la interfaz de inventario hará que el pedido falle). Por lo tanto, para esta inquietud de servicio temporal, si vuelve a intentarlo después de un tiempo de espera, se puede guardar, por lo que es necesario resolverlo mediante un mecanismo de reintento.

Pero después de introducir el mecanismo de reintento de tiempo de espera, no todo es perfecto. También trae efectos secundarios. Estos son los problemas que deben tenerse en cuenta al desarrollar interfaces RPC, y también son los problemas más fáciles de pasar por alto:

  1. Solicitud repetida: es posible que el proveedor haya terminado de ejecutarse, pero debido a que el consumidor de jitter de red piensa que ha excedido el tiempo de espera, en este caso el mecanismo de reintento causará solicitudes repetidas, lo que causará problemas de datos sucios, por lo que el servidor debe considerar la idempotencia de la interfaz.

  2. Reduzca la capacidad de carga del consumidor : si el proveedor no es una inquietud temporal, pero sí existe un problema de rendimiento, por lo que volver a intentarlo varias veces no tendrá éxito, pero prolongará el tiempo de respuesta promedio del consumidor. Por ejemplo, en circunstancias normales, el tiempo de respuesta promedio del proveedor es 1s, el consumidor establece el tiempo de espera en 1.5s, y el número de reintentos se establece en 2, de modo que una sola solicitud tomará 3s, la carga total del consumidor se reducirá, si el consumidor Es un servicio de alto QPS y puede provocar una reacción en cadena que provoque una avalancha.

  3. Tormenta de reintento explosivo : si un enlace de llamada pasa 4 servicios, el servicio D más bajo agota el tiempo de espera, de modo que los servicios en sentido ascendente iniciarán el reintento, suponiendo que los tiempos de reintento estén configurados en 3, entonces B será normal. En el caso de 3 veces la carga, C es 9 veces y D es 27 veces, todo el clúster de servicios puede estar en avalancha.

¿Cómo establecer un tiempo de espera razonable?

Después de comprender el principio de implementación del tiempo de espera del marco RPC y los posibles efectos secundarios, puede establecer el tiempo de espera de acuerdo con los siguientes métodos:

  • Antes de configurar el tiempo de espera de la persona que llama, primero comprenda el tiempo de respuesta del TP99 que depende del servicio (si el rendimiento del servicio dependiente fluctúa mucho, también puede ver TP95). El tiempo de espera de la persona que llama puede aumentar en un 50% sobre esta base

  • Si el marco RPC admite configuraciones de tiempo de espera multigranular, entonces: el tiempo de espera global debe ser ligeramente mayor que el tiempo que consume más tiempo a nivel de interfaz, el tiempo de espera para cada interfaz debe ser ligeramente mayor que el tiempo que consume más tiempo a nivel de método y el tiempo de espera para cada método El tiempo debe ser ligeramente mayor que el tiempo real de ejecución del método.

  • Distinga entre servicio recuperable y servicio no recuperable: si la interfaz no implementa idempotencia, no está permitido establecer el número de reintentos. Nota: La interfaz de lectura es idempotente natural, y la interfaz de escritura puede usar la identificación del documento comercial o generar una identificación única en la persona que llama y pasarla al servidor. Esta identificación se usa para evitar el peso y evitar la introducción de datos sucios.

  • Si el marco RPC admite la configuración de tiempo de espera del servidor, también se establece en secuencia según las tres reglas anteriores, de modo que se pueda evitar la configuración sin la configuración del cliente y se reduzcan los peligros ocultos.

  • Desde una perspectiva empresarial, si los requisitos de disponibilidad del servicio no son tan altos (como los sistemas de aplicaciones internas), puede volver a intentarlo manualmente manualmente sin establecer el número de reintentos de tiempo de espera, lo que puede reducir la complejidad de la implementación de la interfaz, pero es más propicio para Post-mantenimiento

  • Cuanto mayor sea la configuración del número de reintentos, mayor será la disponibilidad del servicio y la pérdida comercial se puede reducir aún más, pero los riesgos de rendimiento también serán mayores. Esto debe establecerse de manera integral en varias veces (generalmente 2 veces, hasta 3 veces)

  • Si la persona que llama es un servicio de QPS alto, debe considerar la estrategia de reducción de categoría y fusible cuando el servidor está en horas extras. (Por ejemplo, si más del 10% de las solicitudes son incorrectas, detenga el mecanismo de reintento y sople directamente, y cambie para llamar a otros servicios, mecanismo MQ asíncrono o use los datos en caché de la persona que llama)

Finalmente, un breve resumen:

La configuración de tiempo de espera de la interfaz RPC parece ser simple, pero de hecho hay muchas preguntas universitarias. No solo implica muchos problemas técnicos (como la idempotencia de la interfaz, la degradación del servicio y los fusibles, la evaluación y la optimización del rendimiento), sino que también debe evaluar la necesidad desde una perspectiva comercial. Sepa qué es y espere que este conocimiento le brinde una perspectiva más global al desarrollar interfaces RPC.

Las palabras clave no son fáciles. Si cree que este artículo es valioso para usted, reenvíelo a su círculo de amigos y haga clic para leerlo. ¡Gracias por su aliento y apoyo!

【FINAL】

Más recomendaciones interesantes

Tomando el primer lugar en los productos de contenedores de Gartner, ¡Alibaba Cloud gana la batalla clave de cloud native!

El entrevistador de Tencent me preguntó este árbol binario, simplemente soy | El Programa de la Fuerza

☞ Ganando GitHub 2000+ Star, ¿cómo supera la plataforma de aprendizaje automático Alink de código abierto de Alibaba Cloud el doble "juego" de 11 datos? | AI Tecnología Ecología

¿Microsoft adquirió una compañía para una persona? ¡Descifra programas de Sony, escribe novelas de hackers y mira su dura vida de programa!

Plantilla de proyecto de aprendizaje automático: 6 pasos básicos del proyecto ML

☞IBM, Microsoft, Apple, Google, Samsung ... ¡Estos gigantes de la tecnología en la cadena de bloques ya han hecho tantas cosas!

Resumen de programadores senior: te contaré las 6 formas de analizar el proceso de Linux

El bienestar de hoy: si deja un comentario en el área de comentarios, puede obtener un boleto para la transmisión en vivo de la "Conferencia de diez mil desarrolladores de inteligencia artificial de 2020" por un valor de 299 yuanes . Ven y mueve tu dedo y escribe lo que quieres decir.

Haga clic para leer el texto original, ¡maravilloso para continuar!

Cada "observación" que pides, me lo tomo en serio

1945 artículos originales publicados · 40 mil likes + · 18.18 millones de visitas

Supongo que te gusta

Origin blog.csdn.net/csdnnews/article/details/105445747
Recomendado
Clasificación