Cómo combinar dos plataformas en una y no ofender a los usuarios. Yandex.Kew Developers Experience



El año pasado, el servicio TheQuestion se unió a Yandex. En ese momento, ya había un servicio similar de preguntas y respuestas: Yandex.Znatoki. Los conocedores tenían una gran audiencia y muchas preguntas interesantes, pero no había suficientes expertos que pudieran dar respuestas de alta calidad a estas preguntas. La Pregunta, por el contrario, tenía una fuerte comunidad de expertos, pero carecía de preguntas interesantes. El paso lógico era combinar los dos servicios para aprovechar al máximo cada uno de ellos. Pero, ¿cómo hacer esto si cada servicio tiene su propia base tecnológica, contenido y usuarios?

Hoy hablaré sobre cómo nuestro equipo resolvió este problema desde un punto de vista tecnológico. Descubrirá qué opciones de combinación hemos considerado y cuáles al final hemos elegido. Le contaré sobre la "API de intercambio", la migración de la base de datos, los perfiles de agrupación y las pruebas de back-end. Y sin embargo, sobre la noche de la mudanza sin derecho a cometer un error. Verás que no teníamos que aburrirnos.

La tarea de fusionar dos servicios en uno no es nueva, pero esto no lo hace más fácil. La historia conoce muchos ejemplos exitosos (y no tan) de integración, pero, desafortunadamente, no hay una "bala de plata" y una instrucción clara "haga esto y todo saldrá bien". Todo depende en gran medida de los detalles de los servicios que se combinan y del resultado deseado.

En nuestro caso, el objetivo era este: que todo el contenido escrito en cada uno de los sitios estaba disponible en un servicio unificado, y sus autores podían administrarlo.

Entonces, ¿cómo se combinan los dos servicios de preguntas y respuestas, que parecen ser muy similares, pero muy diferentes en esencia? Transferir contenido y usuarios de un servicio a otro es muy similar a mudarse de un departamento antiguo a uno nuevo.

Solo en nuestro caso, el usuario puede vivir simultáneamente en dos apartamentos (Connoisseurs y TheQuestion), y debe transportarlo con cuidado al tercero. Debe mover todos los muebles, plantas, un gato e incluso papel tapiz a un nuevo departamento (es decir, preguntas, respuestas, comentarios, me gusta) y luego invitarlo a mudarse.

¿Como hacer esto? Varias opciones vienen inmediatamente a la mente.

Opción 1. Muy mal.
Simplemente tomemos uno de los servicios, transfiramos todo el contenido a otro (aunque incluso esto ya no es fácil) y cerremos el servicio original.

Esta opción es muy mala desde el punto de vista del usuario del primer servicio. Acabamos de demoler su vieja casa y lo obligamos a mudarse a una nueva. A cualquiera no le gustará esta actitud, y en lugar de moverse, puede simplemente ir al atardecer. Para nosotros, el valor principal es la comunidad de usuarios, por lo que no planeamos ofender a nadie. Y audazmente cambió a otras opciones.

Opción 2. Malo
No cambiemos ninguno de los servicios, en su lugar, inicie uno nuevo e integrado y agregue periódicamente contenido de los otros dos (por ejemplo, una vez al día).

En este caso, no parecemos empeorar al usuario, pero tampoco lo hacemos mejor. Su antiguo departamento permanece sin cambios, pero no tiene sentido mudarse a uno nuevo. Todos los vecinos también viven en una casa antigua, una flor recién comprada será transportada a un nuevo departamento solo después de un día. Tal servicio unificado no tiene posibilidades de convertirse en un nuevo hogar.

Opción 3. Bueno, pero complejo
No cerremos ninguno de los servicios, duplicaremos instantáneamente contenido y perfiles en el servicio integrado, y las personas se moverán con el tiempo.

Todos los vecinos del usuario (e incluso el gato) viven simultáneamente en la casa vieja y en la nueva. Una flor que acaba de comprar aparece instantáneamente en un apartamento nuevo. ¡Exactamente lo que se necesita! Esta opción es la más cómoda desde el punto de vista del usuario. Por lo tanto, lo elegimos.

Empieza a moverte


