Könnten Sie Ihre aktuelle Einkommensstufe nennen?
Golang
Erzählen Sie uns von der schwierigsten und interessantesten Aufgabe, die Sie gelöst haben, insbesondere im architektonischen Bereich.
Lebst du momentan in Moskau? Welche Stadt erwägst du? Betrachtest du ein hybrides Arbeitsmodell? In welcher Phase der Suche befindest du dich?
Haben Sie andere laufende Vorstellungsgespräche?
Wie werden diese Metrikdaten in Grafana integriert und angezeigt?
Wie war die Zusammensetzung des Teams, mit dem Sie zuletzt gearbeitet haben?
Entwurf eines skalierbaren Messaging-Systems, das 150 Millionen Nutzer, 75 Millionen DAU, 225 Millionen MAU, 1,2 Mio. Lese- / 300k Schreib-QPS, 5 Millionen gleichzeitige Nutzer, 60 PB neue Daten pro Jahr, jährliches Wachstum von 30 %, P99 <200 ms für Lesen, <300 ms für Schreiben, SLA 99,95 % unterstützt. KONTEXT Es ist erforderlich, ein verteiltes Messaging-System zu entwerfen, ähnlich wie WhatsApp, das 1:1- und Gruppen-Chats unterstützt, die Zustellung von Nachrichten gewährleistet, Online-Status der Nutzer anzeigt und Multimedia-Dateien (Fotos, Videos, Audio) überträgt. Das System muss hohe Verfügbarkeit und niedrige Latenz gewährleisten, hohen Parallelismus unterstützen und global skalieren. FUNKTIONALE ANFORDERUNGEN - Unterstützung für persönliche (1:1) und Gruppen-Chats mit der Möglichkeit, Teilnehmer hinzuzufügen/zu entfernen - Versand und Empfang von Textnachrichten und Multimedia-Dateien Nicht-funktionale Anforderungen: - Es gibt keine explizite Implementierung von End-to-End-Verschlüsselung auf Service- oder Client-Ebene, außer einer allgemeinen Anmerkung. - Es gibt keine klare Beschreibung von Sharding und Replikation der Datenbanken nach chat_id oder user_id für Skalierbarkeit und Fehlertoleranz. - Es gibt keine explizite Komponente oder Mechanismus zur Offline-Synchronisation von Nachrichten und Delivery-Receipts. - Es ist nicht ersichtlich, wie die Lastverteilung zwischen Datenbanken und Diensten, insbesondere bei Spitzenbelastungen, umgesetzt wird. **Kritische Punkte, auf die geachtet werden sollte:** (Diagramm zeigt eine Architektur mit Load Balancer, API Gateway, Message Queue, Service, Cache, Database, Object Storage und CDN)
Hast du ein aktives GitHub oder LinkedIn?
Erzählen Sie kurz, was Sie bei Ihren vorherigen Arbeitsstellen gemacht haben und welche Funktionen Sie umgesetzt haben.
/* Es gibt zwei PostgreSQL-Server: * PROD - OLTP-Server, * STATS - Server für lange analytische Abfragen. Auf dem aktuellen Server in der Datenbank prod gibt es eine große Tabelle (10Tb) mit folgendem Aufbau: CREATE TABLE profiles( id SERIAL, data JSONB ) In der Tabelle können "Lücken" sein, d.h. einige `id` können fehlen. Es ist notwendig, ein Programm zu schreiben, um die Tabelle profiles von PROD nach STATS zu kopieren. Es wird angenommen, dass die folgenden Schnittstellen für die Arbeit mit Datenbanken verwendet werden: type Row []interface{} type Database interface { // die Implementierung des Database-Interfaces kann Verbindungen neu herstellen // der Aufruf von SaveRows ist 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 // Wenn full=false, Datenübertragung ab der Stelle des vorherigen Fehlers fortsetzen // Wenn full=true, alle Daten übertragen func CopyTable(fromName string, toName string, full bool) error { // ... dein Code } Wenn die Option `full=false` übergeben wird, soll das Programm die Datenübertragung ab der Stelle des vorherigen Fehlers fortsetzen. Wenn `full=true`, sollen alle Daten übertragen werden. **Basisebene**: - sequenzielle Datenübertragung in einem einzigen Thread - Fehlerbehebung (Option `full=false`) Zusätzliche Informationen: - falls notwendig, kann die Schnittstelle erweitert werden, indem eigene Methoden hinzugefügt werden - falls notwendig, kann direkt das Paket **database/sql** verwendet werden
Entwurf eines skalierbaren Messaging-Systems, das 150 Millionen Nutzer, 75 Millionen DAU, 225 Millionen MAU, 1,2 Mio. Lese- / 300k Schreib-Peak-QPS, 5 Millionen gleichzeitige Nutzer, 60 PB neue Daten pro Jahr, 30% jährliches Wachstum, SLA 99,95%, p99 <200 ms für Lesen, <300 ms für Schreiben unterstützt. KONTEXT Es ist erforderlich, ein verteiltes Messaging-System zu entwerfen, ähnlich wie WhatsApp, das 1:1- und Gruppen-Chats unterstützt, die Zustellung von Nachrichten gewährleistet, Online-Status der Nutzer anzeigt und die Übertragung von Multimedia-Dateien (Fotos, Videos, Audio) ermöglicht. Das System muss hohe Verfügbarkeit und niedrige Latenz bieten, hohen Parallelismus unterstützen und global skalieren. FUNKTIONALE ANFORDERUNGEN - Unterstützung für persönliche (1:1) und Gruppen-Chats mit der Möglichkeit, Teilnehmer hinzuzufügen/zu entfernen - Versand und Empfang von Textnachrichten und Multimedia-Dateien Es ist keine klare Implementierung eines End-to-End-Verschlüsselungsmechanismus auf Service- oder Client-Ebene sichtbar, abgesehen von einer allgemeinen Anmerkung. - Es fehlt eine explizite Beschreibung von Sharding und Replikation der Datenbanken nach chat_id oder user_id für Skalierbarkeit und Fehlertoleranz. - Es gibt keinen klaren Komponenten- oder Mechanismus für die Offline-Synchronisierung von Nachrichten und Delivery-Receipts. - Es ist unklar, wie die Lastverteilung zwischen Datenbanken und Diensten, insbesondere bei Spitzenbelastungen, erfolgt. **Kritische Punkte, die beachtet werden sollten:**
Wie sind die Tests im Team aufgebaut — wer schreibt was, welche Abdeckung, gibt es E2E?
/* Wir müssen Daten von einer Quelle zu einem Verbraucher übertragen. Die Quelle liefert die Daten in kleinen Chargen (~zehn Einträge), während der Verbraucher besser mit größeren Chargen (~tausend Einträge) arbeitet. Ein echtes Beispiel ist die Übertragung von Daten aus Kafka-Queues in eine Clickhouse-Datenbank. Quelle: - Praktisch unendlich. - Die Quelle gibt nie mehr als MaxItems Datensätze bei einem Aufruf von Next zurück. - Innerhalb einer "Sitzung" (einem Aufruf der Funktion Pipe) liefert die Quelle bei jedem Aufruf von Next neue Daten. - Nach einem Neustart beginnt die Quelle jedoch an der vorherigen "bestätigten" Position, die durch cookie bestimmt wird. Daher muss jeder Wert von cookie, der von Next zurückgegeben wird, nach dem Speichern der Daten im Empfänger mit Commit bestätigt werden, und zwar in genau der Reihenfolge, in der sie von Next zurückgegeben wurden. Empfänger: - Kann nicht mehr als MaxItems auf einmal verarbeiten. Basisebene: Es ist erforderlich, die Funktion func Pipe(p Producer, c Consumer) error zu implementieren, die Daten aus der Quelle liest, sie in einen Puffer gruppiert, der nicht größer als MaxItems ist, und sie im Empfänger speichert, und anschließend den Fortschritt in der Quelle bestätigt. Schwierigkeit: Die Methoden Next, Process und Commit sind mit Netzwerkaufrufen verbunden und können ziemlich lange dauern. Um den Prozess zu beschleunigen, müssen die Prozesse Lesen, Schreiben und Fortschrittsbestätigung parallelisiert werden. Damit während Process oder Commit das Lesen aus der Quelle und die Bildung des neuen Puffers fortgesetzt werden. */ const MaxItems = 9999 type Producer interface { // Next gibt zurück: // - einen Batch von Items zur Verarbeitung // - eine cookie, die bestätigt werden muss, wenn die Verarbeitung abgeschlossen ist // - einen Fehler Next() (items []any, cookie int, err error) // Commit wird verwendet, um einen Datenbatch als verarbeitet zu markieren Commit(cookie int) error } type Consumer interface { Process(items []any) error } func Pipe(p Producer, c Consumer) error { // TODO }
Wie kann die Effizienz der Elementsuche in einer Datenstruktur Map verbessert werden?
Gegeben ist eine Zeichenkette. Finden Sie die Anzahl der Indexpaare i und j (i <= j), zwischen denen, einschließlich, keine wiederholten Zeichen sind. Für die Zeichenkette "aba" ist die Antwort 5: [0, 0] ("a") [0, 1] ("ab") [1, 1] ("b") [1, 2] ("ba") [2, 2] ("a") Für die Zeichenkette "abcb" ist die Antwort ?: aba 3 + 2 = 5 abcb 4 (a, b, c, d) + 1 (ab) + 1 (bc) + 1 (cb) + 1 (abc) = 8
/* eine Zeichenkette wird gegeben. Finde die Anzahl der Indexpaare i und j (i <= j), zwischen denen keine wiederholten Zeichen sind. Für die Zeichenkette "aba" ist die Antwort 5: können nicht nur ASCII sein [0, 0] ("a") [0, 1] ("ab") [1, 1] ("b") [1, 2] ("ba") [2, 2] ("a") */
Was ist das Problem mit der aktuellen Implementierung der Map-Aktualisierung im Worker (tasksRes[t.id][task{...}])?
Erklären Sie das Prinzip der Dependency Inversion und warum der direkte Aufruf von Repository-Methoden aus einem Use Case gegen SOLID verstößt.
/* Es gibt eine Anwendung mit einer Microservice-Architektur. Ein Microservice kann durch eine Backend-Schnittstelle abstrahiert werden. Um auf eine Instanz des Microservice zuzugreifen, kann der Typ BackendImpl verwendet werden, der bereits implementiert ist. Jeder Microservice hat mehrere Dutzend laufende Instanzen, die jeweils unter ihrer eigenen Adresse addr erreichbar sind. Allerdings sind einzelne Instanzen des Microservice nicht zuverlässig: sie können abstürzen, nicht erreichbar sein oder überlastet sein. Daher müssen Sie den Typ Balancer implementieren, der ebenfalls die Backend-Schnittstelle implementiert und das Client-seitige Load-Balancing zwischen den Instanzen des Microservice durchführt, wobei jedes Mal die **am wenigsten belastete** Instanz ausgewählt wird. */ type Request interface{} type Response interface{} type Backend interface { Invoke(ctx context.Context, req Request) (Response, error) } var _ Backend = &BackendImpl{} // addr enthält ip:port einer bestimmten Instanz func NewBackend(addr string) *BackendImpl type Balancer struct { // TODO } var _ Backend = &Balancer{} // addrs enthalten die Adressen aller balancierten Instanzen func NewBalancer(addrs []string) *Balancer { // TODO }
Wie funktioniert die WebSocket-Verbindung in der Architektur — wann wird sie hergestellt und wer kommuniziert mit wem?