¡La interfaz tomó más de 2000 segundos! ¡Estoy entumecida!

¡La interfaz tomó más de 2000 segundos! ¡Estoy entumecida!

  • Hace unas mañanas había un servicio push que seguía llamando a la policía y lo reportaba muchas veces, cada vez los estudiantes de operación y mantenimiento tenían que reiniciar el servicio para mantenerlo, como yo estaba a cargo de esto, de repente me puse nervioso y se apresuró a la empresa. ¡No comas, comprueba rápidamente!

1. Síntomas y pasos para la resolución de problemas:

La siguiente es una captura de pantalla de varias alarmas en la tarde:

  • Mira la foto de abajo. . . . La interfaz se agotó durante más de 2000 segundos. . . . ¡Mi corazón esta roto! ! ! ¡La gente también está entumecida! ! ! Mi cerebro está zumbando. . .
  • imagen.png
  • Además, siempre informa que el pod no está saludable y no está disponible, ¡estas advertencias más serias!
  • imagen.png

Mi primera reacción es que la persona que llama tiene una operación de envío grupal, y luego miré los qps de la interfaz, ¡parece que no es alto! Eso es 9req / s. Después de eso, fui a la plataforma de monitoreo de grafana para observar la información de jvm y descubrí que la cantidad de subprocesos ha aumentado y el WAITINGestado aumentado.

El siguiente es el seguimiento de un pod:

imagen.png imagen.png

Para observar qué estado de hilo ha ido subiendo, hagamos clic para ver los detalles:

imagen.png

En la figura anterior, puede ver que el diagrama de estado de subprocesos del pod muestra los 6 estados de subprocesos, que están representados por líneas de diferentes colores. Y el más alto también aumenta después de las 14: 00. La línea azul representa el número de subprocesos en el estado EN ESPERA.

A través del fenómeno en la imagen de arriba, probablemente sé que debe haber un hilo que ha estado allí todo el tiempo Más tarde, le pedí al compañero de operación y mantenimiento que volcara el archivo del hilo y lo analicé para ver dónde entró el hilo en la espera wait. 无限wait下去! ! !

El siguiente es el archivo de hilo descargado, puede ver la búsqueda 427个WAITING,这也基本和 grafana 监控中状态是WAITTING的线程数量一致

imagen.png

Aquí viene el punto importante (la información de la pila del estado ESPERANDO proviene de algún lugar de IOSPushStrategy#pushMsgWithIOSeste

imagen.png 而类 PushNotificationFuture 继承了 CompletableFuture,他自己又没有get方法,所以本质上 就是调用的 CompletableFuture的 get 方法。 imagen.png ps:提一嘴,我们这里的场景是 等待ios push服务器的结果,不知道啥情况,今天(指发生故障的那天)ios push服务器(域名: api.push.apple.com )一直没返回,所以就导致一直等待下去了。。

看到这, 我 豁然开朗 && 真相大白 了,原来是在使用 CompletableFutureget时候,没设置超时时间,这样的话会导致一直在等结果。。。(但代码不是我写的,因为我知道 CompletableFuture 的get不设置参数会一直等下去 ,我只是维护,后期也没怎么修改这块的逻辑,哎 ,说多了都是泪呀!)

好一个 CompletableFuture#get();

(真是 死等啊。。。一点不含糊的等待下去,等的天荒地老海枯石烂也要等下去~~~ )

到此,问题的原因找到了。

2、 修复问题

解决办法很简单,给CompletableFuture的get操作 加上超时时间即可,如下代码即可修复: imagen.png

在修复后,截止到今天(6月8号)没有这种报警情况了,而且线程数和WAITING线程都比较稳定,都在正常范围内,如下截图(一共4个pod): imagen.png

至此问题解决了~~~ 终于可以睡个好觉啦!

3、 复盘总结

3.1、 代码浅析

既然此次的罪魁祸首是 CompletableFuture的get方法 那么我们就浅析一下 :

  1. 首先看下 get(); 方法 imagen.png imagen.png

Arriba puede ver el método get sin if(deadLine==0) 成立 parámetros: , es decir, el método park(this); finalmente se llama al método LockSupport, y este método finalmente llama al método no seguro -> unsafe.park(false, 0L); el segundo El primero El parámetro es cuánto tiempo esperar, unpark activará el subproceso suspendido y 0 significa esperar indefinidamente.

  1. Mirando get(long timeOut,TimeUnit unit);el método imagen.pngpodemos ver el método get con if(deadLine==0) 不成立,走的else逻辑 parámetros: es decir, el método que finalmente se llama, y ​​este método finalmente es llamado por LockSupporteste método -> el segundo parámetro es el parámetro tiimeOut que pasa cuando llama get (es solo que la capa inferior se convierte en nanosegundos)parkNanos(this,nanos);unsafeunsafe.park(false, nanos);

    Ejecutamos el programa y descubrimos que después del tiempo especificado, get(long timeOut,TimeUnit unit);el método arroja una TimeoutException. En cuanto a cómo nuestros desarrolladores lo manejan después del tiempo de espera, depende de la situación específica.
    Exception in thread "main" java.util.concurrent.TimeoutException
            at java.base/java.util.concurrent.CompletableFuture.timedGet(CompletableFuture.java:1886)
            at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2021)
    

Y en mi otro artículo, análisis de texto largo de , en este artículo, en realidad 深入过openjdktenemos el código fuente, la experiencia parky unparkla operación, tomemos una captura de pantalla para recordar:

imagen.png

3.2 Resumen final:

1. Al llamar a la interfaz externa. Asegúrese de prestar atención a la configuración del período de tiempo de espera para evitar que el servicio de terceros afecte su propio servicio después de un problema.

2. No importa qué tipo de Futuro vea en el futuro, debe tener cuidado, porque esto es asincrónico, pero cuando llama al método get, esencialmente está esperando sincrónicamente, por lo que debe establecer un tiempo de espera para él, de lo contrario, ¿cuándo ¡Depende de la voluntad de Dios devolver el resultado!

3. Prepárese para lo peor cuando se conecte con un tercero, y es necesario un enfoque de falla rápida.

4. ¡ Cuando encuentre grandes problemas, mantenga la calma tanto como sea posible y no se confunda!

Acho que você gosta

Origin juejin.im/post/7242237897993814075
Recomendado
Clasificación