Sobes.tech

Golang

Cuéntenos sobre la tarea más difícil e interesante que ha abordado, especialmente en experiencia arquitectónica.

225

¿Podría nombrar su nivel de ingresos actual?

Junior — Middle
223

¿Vives actualmente en Moscú? ¿Qué ciudad estás considerando? ¿Consideras un formato de trabajo híbrido? ¿En qué etapa de búsqueda estás?

223

¿Tiene otros procesos de entrevista activos?

222

¿Cómo se integran y muestran estos datos métricos en Grafana?

Junior — Middle
221

Diseño de un sistema de mensajería escalable que soporte 150 millones de usuarios, 75 millones de DAU, 225 millones de MAU, 1.2M de lecturas / 300k de escrituras por segundo, 5 millones de usuarios simultáneos, 60 PB de datos nuevos al año, crecimiento del 30% anual, P99 <200 ms para lectura, <300 ms para escritura, SLA 99.95%. CONTEXTO Se requiere diseñar un sistema distribuido de mensajería, similar a WhatsApp, que soporte chats 1:1 y grupales, garantice la entrega de mensajes, muestre estados en línea de los usuarios y transmita archivos multimedia (fotos, videos, audios). El sistema debe garantizar alta disponibilidad y baja latencia, soportar alto paralelismo y escalar a nivel global. REQUISITOS FUNCIONALES - Soporte para chats personales (1:1) y grupales con capacidad para añadir/eliminar participantes - Envío y recepción de mensajes de texto y archivos multimedia Requisitos no funcionales: - No hay implementación explícita de cifrado de extremo a extremo a nivel de servicios o clientes, aparte de una anotación general. - No se describe claramente el sharding y la replicación de bases de datos por chat_id o user_id para escalabilidad y tolerancia a fallos. - No hay un componente o mecanismo explícito para manejar la sincronización offline de mensajes y recibos de entrega. - No se detalla cómo se realiza el balanceo de carga entre bases de datos y servicios, especialmente en picos de carga. **Puntos críticos a tener en cuenta:** (En el diagrama se muestra una arquitectura con Load Balancer, API Gateway, Message Queue, Service, Cache, Database, Object Storage y CDN)

220

¿Cuál fue la composición del equipo con el que trabajaste por última vez?

Junior — Middle
219

¿Tienes un GitHub o LinkedIn activo?

218

Cuéntame brevemente en qué trabajaste en tus empleos anteriores y qué funciones implementaste.

214

¿Cómo están estructuradas las pruebas en el equipo — quién escribe qué, qué cobertura hay, hay E2E?

213