Lo que finalmente hicimos se puede describir en varias oraciones. Repetimos completamente todo el back-end de TheQuestion API basado en el backend de Connoisseurs, obteniendo así un solo backend que puede funcionar con dos (e incluso tres) sitios a la vez. Al mismo tiempo, la interfaz de TheQuestion se mantuvo casi sin cambios, lo que significa que desde el punto de vista de los usuarios, el sitio en sí prácticamente no ha cambiado. Este proyecto ha recibido el nombre interno "API de intercambio". Pero lo primero es lo primero.

Lo que teníamos en la entrada: dos sitios completamente independientes. Los entendidos viven en las nubes internas de Yandex. El backend de Connoisseurs está escrito en Python. TheQuestion vive en las nubes de Microsoft Azure, el backend TheQuestion está escrito en Go. Los servicios tienen un esquema de almacenamiento de datos completamente diferente en las bases de datos. Además, TheQuestion tiene dos aplicaciones móviles (para Android e iOS), que también debían ser compatibles. En general, el enemigo no quiere unir tal zoológico.



Etapa 0. Conduzca a la nube Yandex


Estrictamente hablando, este paso no es necesario para la "API del complemento", pero simplifica significativamente los siguientes pasos. En esta etapa, abandonamos por completo las instalaciones y el almacenamiento externo. La pregunta comenzó a usar servidores DNS de Yandex. Los servicios de rentme se trasladaron a Yandex.Cloud. La base de datos se transfirió a las bases de datos administradas de Yandex. Durante el movimiento, también pudimos encontrar y corregir varios errores en TheQuestion, por ejemplo, conexiones no cerradas a Redis en el código de 2015. Como beneficio adicional, también recibimos poder adicional para TheQuestion.

Etapa 1. Migración de datos


Independientemente de la opción que desee combinar servicios, tendríamos que combinar los datos en cualquier caso. Para una única base de datos, decidieron tomar PostgreSQL: este DBMS ya se ha utilizado tanto en Expertos como en TheQuestion. Para no volver a complicar el proyecto, no comenzaron a crear una tercera base para el servicio integrado, sino que simplemente tomaron la base de datos Znatokov y la expandieron para que pudiera aceptar todos los datos de TheQuestion. Este fue el primer gran desafío tecnológico.

Cada entrada en cada tabla de la base de datos TheQuestion tuvo que convertirse y colocarse en la Base de datos de expertos. Luego, correlacione cada columna de una y otra base. Muchos campos tuvieron que ser convertidos no trivialmente de un formato a otro. Entonces, una gran subtarea separada fue la conversión del formato de almacenamiento de texto (el formato real del almacenamiento de preguntas o respuestas) de QML (TheQuestion) a Markdown (Expertos).

Establecimos un proceso regular (varias veces al día) para transferir nuevos datos de una base de datos a otra, pero al mismo tiempo nos aseguramos de que los datos de TheQuestion no se mostraran en ningún lugar hasta la finalización de la siguiente etapa. Debido a que "varias veces al día" está lejos de ser prometido "instantáneamente", y los datos podrían estar en un estado inconsistente con los mismos datos en TheQuestion, lo que confundiría a los usuarios. Entonces, ¿por qué comenzamos con la migración de datos si el backend aún no estaba listo?

En primer lugar, de esta manera estabilizamos el proceso. En segundo lugar, redujeron la cantidad de datos nuevos que deberán transferirse en el futuro, y esto es importante, ya que todo el contenido importado tuvo que pasar por el marcado de calidad, contenido inapropiado, spam, fraude.



Etapa 2. "API de intercambio"


Entonces, resolvimos el primero de los problemas: aprendimos a tomar contenido de la base de datos de TheQuestion e incluso mostrarlo si lo desea. Ahora era necesario hacer que este contenido ingresara a la base de datos integrada al instante, y no varias veces al día.

Para hacer esto, fue necesario reescribir todo el backend TheQuestion con toda la lógica necesaria. El nombre del proyecto, "API de intercambio", estrictamente hablando, no refleja completamente la esencia. Sería más correcto llamarlo "Intercambio de backend". El hecho es que, además de la implementación directa de todos los "bolígrafos" necesarios para el funcionamiento del front-end de TheQuestion, debían realizarse otras posibilidades. Nos enfrentamos a varias tareas importantes.

