Análisis posterior al incidente de Kagi de la semana pasada
(status.kagi.com)Resolución del problema de inestabilidad del servicio de Kagi.com
- Investigando - Después del despliegue surgió un problema y el equipo estuvo trabajando en resolverlo. (12 de enero, 16:45 UTC)
- Monitoreando - Se revirtió el cambio de configuración que se estima fue la causa del problema y se sigue monitoreando que el servicio vuelva a la normalidad. (12 de enero, 18:30 UTC)
- Actualización - Para recuperar completamente la estabilidad, se suspenderá temporalmente el tráfico y se redirigirá a los usuarios a esta página. Se compartirán más detalles conforme avance la situación mientras el servicio se restablece de manera controlada. (12 de enero, 20:26 UTC)
- Monitoreando - El tráfico ya fue restablecido y se sigue monitoreando que el servicio vuelva completamente a la normalidad. (12 de enero, 21:14 UTC)
- Resuelto - Todos los servicios están operando con normalidad. Agradecen a los usuarios por esperar mientras se resolvía el problema.
Análisis posterior
- Zac, líder técnico de Kagi, compartió un análisis posterior detallado sobre la interrupción del servicio de la semana pasada.
- En respuesta a este incidente, el ingeniero senior Seth y el ingeniero de DevOps Luan trabajaron juntos.
- Hubo actores que abusaron del servicio y explotaron cuellos de botella en la infraestructura; se tomaron medidas inmediatas de mitigación y se están realizando mejoras en varias áreas del código y de la comunicación.
Cómo ocurrió el incidente
- Alrededor de las 5:30 p. m. del 12 de enero, detectaron un problema en la infraestructura a través del monitoreo interno y de reportes de usuarios.
- La naturaleza del problema provocaba cargas lentas o timeout de página para usuarios en distintas regiones.
- Resolver el problema tomó bastante tiempo, y aquí explican el contexto, el desarrollo de los hechos y los planes a futuro.
Proceso técnico de resolución
- Al principio, el problema coincidió casualmente con una actualización de recursos de RAM adicional en una VM.
- El monitoreo reportó alta latencia y problemas en el pool de conexiones a la base de datos de la aplicación.
- El pool de conexiones llegó a saturarse, lo que significaba que la cantidad total de conexiones superaba el límite máximo configurado.
- Mientras evaluaban la salud interna de la base de datos y el rendimiento de las consultas, probaron reemplazar algunas instancias para ver si eso ayudaba a reducir la congestión.
- Como parecía que reemplazar parte de las instancias ayudaba, pausaron temporalmente el tráfico de usuarios para restablecer por completo todos los pools de conexiones de una sola vez.
- Al revisar el estado de la base de datos, quedó claro que la causa raíz era una alta contención sobre filas de la tabla de usuarios.
- Esa contención incrementó bruscamente la latencia de escritura, generó backpressure sobre el pool de conexiones de la aplicación y finalmente agotó todas las conexiones disponibles.
- Hasta ahora, Kagi había estado usando la base de datos de un solo núcleo más barata disponible en GCP, lo que implicaba el riesgo de dejar la base de datos inutilizada con facilidad.
- Identificaron a los actores maliciosos y encontraron cuentas creadas en menos de 24 horas, además de una sola cuenta de usuario que realizó más de 60,000 búsquedas en poco tiempo.
- Se eliminó la capacidad de búsqueda de esa cuenta y se publicó un hotfix que desactiva la escritura específica que causó el problema.
- Para la medianoche, el problema quedó completamente resuelto, y siguen monitoreando de cerca cualquier señal de que esos actores regresen.
Próximas acciones
- Aprendieron mucho de este incidente y ya están en marcha planes inmediatos para reforzar más el sistema y mejorar el proceso de comunicación durante incidentes.
- Primero, reconocen que las actualizaciones de la página de estado no fueron lo suficientemente rápidas.
- Planean migrar a una plataforma de página de estado que permita exponer más fácilmente a los usuarios el monitoreo interno automatizado, para que puedan ver en tiempo real la salud de la plataforma.
- Están mitigando directamente las consultas problemáticas y ejecutando pruebas de carga para ver si existen fallas similares adicionales.
- También instalarán monitoreo adicional para apuntar más rápido al lugar correcto dentro de la infraestructura y evitar perder tiempo siguiendo señales equivocadas como ocurrió esta vez.
- Están reforzando los sistemas que detectan este tipo de abuso, y como este no solo afecta el rendimiento sino que también genera costos directos, necesitan establecer límites automatizados para hacerlos cumplir.
- Las nuevas restricciones ya estaban activas al momento de esta publicación, y seguirán monitoreando su impacto y ajustándolas según sea necesario.
- Si alguien cree que su acceso a Kagi fue bloqueado por error, piden que se comunique a support@kagi.com.
Opinión de GN⁺
- Kagi sufrió un problema de latencia de escritura causado por contención de filas en la tabla de usuarios, lo que generó backpressure en el pool de conexiones de la aplicación y terminó provocando la caída del servicio.
- Este problema fue consecuencia del riesgo asociado a que Kagi utilizara la base de datos de un solo núcleo más barata de GCP.
- El equipo de Kagi mostró su intención de mejorar la estabilidad y la transparencia del servicio mediante acciones como reforzar el sistema, mejorar la comunicación con los usuarios y establecer límites automatizados para prevenir abusos. Estos esfuerzos reflejan la voluntad de Kagi de ofrecer un servicio más confiable a sus usuarios.
1 comentarios
Opiniones de Hacker News
Al principio resultó ser pura coincidencia que la actualización de infraestructura para agregar RAM a la VM y la interrupción ocurrieran exactamente a la misma hora, pero estas “coincidencias” pasan muy seguido y te hacen dudar de su propia existencia mientras rastreas el problema.
Si en ese estado entras en pánico, terminas metiendo un hotfix que rompe otra cosa, y a partir de ahí todo se vuelve mucho más doloroso.
La ley de Murphy es cruel con administradores de sistemas y desarrolladores.
Hay una frase que me gusta: “si no sabes por qué/cómo lo arreglaste, quizá en realidad no lo arreglaste”.
“Por suerte” no tenía nada que ver con mi consulta, pero cuando se juntan dos coincidencias así, da mucho miedo.
Después de pasar por esto suficientes veces, desarrollé el hábito de cuestionar más supuestos y de no marcar como datos confirmados cosas que todavía no se verificaron.
No eliminé por completo los sesgos ni las conclusiones apresuradas, pero ayudó, y mantener la mente abierta es bastante difícil.
Una habilidad importante para un ingeniero es poder razonar críticamente sobre los cambios de respuesta a incidentes, depurarlos y “probarlos de forma aislada”. Es mucho más difícil de lo que parece y normalmente se acerca a una habilidad de senior.
Fui uno de los usuarios que reportó este problema en Discord. Me gusta Kagi, pero fue bastante decepcionante que la página de estado mostrara que todo estaba normal.
Me inquietó que, incluso durante una interrupción que afectaba a usuarios reales, la página de estado pareciera no ser una prioridad, y espero que en adelante se actualice con precisión.
En el pasado, servicios de los que dependía mucho, como GitHub, actualizaban la página de estado de inmediato, y eso me tranquilizaba porque sabía que el problema no era de mi dispositivo, sino un problema reconocido del servicio.
Esta vez necesitaba encontrar una tienda de comestibles cercana que estuviera abierta antes de que nevara ese día, y al final tuve que ir a Google, lo que me decepcionó un poco.
Aun así, el 99.9% del tiempo que he usado Kagi ha sido mejor que Google, así que lo seguiré usando, y espero que, como dijeron en el postmortem, muevan el código de la página de estado a otro servicio/plataforma.
Al final, publicar algo en la página de estado se convierte en una conversación en sí misma, y esa conversación consume tiempo y atención de los ingenieros, lo que retrasa la resolución del incidente.
Hay que equilibrar la comunicación con la recuperación real, y la respuesta correcta no siempre es clara.
Si hay suficiente gente, un Technical Incident Manager puede encargarse de la comunicación y se pueden sumar más ingenieros al lado de comunicaciones, pero no siempre es posible. Algunos sistemas son especializados, tienen poca documentación y poca instrumentación.
Personalmente prefiero publicar un aviso grande y ambiguo de “estamos investigando un posible problema” apenas aparecen señales de problemas, y luego completar los detalles o retirarlo. Pero a las empresas en las que trabajé no les gustaba esa idea.
En ese momento Kagi me atrajo mucho y probé alternar algunas consultas, pero a medida que LLM, Perplexity y Google responden cada vez más directamente desde la página de búsqueda, no me quedan muchas consultas para Kagi.
Sería bastante interesante si Kagi de algún modo se fusionara con Perplexity.
Muchas veces ni siquiera la muestran hasta el final.
Esta interrupción me resulta tan familiar que sorprende.
Personalmente he lidiado más veces de las que quisiera admitir con exactamente este tipo de interrupción, y al igual que el equipo de Kagi, caí en la madriguera del estado del pool de conexiones de la base de datos y probé las mismas mitigaciones, como meter nuevas instancias o creer que “resetear” el tráfico lo resolvería, pero fue en vano.
En este tipo de interrupciones tampoco ayuda que los indicadores habituales de saturación de la base de datos, como uso de CPU, IOPS, etc., casi no se muevan. La latencia de las consultas se ve alta, pero uno piensa “hay margen de CPU e IOPS…”, y termina pasando por alto que, como siempre, había contención de locks escondida.
Por experiencia, el 98% de las anomalías en un pool de conexiones a la DB se originan en anomalías de la propia DB. No sé qué base de datos relacional usa Kagi, pero recomiendo mucho graficar la latencia global de espera de I/O de la DB (segundos/segundo), el tiempo global de adquisición de locks (segundos/segundo) y el tiempo de ejecución por consulta normalizada (segundos/segundo).
Si a eso se le suma una gráfica de uso de CPU, se obtiene un dashboard que permite identificar rápido la mayoría de los problemas de rendimiento a gran escala.
Por separado, me sorprende un poco que las consultas de búsqueda provoquen escrituras en una base de datos relacional. Pensé que la base de datos relacional se usaría solo para cosas como configuración de usuarios y gestión de inicios de sesión.
Si Kagi está haciendo agregación de uso en la base de datos relacional, por ejemplo incrementando contadores, es un modo de falla muy típico que explota al escalar.
Puede haber escrituras indirectas por una búsqueda, como cuando se bloquean resultados, y obviamente también historial de visitas o analítica.
Aun así, no queda claro qué podría estar causando contención de locks de escritura por cada búsqueda.
Es algo por lo que toda startup pasa en algún momento. Lo viví y es realmente doloroso.
A veces no hay tiempo ni recursos para desarrollar la capacidad de prevenir estos problemas, y otras veces ni siquiera se te ocurre que cierto problema pueda ocurrir hasta que te golpea por la espalda.
La transparencia es importante, y aprender también, pero a veces la compensación también importa. Kagi debería considerar ofrecer créditos de búsqueda por el tiempo en que no se pudo usar el servicio.
Más aún considerando que ellos mismos reconocieron que faltó respuesta en tiempo real.
Una caída en un servicio de pago no es lo mismo que una caída en un servicio donde “el usuario es el producto”.
Muestra mucho sobre el nivel de observabilidad que tienen en sus sistemas internos.
Es fácil decir que debieron haberlo detectado antes, pero con dashboards adecuados en Datadog y consultas de Splunk, habría quedado claro mucho más rápido.
Espero que tomen esto como una oportunidad de aprendizaje e inviertan en mejor monitoreo.
Esto fue 100% una experiencia de aprendizaje, pero puedo dar un poco más de contexto sobre la observabilidad.
Kagi es un equipo pequeño, y en la práctica hay 3 personas capaces de responder a eventos como este, distribuidas en 3 zonas horarias. Para mí y para el desarrollador principal, este es el primer tramo de nuestra carrera web; no somos veteranos de Silicon Valley que ya hayan pasado por todo esto.
Es evidente que hay mucho por aprender, pero, habiendo construido Kagi desde cero, me enorgullece lo que hemos avanzado y hacia dónde vamos.
Empezamos a tomarnos la observabilidad más en serio desde hace unos 6 meses. Ahora tenemos muchos dashboards y alertas que entran directo al canal de chat de la empresa y llaman a la gente relevante.
Como principal responsable de la DB, Query Insights de GCP es de gran ayuda. Durante la caída, el monitoreo sí alertó y Query Insights también mostró la consulta “culpable”, pero aun con todo el monitoreo del mundo, puede faltarte la experiencia para interpretar la causa raíz o la mitigación más eficiente.
En otras palabras, todavía nos falta la sabiduría para no dejarnos hacer gaslighting por lo que nos muestran nuestros propios sistemas si no tenemos cuidado. En retrospectiva, puedo decir que GCP Query Insights estaba 100% en lo correcto y que no era un bug en el espacio de la aplicación.
Gracias al crecimiento, ahora podemos ampliar bastante el equipo; ya antes hemos recibido consultoría SRE y seguiremos buscando más apoyo, de tiempo completo o parcial, para continuar mejorando.
¿Un solo usuario corriendo un scraper pudo tirar el servicio durante 7 horas? Sé que desde afuera es fácil decir “debieron preverlo”, pero me parece raro que durante las pruebas nadie preguntara: “¿qué pasa si se generan muchísimas búsquedas?”.
https://news.ycombinator.com/item?id=39019936
En resumen, somos un equipo joven, con muy pocas personas clave, y todos usamos varios sombreros a la vez. Todavía no tenemos un equipo SRE dedicado.
Sobre “¿qué pasa si se generan muchísimas búsquedas?”, si miras https://kagi.com/stats, ya hay “muchas búsquedas” ocurriendo, y nos acercamos a 400 mil por día. En el día a día, el sistema opera con suficiente capacidad de sobra y también tenemos algunas medidas de autoescalado.
El problema estuvo en los detalles de cómo algunos usuarios explotaron un caso patológico. Por nuestra falta de experiencia, no sabíamos qué tráfico natural o patológico debíamos anticipar y simular de antemano.
Simular carga con 20 mil usuarios buscando simultáneamente suena como un experimento razonable para hacer al inicio, y de hecho hicimos algo parecido. Pero, viendo esta caída, aun así eso no habría detectado este problema.
Hasta ahora, unas 10 personas han corrido escáneres de seguridad contra el servicio en producción, y el tráfico generado en esos casos fue mayor que el de esta caída.
Equilibrar este tipo de desarrollo mientras también hay que crear funcionalidades es muy difícil, y claramente debimos hacer más. Como dije en otro comentario, en el corto plazo buscamos ampliar el equipo para no estar tan dispersos en estos esfuerzos.
En retrospectiva se pueden decir muchas cosas, pero espero haber transmitido con más transparencia cómo llegamos hasta aquí.
Más aún si fue la primera vez que alguien los golpeó de esa manera.
Como comparación, los sistemas que manejo no son de escala FAANG, pero en tasa de solicitudes definitivamente son más grandes que Kagi. Kagi aprenderá rápido, y si mientras tanto surgen más problemas como este, incluso me parece hasta cierto punto aceptable. También es una señal de que se están moviendo en la dirección correcta.
Como usuario de pago de Kagi, después de sufrir el downtime me di cuenta de cuánto daba por sentada la confiabilidad de Google.
En los últimos 20 años, Google casi nunca se me cayó, salvo una vez. Perder acceso a un motor de búsqueda es bastante crítico.
Me gusta mucho Kagi y pago por él, pero haber tenido downtime en mi segundo mes de uso fue bastante incómodo. Me gustan los post mortems, pero preferiría no tener que leerlos.
Aun así, espero que esta experiencia haga que Kagi se vuelva un servicio más resiliente y confiable.
Un motor de búsqueda no es un servicio con efecto de bloqueo como un proveedor de email o un ISP.
Definitivamente dependía de que Kagi fuera rápido y funcionara bien en todos lados.
Me recuerda a cuando estábamos ejecutando una prueba de concepto de una nueva herramienta de networking en un cliente. Unos 2 minutos después de iniciarla, toda la red del cliente se cayó.
Estábamos en una zona de sandbox aislada, así que no había forma de que nuestro producto causara una caída de toda la red, pero en mi cabeza pensaba: “no puede ser eso, ¿verdad… verdad?!?!”.
“Más tarde logramos comunicarnos con la cuenta que habíamos bloqueado, y afirmó que usaba la cuenta para hacer scraping automatizado de nuestros resultados, algo que no está permitido por los términos de uso.”
Hay que aplicar límites de QPS a todas las solicitudes RPC/API/HTTP de entrada posibles, especialmente a las públicas
Teníamos una función de búsqueda con autocompletado, y para admitir a usuarios que escribían rápido, habíamos eliminado deliberadamente el límite de velocidad de ese endpoint
Un día, alrededor de las 6 a. m., alguien de Tennessee llegó a trabajar y dejó su cartera sobre el teclado; la cartera mantuvo presionada una tecla y empezó a pegarle a la API con cada pulsación
Como era de esperarse, tras unos 15 minutos la BD se volvió muy inestable, y la latencia de la BD creció tanto que un servidor web se cayó. Siguieron fallas en cadena y todo el clúster de producción terminó caído
Ni hace falta decir que ese día se volvió a agregar el límite de velocidad