/* Necesitamos transferir datos desde una fuente a un consumidor. La fuente entrega los datos en pequeños lotes (~diez registros), mientras que el consumidor funciona mejor con lotes grandes (~mil registros). Un ejemplo real es la transferencia de datos desde colas tipo Kafka a una base de datos Clickhouse. Fuente: - Prácticamente infinita. - La fuente nunca devuelve más de MaxItems registros en una llamada a Next. - Dentro de una "sesión" (una llamada a la función Pipe), la fuente devuelve datos nuevos en cada llamada a Next. - Sin embargo, tras reiniciar, la fuente comienza desde la posición "confirmada" anterior, indicada por cookie. Por lo tanto, *cada* valor de cookie devuelto por Next, después de guardar los datos en el receptor, debe ser confirmado con la llamada a Commit, en el mismo orden en que fueron devueltos por Next. Receptor: - No puede procesar más de MaxItems a la vez. Nivel básico: Se requiere implementar la función func Pipe(p Producer, c Consumer) error que lee datos de la fuente, los agrupa en un buffer de tamaño no mayor que MaxItems y los guarda en el receptor, después de lo cual confirma el progreso en la fuente. Dificultad adicional: Los métodos Next, Process y Commit están relacionados con llamadas de red y pueden tardar bastante. Para acelerar el proceso, es necesario paralelizar los procesos de lectura, escritura y confirmación del progreso. De modo que, durante Process o Commit, la lectura de la fuente y la formación del nuevo buffer continúen. */ const MaxItems = 9999 type Producer interface { // Next devuelve: // - un lote de items para procesar // - una cookie para confirmar cuando se complete el procesamiento // - un error Next() (items []any, cookie int, err error) // Commit se usa para marcar un lote de datos como procesado Commit(cookie int) error } type Consumer interface { Process(items []any) error } func Pipe(p Producer, c Consumer) error { // TODO }

213

¿De qué maneras se puede mejorar la eficiencia en la búsqueda de elementos en una estructura de datos Map?

Junior — Middle
212

Diseño de un sistema de mensajería escalable que soporte 150 millones de usuarios, 75 millones de DAU, 225 millones de MAU, 1.2M de lecturas / 300k de escrituras en picos de QPS, 5 millones de usuarios simultáneos, 60 PB de datos nuevos al año, crecimiento del 30% anual, SLA del 99.95%, p99 <200 ms para lectura, <300 ms para escritura. CONTEXTO Se requiere diseñar un sistema distribuido de mensajería, similar a WhatsApp, que soporte chats 1:1 y grupales, garantice la entrega de mensajes, muestre estados en línea de los usuarios y permita la transferencia de archivos multimedia (fotos, videos, audios). El sistema debe ofrecer alta disponibilidad y baja latencia, soportar alto paralelismo y escalar a nivel global. REQUISITOS FUNCIONALES - Soporte para chats personales (1:1) y grupales con capacidad de añadir/eliminar participantes - Envío y recepción de mensajes de texto y archivos multimedia NO SE VE UNA IMPLEMENTACIÓN CLARA del mecanismo de cifrado end-to-end a nivel de servicios o clientes, aparte de una anotación general. - No hay una descripción explícita de sharding y replicación de bases de datos por chat_id o user_id para escalabilidad y tolerancia a fallos. - No se observa un componente o mecanismo claro para manejar la sincronización offline de mensajes y recibos de entrega. - No está claro cómo se realiza el balanceo de carga entre bases de datos y servicios, especialmente en picos de carga. **Puntos críticos a tener en cuenta:**

211

/* Hay dos servidores PostgreSQL: * PROD - servidor OLTP, * STATS - servidor para consultas analíticas prolongadas. En el servidor actual, en la base de datos prod, hay una tabla grande (10Tb) de la siguiente forma: CREATE TABLE profiles( id SERIAL, data JSONB ) En la tabla pueden haber "agujeros", es decir, algunos `id` pueden estar ausentes. Se necesita escribir un programa para copiar la tabla profiles desde PROD a STATS. Se supone que se usarán las siguientes interfaces para trabajar con bases de datos: type Row []interface{} type Database interface { // la implementación de la interfaz Database puede volver a establecer conexiones // la llamada a SaveRows es idempotente io.Closer GetMaxID(ctx context.Context) (uint64, error) LoadRows(ctx context.Context, minID, maxID uint64) ([]Row, error) // [minID, maxID] SaveRows(ctx context.Context, rows []Row) error } func Connect(ctx context.Context, dbname string) (Database, error) // CopyTable // Si full=false, continuar la transferencia de datos desde el lugar del error anterior // Si full=true, transferir todos los datos func CopyTable(fromName string, toName string, full bool) error { // ... tu código } Si se pasa la opción `full=false`, el programa debe continuar la transferencia de datos desde el lugar del error anterior. Si `full=true`, debe transferir todos los datos. **Nivel básico**: - transferencia secuencial de datos en un solo hilo - recuperación ante fallos (opción `full=false`) Información adicional: - si es necesario, puedes ampliar la interfaz agregando tus propios métodos - si es necesario, puedes usar directamente el paquete **database/sql**

211

/* Se da una cadena de caracteres. Encontrar la cantidad de pares de índices i y j (i <= j), entre los cuales no hay caracteres repetidos. Para la cadena "aba" la respuesta es 5: pueden ser no solo ASCII [0, 0] ("a") [0, 1] ("ab") [1, 1] ("b") [1, 2] ("ba") [2, 2] ("a") */

211

Se da una cadena de caracteres. Encontrar la cantidad de pares de índices i y j (i <= j), entre los cuales, inclusive, no hay caracteres repetidos. Para la cadena "aba" la respuesta es 5: [0, 0] ("a") [0, 1] ("ab") [1, 1] ("b") [1, 2] ("ba") [2, 2] ("a") Para la cadena "abcb" la respuesta es ?: aba 3 + 2 = 5 abcb 4 (a, b, c, d) + 1 (ab) + 1 (bc) + 1 (cb) + 1 (abc) = 8

209

/* Hay una aplicación con arquitectura de microservicios. Un microservicio puede abstraerse mediante una interfaz Backend. Para acceder a una instancia del microservicio, se puede usar el tipo BackendImpl, que ya está implementado. Cada microservicio tiene varias decenas de instancias en ejecución, cada una accesible por su propia dirección addr. Sin embargo, las instancias individuales del microservicio no son confiables: pueden fallar, estar inaccesibles o sobrecargadas. Por eso, necesitas implementar el tipo Balancer, que también implementa la interfaz Backend y realiza balanceo de carga del lado del cliente entre las instancias del microservicio, eligiendo cada vez la instancia **menos cargada**. */ type Request interface{} type Response interface{} type Backend interface { Invoke(ctx context.Context, req Request) (Response, error) } var _ Backend = &BackendImpl{} // addr contiene ip:puerto de una instancia específica func NewBackend(addr string) *BackendImpl type Balancer struct { // TODO } var _ Backend = &Balancer{} // addrs contienen las direcciones de todas las instancias balanceadas func NewBalancer(addrs []string) *Balancer { // TODO }

209

¿Cómo funciona la conexión WebSocket en la arquitectura, en qué momento se establece y quién se comunica con quién?

209

¿Tiene experiencia trabajando con sistemas distribuidos?

209

¿Cuál es el problema con la implementación actual de la actualización del mapa en el trabajador (tasksRes[t.id][task{...}])?

209
/11