AutorizaciónYandex tiene un sistema de autorización de usuario centralizado: Yandex.Passport. Y los entendidos, por supuesto, usaron el pasaporte. Para iniciar sesión, debe tener una cuenta en Yandex. Ese fue el problema. No todos los usuarios de TheQuestion iniciaron sesión en el sitio a través de Yandex (aunque hubo esa oportunidad). Muchos usuarios no tenían un inicio de sesión de Yandex en absoluto y pasaron por las redes sociales (VKontakte, Facebook ...). Naturalmente, teníamos que mantener esta funcionalidad al movernos. Por lo tanto, implementamos la autorización "sin pasaporte".

Búsqueda de sitio.TheQuestion implementó una búsqueda de preguntas, respuestas, usuarios y temas. Para la búsqueda, se utilizó una solución Sphinx de terceros. Obviamente, si estamos hablando de un solo servicio, entonces la búsqueda debería ser la misma, es decir, no puede funcionar en dos sistemas a la vez. Por lo tanto, Sphinx fue abandonado en favor de un motor de búsqueda interno con soporte para la funcionalidad necesaria y la indexación de todo el contenido de TheQuestion.

Envío de páginas en Zen y Turbo . Al momento de unirse, TheQuestion ya utilizaba tecnologías Yandex. Se admitieron páginas turbo, contenido interesante cayó en el feed Zen. Todo esto también tenía que ser soportado en la "API de reemplazo".

Notificaciones en el servicio y aplicaciones, listas de correo.Todo lo relacionado con la notificación a los usuarios: suscripciones, boletines con contenido interesante, comentarios sobre me gusta y comentarios, mucho más. Todo esto tuvo que ser cuidadosamente transferido y no olvidado.

Sistema de administración del sitio . Este párrafo se refiere a todo lo relacionado con la gestión interna del servicio: moderación, análisis, etc.

Sistema de calificación de usuario unificado.Esta tarea no era técnica, sino lógica. Formalmente, no es necesario desarrollar un sistema de calificación unificado para una "API de intercambio", pero este sistema todavía es necesario para el futuro servicio integrado. En ambos sitios, los usuarios fueron calificados por la cantidad y calidad del contenido creado. Los detalles de la calificación no fueron revelados, pero cuanto más a menudo y mejor responda las preguntas, mayor será su calificación. Los principios de calificación fueron los mismos en ambos servicios, pero la fórmula en sí y los factores fueron muy diferentes. Era necesario no solo comparar correcta y honestamente a los usuarios de Znatokov y TheQuestion entre ellos, sino también aprender a considerar una calificación única para aquellos expertos que escribieron en dos servicios a la vez.

Y reescribe todas las API.Nos guste o no, esta tarea fue la más importante y difícil. Muchos procesos en los servicios fueron similares, por lo que los tomamos de los conocedores y no escribimos desde cero. Pero también había muchas cosas nuevas, por ejemplo, líneas rectas de usuarios o borradores de respuestas. Como resultado, reescribimos más de 100 "bolígrafos" en la "API de intercambio" e implementamos más de 50 recursos REST.

Después de implementar toda la funcionalidad descrita anteriormente, fue posible comenzar a movernos. Pero antes hicimos un truco.

Está claro que antes de cambiar y lanzar la "API de intercambio" en producción, tenía que probarse muy bien. En primer lugar, era necesario probarlo funcionalmente, es decir, verificar directamente el rendimiento de todo el sitio en la nueva API. En segundo lugar, es estresante. Queríamos estar 100% seguros de que nuestro diseño no "quedaría" bajo carga. Naturalmente, realizamos regularmente "disparos de carga", lo que demostró que tenemos un buen suministro de rendimiento. Pero en materia de rendimiento del servicio, siempre es mejor jugar de forma segura. Cualquier prueba de carga sintética, incluso la mejor, es de alguna manera diferente de la carga de producción. Por lo tanto, decidimos, antes de cambiar la API, llenar la carga de producción en nuestro stand.

