Sobes.tech

Golang

Cum sunt integrate și afișate aceste date metrice în Grafana?

Junior — Middle
221

Aveți alte procese de interviu active?

220

Proiectați o aplicație de mesagerie scalabilă, suportând 150 milioane de utilizatori, cu 75 milioane DAU, 225 milioane MAU, 1.2M citiri / 300k scrieri QPS, 5 milioane de utilizatori simultani, 60 PB de date noi pe an, creștere de 30% pe an, P99 <200 ms pentru citire, <300 ms pentru scriere, SLA 99.95%. CONTEXT Este necesar să proiectați un sistem de mesagerie distribuit, similar cu WhatsApp, care suportă chat-uri 1:1 și de grup, asigură livrarea mesajelor, afișează statusurile online ale utilizatorilor și transmite fișiere multimedia (poze, video, audio). Sistemul trebuie să asigure disponibilitate ridicată și latență scăzută, să suporte paralelism ridicat și să fie scalabil la nivel global. CERINȚE FUNCȚIONALE - Suport pentru chat-uri personale (1:1) și de grup cu posibilitatea de a adăuga/remova participanți - Trimiterea și primirea de mesaje text și fișiere multimedia Cerinte non-funcționale: - Fără implementare explicită a mecanismului de criptare end-to-end la nivel de servicii sau clienți, în afară de o notare generală. - Fără descriere explicită a sharding-ului și replicării bazelor de date pe chat_id sau user_id pentru scalabilitate și toleranță la defecte. - Fără componentă sau mecanism explicit pentru sincronizarea offline a mesajelor și confirmărilor de livrare. - Nu este clar cum se face echilibrarea încărcăturii între baze de date și servicii, mai ales în perioadele de vârf. **Puncte critice de luat în considerare:** (Diagrama arată o arhitectură cu Load Balancer, API Gateway, Message Queue, Service, Cache, Database, Object Storage și CDN)

220

Care a fost componența echipei cu care ai lucrat ultima dată?

Junior — Middle
219

Puteți să menționați nivelul dvs. actual de venit?

Junior — Middle
219

Ce indicator al numărului de operații pe secundă în timpul citirii datelor ați atins sau analizat?

Middle — Middle+
218

