Eksport do magazynu obiektów
Jeden obiekt JSON na każdy osiągnięty cel, w buckecie, który należy do Ciebie. To droga do każdej hurtowni, która nie jest BigQuery.
1. Lukę, którą to zamyka
Do tej pory z MousePlayera do hurtowni danych prowadziła dokładnie jedna droga, i wiodła do Google. Kto prowadzi Snowflake, Redshift albo ClickHouse, nie miał żadnej - choć wszystkie trzy bez problemu czytają z magazynu obiektów.
Mostek zapisuje więc do magazynu obiektów, zamiast po kolei do każdej hurtowni. Snowflake czyta z S3, Redshift czyta z S3, ClickHouse czyta z S3, a BigQuery z Google Cloud Storage. Jeden eksport dociera do wszystkich.
| Dokąd | Jak jest adresowane |
|---|---|
| Amazon S3 | Signature Version 4, bucket w hoście |
| Cloudflare R2 | Signature Version 4 wobec punktu końcowego Twojego konta |
| Google Cloud Storage | przez API zgodne z S3, z kluczem HMAC |
| MinIO, Wasabi, Backblaze B2 i inne | Signature Version 4 wobec Twojego punktu końcowego |
| Azure Blob Storage | link SAS do kontenera - żadnego podpisywania po naszej stronie |
2. Dlaczego Azure jest wyjątkiem - i dlaczego to lepiej
Azure Blob nie mówi w Signature Version 4; podpisuje przez SharedKey. Moglibyśmy zbudować drugi mechanizm podpisu. Zamiast tego mostek przyjmuje link SAS do kontenera - adres, który tworzysz we własnym koncie magazynu i w którym podpis już się znajduje.
To mniej kodu po naszej stronie i mniej zaufania po Twojej. W ogóle nie widzimy klucza konta: przekazujesz uprawnienie, które sam przyciąłeś - do jednego kontenera, z wybraną przez siebie datą wygaśnięcia, odwoływalne w każdej chwili bez dotykania czegokolwiek innego.
Ta sama powściągliwość opłaca się po stronie S3: nadaj kluczowi prawo zapisu do dokładnie tego jednego prefiksu i niczego więcej. Klucz, który może tylko dopisywać do mouseplayer/goals/, nie odczyta Twoich innych bucketów nawet wtedy, gdy wycieknie.
3. Jeden obiekt na cel, a klucz to data
Magazyn obiektów nie zna dopisywania. Plik dzienny trzeba by za każdym razem zapisywać od nowa w całości, a dwa cele docierające jednocześnie nadpisywałyby się nawzajem. Każdy osiągnięty cel staje się więc własnym obiektem.
Ceną jest wiele małych obiektów; użytecznym czyni to budowa klucza:
prefiks/RRRR/MM/DD/kanal/sesja-cel.json
Hurtownia czyta jeden dzień jako jedną partycję, a douzupełnienie danych to przejście po prefiksie, a nie zapytanie. Kto chce partycjonować po projekcie zamiast po dacie, wstawia identyfikator kanału do prefiksu.
Każdy obiekt to jedna linia JSON
Celowo bez wcięć, żeby cały prefiks dało się czytać jako NDJSON, bez otwierania obiektów po kolei. Znacznik czasu, projekt, sesja, identyfikator klienta, cel, wartość, waluta i odnośnik odtwarzający nagranie.
Brak wartości to null, a nie zero
Cel bez wartości pieniężnej zapisuje null. W hurtowni zero zsumowałoby się do kwoty, której nigdy nie było - różnica między „nie uzgodniono kwoty" a „kwota zero" przeżywa eksport.
4. Jeśli przyjdzie 403, przeczytaj najpierw to
Odrzucone żądanie S3 mówi niemal nic, i nie bez powodu komunikat w naszym dzienniku mówi więcej niż samo S3: region wchodzi do podpisu. Błędny region i błędny klucz dają ten sam 403 - oczywiste podejrzenie, czyli klucz, trafia więc tylko w połowie przypadków.
Trzy rzeczy do sprawdzenia, w tej kolejności:
- Region, dokładnie taki, jaki zgłasza bucket. R2 i Google Cloud Storage przyjmują
autoi go nie sprawdzają; wszystkie pozostałe tak. - Uprawnienie do prefiksu. Klucz do
mouseplayer/nie może zapisywać domouseplayer-goals/- końcowy ukośnik ma znaczenie w ARN zasobu. - Punkt końcowy, przy R2 i magazynach zgodnych z S3. Wklej host bez
https://; i tak go obcinamy, ale dopisana ścieżka to inny bucket.
Identyfikator klucza dostępu leży świadomie otwartym tekstem. Z założenia podróżuje w każdym podpisanym żądaniu, więc szyfrowanie go byłoby wysiłkiem bez ochrony. Klucz tajny jest zaszyfrowany, nigdy więcej nie pokazywany i nigdy nie trafia do wewnętrznej kolejki niosącej zadanie.
Wszystkie wymienione znaki towarowe należą do ich właścicieli. MousePlayer nie pozostaje w żadnych relacjach biznesowych z tymi dostawcami.