Para hacer esto, en la interfaz de TheQuestion, implementamos la duplicación de todas las solicitudes GET (es decir, solicitudes de datos, no modificaciones) en dos API a la vez: la "Pregunta de la API antigua", que en ese momento era la principal, y la "API de intercambio" secundaria. Al mismo tiempo, el frontend no esperó una respuesta API menor y no manejó los errores, pero de esta manera pudimos probar el backend en usuarios reales.



Etapa 3. Y luego recordamos sobre las aplicaciones


No, por supuesto, los recordamos todo este tiempo, pero enfrentamos un problema. Quienes trabajaron con aplicaciones móviles saben que la molestia con ellas es mucho más que con el sitio. Esto se debe principalmente a la distribución de nuevas versiones.

En primer lugar, debe trabajar con servicios externos de App Store y Google Play y esperar a que las nuevas versiones pasen la verificación (y, a veces, la verificación puede llevar un tiempo considerable). En segundo lugar, incluso si su aplicación ya pasó la prueba y apareció en la tienda, esto no significa que los usuarios realizarán una actualización.

En el caso de la interfaz del sitio, los propios desarrolladores controlan cuándo se lanza una nueva versión, y saben con certeza que después de eso, todos los usuarios recibirán una versión actualizada del sitio. En el caso de las aplicaciones, no existe tal garantía. Para obtener dicha garantía, a menudo utilizan la "actualización forzada" de la aplicación. Pocas personas aman este método y, por supuesto, siempre, si es posible, debe mantener la compatibilidad con la aplicación y el backend. Por lo tanto, tomamos el camino de hacer cambios precisamente en el lado del backend con cambios mínimos en la interfaz de las aplicaciones. Pero, como suele suceder, el plan se enfrenta a una dura realidad.

Algunos cambios fueron mucho más fáciles de hacer en el extremo frontal que en el extremo posterior, por lo tanto, en el proceso de desarrollo de una "API de complemento", el extremo frontal fue ligeramente, pero cambió. En particular, la antigua base de datos TheQuestion utilizaba identificadores numéricos de 64 bits. La base de datos de Connoisseurs y, en consecuencia, la base de datos combinada y la nueva API para TheQuestion utilizan ID de cadena de 128 bits. En general, para una interfaz escrita en Node.js, esta diferencia no es significativa. Pero para aplicaciones fuertemente tipadas, esto resultó ser fatal. Perdimos la compatibilidad con versiones anteriores y las aplicaciones anteriores no podían funcionar con la "API de complementos".

En algún momento, incluso apareció un proyecto llamado "API de complemento para API de complemento", cuya esencia era escribir una pequeña capa entre el nuevo back-end y las aplicaciones que convertirían todos los datos al formato anterior. Sin embargo, abandonamos rápidamente esta idea. Esta capa resultaría ser una "muleta" muy rígida, que en el futuro definitivamente nos traería muchos problemas. Por ejemplo, no puede simplemente tomar y traducir las ID de 128 bits a las de 64 bits. Tendría que traducir con pérdida de información y, en consecuencia, posibles colisiones por ID, o mantener una tabla intermedia con la correspondencia de las ID antiguas y nuevas (para todos los elementos de la base de datos). Tanto eso como otro, no es la mejor solución arquitectónica.

Además de la identificación, hubo una serie de otros cambios que también fueron mucho más fáciles de soportar en el lado frontal y en el lado de la aplicación. Como resultado, decidimos implementar cambios en las aplicaciones y aún usar la actualización forzada. En poco tiempo desarrollamos nuevas versiones de aplicaciones compatibles con la "API de intercambio", porque no hubo tantos cambios desde la parte frontal y no fueron muy serios. Enviado a la App Store y Google Play, moderado con éxito y comenzó a esperar.

Etapa X. ¡Vamos!


Entonces todo el código está escrito. El soporte con la "API de reemplazo" se prueba y se dispara. Las nuevas versiones de la aplicación se han probado en tiendas y están listas para su publicación. Ahora todo esto tenía que implementarse en producción.

Debido al hecho de que copiar datos nuevos de la base de datos anterior a la nueva se realiza de forma asincrónica y lleva un tiempo, no puede cambiar el backend (y la base de datos que se encuentra debajo) en un sitio de trabajo. Esto puede provocar la pérdida o inconsistencia de los datos del usuario. Por lo tanto, elegimos una fecha, advertimos a los usuarios y preparamos una placa "Trabajo técnico en progreso".