/* Trebuie să transferăm date dintr-o sursă către un consumator. Sursa oferă date în loturi mici (~zece înregistrări), în timp ce consumatorul funcționează mai eficient cu loturi mari (~o mie de înregistrări). Un exemplu real este transferul de date din cozi de tip Kafka către o bază de date Clickhouse. Sursa: - Practic nelimitată. - Sursa nu returnează niciodată mai mult de MaxItems înregistrări într-un singur apel Next. - În cadrul unei "sesiuni" (un apel al funcției Pipe), sursa returnează date noi la fiecare apel Next. - Cu toate acestea, după repornire, sursa va începe de la poziția "confirmată" anterioară, indicată de cookie. Prin urmare, *fiecare* valoare de cookie returnată de Next, după salvarea datelor în receptor, trebuie confirmată cu un apel la Commit, în aceeași ordine în care au fost returnate de Next. Receptor: - Nu poate procesa mai mult de MaxItems odată. Nivel de bază: Este necesar să implementați funcția func Pipe(p Producer, c Consumer) error care citește date din sursă, le grupează într-un buffer de dimensiune cel mult MaxItems și le salvează în receptor, după care confirmă progresul în sursă. Dificultate: Metodele Next, Process și Commit sunt legate de apeluri de rețea și pot dura destul de mult. Pentru a accelera procesul, trebuie paralelizate procesele de citire, scriere și confirmare a progresului. Astfel, în timpul procesului Process sau Commit, citirea din sursă și formarea noului buffer continuă. */ const MaxItems = 9999 type Producer interface { // Next returnează: // - un lot de items de procesat // - un cookie pentru confirmare după finalizarea procesării // - o eroare Next() (items []any, cookie int, err error) // Commit este folosit pentru a marca un lot de date ca procesat Commit(cookie int) error } type Consumer interface { Process(items []any) error } func Pipe(p Producer, c Consumer) error { // TODO }

213

Spune pe scurt ce ai făcut la locurile de muncă anterioare și ce funcții ai implementat.

211

Care este experiența dvs. în implementarea și configurarea sistemelor de autentificare și autorizare?

Junior — Middle
210

Se dă o șir de caractere. Găsiți numărul de perechi de indici i și j (i <= j), între care, inclusiv, nu există caractere repetate. Pentru șirul "aba" răspunsul este 5: [0, 0] ("a") [0, 1] ("ab") [1, 1] ("b") [1, 2] ("ba") [2, 2] ("a") Pentru șirul "abcb" răspunsul este ?: aba 3 + 2 = 5 abcb 4 (a, b, c, d) + 1 (ab) + 1 (bc) + 1 (cb) + 1 (abc) = 8

209

/* Există o aplicație cu arhitectură de microservicii. Un microserviciu poate fi abstractizat prin intermediul unei interfețe Backend. Pentru a accesa o instanță a microserviciului, se poate folosi tipul BackendImpl, care este deja implementat. Fiecare microserviciu are câteva zeci de instanțe în execuție, fiecare accesibilă prin adresa sa addr. Cu toate acestea, instanțele individuale ale microserviciului nu sunt fiabile: pot cădea, pot fi inaccesibile sau suprasolicitate. De aceea, trebuie să implementați tipul Balancer, care implementează și interfața Backend și realizează echilibrarea încărcării pe partea client între instanțele microserviciului, alegând de fiecare dată instanța **cel mai puțin încărcată**. */ type Request interface{} type Response interface{} type Backend interface { Invoke(ctx context.Context, req Request) (Response, error) } var _ Backend = &BackendImpl{} // addr conține ip:portul unei instanțe specifice func NewBackend(addr string) *BackendImpl type Balancer struct { // TODO } var _ Backend = &Balancer{} // addrs conțin adresele tuturor instanțelor echilibrate func NewBalancer(addrs []string) *Balancer { // TODO }

209

Cum funcționează conexiunea WebSocket în arhitectură — în ce moment se stabilește și cine comunică cu cine?

209

Ai experiență în gestionarea unei echipe?

208

Proiectarea unui sistem de mesagerie scalabil care suportă 150 milioane de utilizatori, 75 milioane DAU, 225 milioane MAU, 1,2 milioane QPS de citire / 300k de scriere în vârf, 5 milioane de utilizatori simultani, 60 PB de date noi pe an, creștere de 30% anual, SLA 99,95%, p99 <200 ms pentru citire, <300 ms pentru scriere. CONTEXT Este necesar să proiectăm un sistem de mesagerie distribuit, similar cu WhatsApp, care suportă chat-uri 1:1 și de grup, asigură livrarea mesajelor, afișează statusurile online ale utilizatorilor și permite transferul de fișiere multimedia (poze, videoclipuri, audio). Sistemul trebuie să asigure disponibilitate ridicată și latență scăzută, să suporte un paralelism înalt și să scaleze la nivel global. CERINȚE FUNCȚIONALE - Suport pentru chat-uri personale (1:1) și de grup cu posibilitatea de a adăuga/elimina participanți - Trimiterea și primirea de mesaje text și fișiere multimedia Nu se observă o implementare clară a mecanismului de criptare end-to-end la nivel de servicii sau clienți, în afară de o notă generală. - Lipsește o descriere explicită a sharding-ului și replicării bazelor de date după chat_id sau user_id pentru scalabilitate și toleranță la defecte. - Nu există un component sau mecanism clar pentru gestionarea sincronizării offline a mesajelor și a confirmărilor de livrare. - Nu este clar cum se face echilibrarea încărcăturii între baze de date și servicii, mai ales în perioadele de vârf. **Puncte critice de luat în considerare:**

208

/* Se dă o șir de caractere. Găsiți numărul de perechi de indici i și j (i <= j), între care nu există caractere repetate. Pentru șirul "aba", răspunsul este 5: pot fi și non-ASCII [0, 0] ("a") [0, 1] ("ab") [1, 1] ("b") [1, 2] ("ba") [2, 2] ("a") */

207

Cum se poate crește eficiența căutării elementelor într-o structură de date Map?

Junior — Middle
207

/* Există două servere PostgreSQL: * PROD - server OLTP, * STATS - server pentru interogări analitice lungi. Pe serverul curent, în baza de date prod, există un tabel mare (10Tb) cu următoarea structură: CREATE TABLE profiles( id SERIAL, data JSONB ) În tabel pot exista "găuri", adică unele `id` pot fi omise. Este necesar să scrieți un program pentru a copia tabelul profiles de la PROD la STATS. Se presupune că se vor folosi următoarele interfețe pentru lucrul cu bazele de date: type Row []interface{} type Database interface { // implementarea interfeței Database poate restabili conexiunile // apelul SaveRows este idempotent 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 // Dacă full=false, continuă transferul de date de la locul erorii anterioare // Dacă full=true, transferă toate datele func CopyTable(fromName string, toName string, full bool) error { // ... codul tău } Dacă se transmite opțiunea `full=false`, programul trebuie să continue transferul de date de la locul erorii anterioare. Dacă `full=true`, trebuie să transfere toate datele. **Nivel de bază**: - transfer secvențial de date într-un singur flux - recuperare după erori (opțiunea `full=false`) Informații suplimentare: - dacă este necesar, poți extinde interfața adăugând propriile metode - dacă este necesar, poți folosi direct pachetul **database/sql**

207

Cum sunt structurate testele în echipă — cine scrie ce, ce acoperire, există E2E?

206

Vorbește-mi despre ultimul tău proiect — despre ce este și cu ce te ocupi exact?

205
/11