Woon je momenteel in Moskou? Welke stad overweeg je? Overweeg je een hybride werkmodel? In welke fase van de zoektocht ben je?
Golang
Heeft u andere actieve sollicitatieprocessen?
Kunt u uw huidige inkomensniveau noemen?
Hoe worden deze metrische gegevens geïntegreerd en weergegeven in Grafana?
Ontwerp een schaalbare berichtenapplicatie die 150 miljoen gebruikers ondersteunt, met 75 miljoen DAU, 225 miljoen MAU, 1.2M lees- / 300k schrijfsnelheid QPS, 5 miljoen gelijktijdige gebruikers, 60 PB nieuwe gegevens per jaar, een jaarlijkse groei van 30%, P99 <200 ms voor lezen, <300 ms voor schrijven, SLA 99.95%. CONTEXT Het is nodig om een gedistribueerd berichten systeem te ontwerpen, vergelijkbaar met WhatsApp, dat 1-op-1 en groepschats ondersteunt, berichten bezorgt, online statussen van gebruikers toont en multimedia bestanden (foto's, video's, audio) verzendt. Het systeem moet hoge beschikbaarheid en lage latency garanderen, hoge paralleliteit aankunnen en wereldwijd schaalbaar zijn. FUNCTIONELE EISEN - Ondersteuning voor persoonlijke (1:1) en groepschats met mogelijkheid tot toevoegen/verwijderen van deelnemers - Verzenden en ontvangen van tekstberichten en multimedia bestanden Niet-functionele eisen: - Geen expliciete implementatie van end-to-end encryptie mechanisme op servicelagen of clients, behalve een algemene annotatie. - Geen expliciete beschrijving van sharding en replicatie van databases op basis van chat_id of user_id voor schaalbaarheid en fouttolerantie. - Geen expliciete component of mechanisme voor offline berichtensynchronisatie en afleveringsbevestigingen. - Het is niet duidelijk hoe load balancing wordt uitgevoerd tussen databases en services, vooral tijdens piekbelastingen. **Kritieke punten om op te letten:** (De diagram toont een architectuur met Load Balancer, API Gateway, Message Queue, Service, Cache, Database, Object Storage en CDN)
Wat was de samenstelling van het team waarmee je voor het laatst hebt gewerkt?
Heb je een actief GitHub of LinkedIn?
Welke indicator van het aantal bewerkingen per seconde bij het lezen van gegevens hebt u bereikt of geanalyseerd?
Vertel kort wat je hebt gedaan bij je vorige banen en welke functies je hebt geïmplementeerd.
/* We moeten gegevens van een bron naar een consument overbrengen. De bron geeft gegevens in kleine batches (~tien records), terwijl de consument efficiënter werkt met grote batches (~duizend records). Een echt voorbeeld is het overzetten van gegevens van Kafka-achtige wachtrijen naar een Clickhouse-database. Bron: - Bijna oneindig. - De bron geeft nooit meer dan MaxItems records terug in één Next-aanroep. - Tijdens één "sessie" (één aanroep van de Pipe-functie) geeft de bron bij elke Next-aanroep nieuwe gegevens. - Na een herstart begint de bron echter vanaf de vorige "bevestigde" positie, aangegeven door cookie. Daarom moet elke cookie-waarde die door Next wordt geretourneerd, na het opslaan van de gegevens in de ontvanger, worden bevestigd met een Commit-aanroep, in dezelfde volgorde als ze door Next werden geretourneerd. Ontvanger: - Kan niet meer dan MaxItems tegelijk verwerken. Basissysteem: Het is nodig om de functie func Pipe(p Producer, c Consumer) error te implementeren die gegevens uit de bron leest, deze groepeert in een buffer van niet groter dan MaxItems en opslaat in de ontvanger, waarna de voortgang in de bron wordt bevestigd. Uitdaging: De methoden Next, Process en Commit zijn verbonden met netwerkoproepen en kunnen vrij lang duren. Om het proces te versnellen, moeten de lees-, schrijf- en bevestigingsprocessen parallel worden uitgevoerd. Zodat tijdens Process of Commit, het lezen uit de bron en het vormen van de nieuwe buffer doorgaan. */ const MaxItems = 9999 type Producer interface { // Next geeft terug: // - een batch van items om te verwerken // - een cookie om te bevestigen wanneer de verwerking is voltooid // - een fout Next() (items []any, cookie int, err error) // Commit wordt gebruikt om een gegevensbatch als verwerkt te markeren Commit(cookie int) error } type Consumer interface { Process(items []any) error } func Pipe(p Producer, c Consumer) error { // TODO }
Hoe zijn de tests in het team georganiseerd — wie schrijft wat, welke dekking, is er E2E?
/* Gegeven is een tekenreeks. Vind het aantal paren indices i en j (i <= j), tussen welke geen herhaalde tekens zijn. Voor de string "aba" is het antwoord 5: mogen niet alleen ASCII zijn [0, 0] ("a") [0, 1] ("ab") [1, 1] ("b") [1, 2] ("ba") [2, 2] ("a") */
Gegeven een tekenreeks. Vind het aantal paren indices i en j (i <= j), tussen welke, inclusief, geen herhaalde tekens zijn. Voor de tekenreeks "aba" is het antwoord 5: [0, 0] ("a") [0, 1] ("ab") [1, 1] ("b") [1, 2] ("ba") [2, 2] ("a") Voor de tekenreeks "abcb" is het antwoord ?: aba 3 + 2 = 5 abcb 4 (a, b, c, d) + 1 (ab) + 1 (bc) + 1 (cb) + 1 (abc) = 8
/* Er bestaat een toepassing met een microservices-architectuur. Een microservice kan worden geabstraheerd met behulp van een Backend-interface. Om toegang te krijgen tot een instantie van de microservice, kan het type BackendImpl worden gebruikt, dat al is geïmplementeerd. Elke microservice heeft tientallen exemplaren die draaien, elk bereikbaar via zijn eigen adres addr. Echter, individuele exemplaren van de microservice zijn niet betrouwbaar: ze kunnen crashen, niet bereikbaar zijn of overbelast zijn. Daarom moet je het type Balancer implementeren, dat ook de Backend-interface implementeert en client-side load balancing uitvoert tussen de microservice-exemplaren, waarbij telkens het **minimaal belaste** exemplaar wordt gekozen. */ type Request interface{} type Response interface{} type Backend interface { Invoke(ctx context.Context, req Request) (Response, error) } var _ Backend = &BackendImpl{} // addr bevat ip:poort van een specifiek exemplaar func NewBackend(addr string) *BackendImpl type Balancer struct { // TODO } var _ Backend = &Balancer{} // addrs bevatten de adressen van alle gebalanceerde exemplaren func NewBalancer(addrs []string) *Balancer { // TODO }
Hoe werkt de WebSocket-verbinding in de architectuur — op welk moment wordt deze tot stand gebracht en wie communiceert met wie?
Ontwerp van een schaalbaar berichtenplatform dat 150 miljoen gebruikers ondersteunt, met 75 miljoen DAU, 225 miljoen MAU, 1,2 miljoen lees- / 300k schrijfsituaties QPS, 5 miljoen gelijktijdige gebruikers, 60 PB nieuwe gegevens per jaar, 30% jaarlijkse groei, SLA 99,95%, p99 <200 ms voor lezen, <300 ms voor schrijven. CONTEXTE Het is nodig om een gedistribueerd berichtenplatform te ontwerpen, vergelijkbaar met WhatsApp, dat 1:1 en groepschats ondersteunt, berichtbezorging garandeert, online statussen van gebruikers toont en multimedia-bestanden (foto's, video's, audio) overdraagt. Het systeem moet hoge beschikbaarheid en lage latentie bieden, hoge paralleliteit ondersteunen en wereldwijd schalen. FUNCTIONELE EISEN - Ondersteuning voor persoonlijke (1:1) en groepschats met de mogelijkheid om deelnemers toe te voegen/verwijderen - Verzenden en ontvangen van tekstberichten en multimedia-bestanden Er lijkt geen duidelijke implementatie van end-to-end encryptie-mechanismen op servicetoe of clientniveau, afgezien van een algemene notitie. - Er ontbreekt een expliciete beschrijving van sharding en replicatie van databases op basis van chat_id of user_id voor schaalbaarheid en fouttolerantie. - Er is geen duidelijke component of mechanisme voor offline synchronisatie van berichten en afleverbevestigingen. - Het is niet duidelijk hoe de load balancing tussen databases en services wordt uitgevoerd, vooral bij piekbelastingen. **Kritieke punten om rekening mee te houden:**
Heb je ervaring met teammanagement?
Hoe kan de efficiëntie van het zoeken van elementen in een Map-gegevensstructuur worden verbeterd?
Heeft u ervaring met gedistribueerde systemen?
/* Er zijn twee PostgreSQL-servers: * PROD - OLTP-server, * STATS - server voor lange analytische queries. Op de huidige server, in de database prod, is er een grote tabel (10Tb) met de volgende structuur: CREATE TABLE profiles( id SERIAL, data JSONB ) In de tabel kunnen "gaten" zijn, dat wil zeggen dat sommige `id` kunnen ontbreken. Het is nodig om een programma te schrijven om de tabel profiles van PROD naar STATS te kopiëren. We gaan ervan uit dat de volgende interfaces worden gebruikt voor het werken met databases: type Row []interface{} type Database interface { // de implementatie van de Database-interface kan verbindingen opnieuw opzetten // de aanroep van SaveRows is 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 // Als full=false, de gegevensoverdracht voortzetten vanaf de plek van de vorige fout // Als full=true, alle gegevens overzetten func CopyTable(fromName string, toName string, full bool) error { // ... jouw code } Als de optie `full=false` wordt doorgegeven, moet het programma de gegevensoverdracht voortzetten vanaf de plek van de vorige fout. Als `full=true`, moet het alle gegevens overzetten. **Basisniveau**: - sequentiële gegevensoverdracht in één stroom - herstel na fouten (optie `full=false`) Aanvullende informatie: - indien nodig, kun je de interface uitbreiden door je eigen methoden toe te voegen - indien nodig, kun je direct het pakket **database/sql** gebruiken