Y entonces llegó la hora, o más bien la noche X. El plan de despliegue se veía así:

  1. En el sitio web TheQuestion colgamos un trozo "El trabajo está en progreso".
  2. Transferimos aplicaciones al modo de solo lectura. Los usuarios pueden leer el contenido de la base de datos anterior, pero no pueden crear una nueva.
  3. TheQuestion Readonly. : . , , .
  4. . , .
  5. .
  6. , , API.
  7. API . — , API .
  8. , , .
  9. « », API.
  10. .

Bueno, eso no parece tan aterrador. En realidad, todo salió muy bien. De las sorpresas que encontramos, quizás fue demasiado tiempo para publicar la aplicación en la App Store (la aplicación se verificó por adelantado, solo se trataba de aparecer en la tienda). Al final, tomó varias horas, por lo que toda la operación se retrasó un poco.

Además, en el proceso de cambio, había una característica clave que complicaba todo muchas veces y aumentaba la responsabilidad. El hecho es que el proceso de cambio no se pudo revertir.

Aunque el proceso de copiar y convertir datos de la antigua base de datos TheQuestion a la nueva e integrada se configuró y depuró para nosotros, no hubo un proceso de copia inversa (de la nueva base de datos a la anterior). Esto significa que tan pronto como abrimos el sitio en la "API de intercambio" y ponemos en marcha el tráfico de usuarios, todas las preguntas, respuestas, comentarios y "me gusta" recién creados ya no pueden entrar fácilmente en la antigua base de datos TheQuestion. Si algo sale mal después de abrir, por ejemplo, una sola base de datos no puede hacer frente a la carga, entonces no será posible revertir todo rápidamente.

De hecho, por supuesto, exagero. En cualquier caso, no perderíamos los datos del usuario. Teníamos un plan B y una forma de hacer una copia de seguridad manual de los datos de una nueva base de datos a una antigua. Pero todavía tomaría algún tiempo, y la reversión no habría ocurrido sin dolor para los usuarios.

Afortunadamente, el Plan A funcionó y no hubo que revertir nada.



Etapa final


Entonces, se modificó el backend, se combinó la base de datos, no se olvidaron las aplicaciones móviles. Para los usuarios, nada ha cambiado, porque el sitio Yandex.Ku, que se suponía debía combinar datos de ambos sitios, aún no se había lanzado en ese momento. Y para su lanzamiento necesitábamos resolver un problema más.

Al principio, escribí que teníamos que combinar no solo preguntas y respuestas de dos servicios en uno nuevo, sino también usuarios. Los usuarios deberían haber podido ver no solo su contenido en Kew, sino también administrarlo en Kew. Técnicamente, combinar datos y transferir derechos de gestión no es difícil. Es mucho más difícil asegurarse de que los derechos se transfieran a la persona a quien deben transferirse.

Al pasar de Znatokov a Kew, todo es simple: en ambos casos, se utiliza la misma cuenta Yandex. Pero TheQuestion tiene su propia cuenta, que no puede autorizarse en Kew. Afortunadamente, pensamos en esto de antemano. Mucho antes de las acciones descritas anteriormente, permitimos a los usuarios de TheQuestion vincular sus perfiles de Yandex. Y en el momento de la consolidación física de los servicios, más del 90% de los usuarios activos lo hicieron. Esto nos permitió iniciar sin problemas la migración de contenido y usuarios.

Total


Cuando nos mudamos, queríamos salvar a cada usuario, por lo que fuimos conscientemente a la opción más arriesgada y riesgosa de combinar plataformas. Creamos una base tecnológica unificada, aprendimos a transportar instantáneamente contenido y perfiles. En lugar del cierre inesperado y la reubicación forzada, mantuvieron la funcionalidad de los servicios antiguos, lanzaron uno nuevo y explicaron sus ventajas.



Lanzamos Yandex.Kew el año pasado. Ahora más del 80% de los autores activos de TheQuestion y Znatokov se mudaron voluntariamente a un nuevo hogar.

All Articles