Datenverschleierung fĂŒr Leistungstests

ClickHouse-Benutzer wissen, dass der Hauptvorteil in der hohen Geschwindigkeit der Verarbeitung von analytischen Abfragen liegt. Aber wie können wir solche Aussagen machen? Dies sollte durch vertrauenswĂŒrdige Leistungstests unterstĂŒtzt werden. Wir werden heute darĂŒber sprechen.



Wir haben 2013 mit der DurchfĂŒhrung solcher Tests begonnen, lange bevor das Produkt in Open Source verfĂŒgbar wurde. Nach wie vor waren wir am meisten an der Geschwindigkeit des Yandex.Metrica-Datendienstes interessiert. Wir haben bereits seit Januar 2009 Daten in ClickHouse gespeichert. Ein Teil der Daten wurde seit 2012 in die Datenbank geschrieben, und ein Teil wurde aus OLAPServer und Metrage konvertiert - Datenstrukturen, die zuvor in Yandex.Metrica verwendet wurden. Daher haben wir fĂŒr die Tests die erste verfĂŒgbare Teilmenge von 1 Milliarde Seitenaufrufdaten verwendet. Es gab noch keine Abfragen in Metric, und wir haben Abfragen erstellt, die fĂŒr uns selbst am interessantesten sind (alle Arten von Filterung, Aggregation und Sortierung).

ClickHouse wurde im Vergleich zu Ă€hnlichen Systemen wie Vertica und MonetDB getestet. Um ehrlich zu sein, wurde es von einem Mitarbeiter durchgefĂŒhrt, der zuvor kein ClickHouse-Entwickler gewesen war, und bestimmte FĂ€lle im Code wurden erst optimiert, als die Ergebnisse erhalten wurden. Ebenso haben wir einen Datensatz fĂŒr Funktionstests erhalten.

Nachdem ClickHouse 2016 Open Source beigetreten war, gab es weitere Fragen zu den Tests.

Nachteile von Tests mit proprietÀren Daten


Leistungstests:

  1. Sie sind von außen nicht reproduzierbar, da fĂŒr ihren Start geschlossene Daten erforderlich sind, die nicht veröffentlicht werden können. Aus dem gleichen Grund stehen einige Funktionstests externen Benutzern nicht zur VerfĂŒgung.
  2. Nicht entwickeln. Es besteht die Notwendigkeit einer signifikanten Erweiterung ihres Satzes, so dass es möglich ist, Änderungen der Geschwindigkeit einzelner Teile des Systems auf isolierte Weise zu ĂŒberprĂŒfen.
  3. Sie werden nicht ordnungsgemĂ€ĂŸ fĂŒr Poolanforderungen ausgefĂŒhrt. Externe Entwickler können ihren Code nicht auf Leistungsregressionen ĂŒberprĂŒfen.

Sie können diese Probleme lösen - alte Tests wegwerfen und neue basierend auf offenen Daten erstellen. Unter den offenen Daten können Sie Daten zu FlĂŒgen in die USA , Taxifahrten in New York oder vorgefertigte Benchmarks TPC-H, TPC-DS und Star Schema Benchmark verwenden . Die Unannehmlichkeit besteht darin, dass diese Daten weit von Yandex.Metrica-Daten entfernt sind und ich Testanforderungen speichern möchte.

Es ist wichtig, echte Daten zu verwenden.


Sie mĂŒssen die Leistung des Dienstes nur an realen Daten aus der Produktion testen. Schauen wir uns einige Beispiele an.

Beispiel 1

Angenommen, Sie fĂŒllen eine Datenbank mit gleichmĂ€ĂŸig verteilten Pseudozufallszahlen. In diesem Fall funktioniert die Datenkomprimierung nicht. Die Datenkomprimierung ist jedoch eine wichtige Eigenschaft fĂŒr analytische DBMS. Die Auswahl des richtigen Komprimierungsalgorithmus und der richtigen Integration in das System ist eine nicht triviale Aufgabe, bei der es keine richtige Lösung gibt, da die Datenkomprimierung einen Kompromiss zwischen der Komprimierungs- und Dekomprimierungsgeschwindigkeit und dem potenziellen KomprimierungsverhĂ€ltnis erfordert. Systeme, die nicht wissen, wie man Daten komprimiert, verlieren garantiert. Wenn wir jedoch gleichmĂ€ĂŸig verteilte Pseudozufallszahlen fĂŒr Tests verwenden, wird dieser Faktor nicht berĂŒcksichtigt und alle anderen Ergebnisse werden verzerrt.

Schlussfolgerung: Die Testdaten sollten ein realistisches KomprimierungsverhÀltnis aufweisen.

Über die Optimierung von Datenkomprimierungsalgorithmen in ClickHouse habe ich in einem frĂŒheren Beitrag gesprochen .

Beispiel 2

Lassen Sie uns an der Geschwindigkeit der SQL-Abfrage interessiert sein:

SELECT RegionID, uniq(UserID) AS visitors     FROM test.hits     GROUP BY RegionID     ORDER BY visitors DESC     LIMIT 10 

Dies ist eine typische Anfrage fĂŒr Yandex.Metrica. Was ist wichtig fĂŒr seine Geschwindigkeit?

  • Wie wird GROUP BY durchgefĂŒhrt ?
  • Welche Datenstruktur wird zur Berechnung der Aggregatfunktion uniq verwendet?
  • Wie viele verschiedene RegionIDs sind und wie viel RAM jeder Status der Uniq-Funktion benötigt.

Es ist aber auch sehr wichtig, dass die Datenmenge fĂŒr verschiedene Regionen ungleich verteilt ist. (Wahrscheinlich wird es nach einem Potenzgesetz verteilt. Ich habe ein Diagramm in der Log-Log-Skala erstellt, bin mir aber nicht sicher.) Und wenn ja, ist es fĂŒr uns wichtig, dass die ZustĂ€nde des Uniq-Aggregats mit einer kleinen Anzahl von Werten wenig Speicher benötigen. Wenn es viele verschiedene AggregationsschlĂŒssel gibt, wird die Anzahl in Byteeinheiten angegeben. Wie erhalte ich die generierten Daten mit all diesen Eigenschaften? NatĂŒrlich ist es besser, echte Daten zu verwenden.

Viele DBMS implementieren die HyperLogLog-Datenstruktur fĂŒr die ungefĂ€hre Berechnung von COUNT (DISTINCT), aber alle funktionieren relativ schlecht, da diese Datenstruktur eine feste Speichermenge verwendet. Und ClickHouse verfĂŒgt ĂŒber eine Funktion, die je nach GrĂ¶ĂŸe des Sets eine Kombination aus drei verschiedenen Datenstrukturen verwendet .

Schlussfolgerung: Die Testdaten sollten die Eigenschaften der Werteverteilung in den Daten darstellen - KardinalitÀt (Anzahl der Werte in den Spalten) und gegenseitige KardinalitÀt mehrerer verschiedener Spalten.

Beispiel 3

Lassen Sie uns die Leistung nicht des analytischen ClickHouse-DBMS testen, sondern von etwas Einfacherem, beispielsweise Hash-Tabellen. FĂŒr Hash-Tabellen ist die Auswahl der richtigen Hash-Funktion sehr wichtig. FĂŒr std :: unordered_map ist dies etwas weniger wichtig, da es sich um eine kettenbasierte Hash-Tabelle handelt und eine Primzahl als GrĂ¶ĂŸe des Arrays verwendet wird. In der Standardbibliotheksimplementierung in gcc und clang wird eine triviale Hash-Funktion als Standard-Hash-Funktion fĂŒr numerische Typen verwendet. Aber std :: unordered_map ist nicht die beste Wahl, wenn wir maximale Geschwindigkeit erreichen wollen. Bei Verwendung von Hash-Tabellen mit offener Adressierung wird die richtige Auswahl der Hash-Funktion zu einem entscheidenden Faktor, und wir können die triviale Hash-Funktion nicht verwenden.

Es ist einfach, Leistungstests fĂŒr Hash-Tabellen fĂŒr zufĂ€llige Daten zu finden, ohne die verwendeten Hash-Funktionen zu berĂŒcksichtigen. Es ist auch leicht, Hash-Funktionstests zu finden, wobei der Schwerpunkt auf der Rechengeschwindigkeit und einigen QualitĂ€tskriterien liegt, jedoch isoliert von den verwendeten Datenstrukturen. Tatsache ist jedoch, dass Hash-Tabellen und HyperLogLog unterschiedliche QualitĂ€tskriterien fĂŒr Hash-Funktionen erfordern.



Weitere Informationen hierzu finden Sie im Bericht „Wie Hash-Tabellen in ClickHouse angeordnet sind“ . Es ist etwas veraltet, da Schweizer Tische nicht berĂŒcksichtigt werden .

Herausforderung


Wir möchten, dass die Daten fĂŒr Leistungstests fĂŒr die Struktur dieselben wie fĂŒr Yandex.Metrica-Daten sind, fĂŒr die alle fĂŒr Benchmarks wichtigen Eigenschaften gespeichert sind, damit in diesen Daten jedoch keine Spuren von echten Website-Besuchern zurĂŒckbleiben. Das heißt, die Daten sollten anonymisiert und Folgendes gespeichert werden:

  • KompressionsverhĂ€ltnisse
  • KardinalitĂ€t (Anzahl verschiedener Werte),
  • gegenseitige KardinalitĂ€ten mehrerer verschiedener Spalten,
  • Eigenschaften probabilistischer Verteilungen, mit denen Daten modelliert werden können (wenn wir beispielsweise glauben, dass Regionen nach einem Potenzgesetz verteilt sind, sollte der Exponent - der Verteilungsparameter - fĂŒr kĂŒnstliche Daten ungefĂ€hr der gleiche sein wie fĂŒr real).

Und was wird benötigt, damit die Daten ein Ă€hnliches KomprimierungsverhĂ€ltnis haben? Wenn beispielsweise LZ4 verwendet wird, sollten die Teilzeichenfolgen in den BinĂ€rdaten in ungefĂ€hr denselben AbstĂ€nden wiederholt werden und die Wiederholungen sollten ungefĂ€hr dieselbe LĂ€nge haben. FĂŒr ZSTD wird eine Byte-Entropie-Übereinstimmung hinzugefĂŒgt.

Das maximale Ziel: ein Tool fĂŒr externe Personen verfĂŒgbar zu machen, mit dem jeder seinen Datensatz fĂŒr die Veröffentlichung anonymisieren kann. Damit wir die Leistung von Daten anderer Personen debuggen und testen, Ă€hnlich wie Daten aus der Produktion. Und ich möchte, dass es interessant ist, die generierten Daten zu sehen.

Dies ist eine informelle ErklĂ€rung des Problems. Es wĂŒrde jedoch niemand eine formelle ErklĂ€rung abgeben.

Versuche zu lösen


Die Bedeutung dieser Aufgabe sollte fĂŒr uns nicht ĂŒbertrieben werden. TatsĂ€chlich war es nie in den PlĂ€nen und niemand wĂŒrde es tun. Ich gab einfach die Hoffnung nicht auf, dass sich etwas einfallen lassen wĂŒrde, und plötzlich hĂ€tte ich gute Laune und viele Dinge, die auf spĂ€ter verschoben werden könnten.

Explizite probabilistische Modelle


Die erste Idee besteht darin, eine Familie von Wahrscheinlichkeitsverteilungen auszuwĂ€hlen, die sie fĂŒr jede Spalte der Tabelle modelliert. WĂ€hlen Sie dann basierend auf den Statistiken der Daten die Modellanpassungsparameter aus und generieren Sie neue Daten unter Verwendung der ausgewĂ€hlten Verteilung. Sie können einen Pseudozufallszahlengenerator mit einem vordefinierten Startwert verwenden, um ein reproduzierbares Ergebnis zu erhalten.

FĂŒr Textfelder können Sie Markov-Ketten verwenden - ein verstĂ€ndliches Modell, fĂŒr das Sie eine effektive Implementierung durchfĂŒhren können.

Es stimmt, einige Tricks sind erforderlich:

  • Wir wollen die KontinuitĂ€t von Zeitreihen erhalten - was bedeutet, dass fĂŒr einige Datentypen nicht der Wert selbst modelliert werden muss, sondern der Unterschied zwischen den benachbarten.
  • Um die bedingte KardinalitĂ€t von Spalten zu simulieren (z. B. dass es normalerweise nur wenige IP-Adressen pro Besucher-ID gibt), mĂŒssen Sie auch die AbhĂ€ngigkeiten zwischen den Spalten explizit aufschreiben (um beispielsweise eine IP-Adresse zu generieren, wird ein Hash aus der Besucher-ID verwendet, aber auch einige andere pseudozufĂ€llige Daten werden hinzugefĂŒgt).
  • Es ist unklar, wie die AbhĂ€ngigkeit auszudrĂŒcken ist, dass ein Besucher ungefĂ€hr zur gleichen Zeit hĂ€ufig URLs mit ĂŒbereinstimmenden Domains besucht.

All dies wird in Form eines Programms dargestellt, in dem alle Distributionen und AbhĂ€ngigkeiten fest codiert sind - das sogenannte „C ++ - Skript“. Markov-Modelle werden jedoch immer noch aus der Summe der Statistiken berechnet, die mit Rauschen geglĂ€ttet und aufgeraut werden. Ich habe angefangen, dieses Skript zu schreiben, aber aus irgendeinem Grund wurde es plötzlich unertrĂ€glich langweilig, nachdem ich das Modell explizit fĂŒr zehn Spalten geschrieben hatte. Und in der Treffertabelle von Yandex.Metrica gab es 2012 mehr als 100 Spalten.

 EventTime.day(std::discrete_distribution<>({    0, 0, 13, 30, 0, 14, 42, 5, 6, 31, 17, 0, 0, 0, 0, 23, 10, ...})(random)); EventTime.hour(std::discrete_distribution<>({    13, 7, 4, 3, 2, 3, 4, 6, 10, 16, 20, 23, 24, 23, 18, 19, 19, ...})(random)); EventTime.minute(std::uniform_int_distribution<UInt8>(0, 59)(random)); EventTime.second(std::uniform_int_distribution<UInt8>(0, 59)(random)); UInt64 UserID = hash(4, powerLaw(5000, 1.1)); UserID = UserID / 10000000000ULL * 10000000000ULL    + static_cast<time_t>(EventTime) + UserID % 1000000; random_with_seed.seed(powerLaw(5000, 1.1)); auto get_random_with_seed = [&]{ return random_with_seed(); }; 

Diese Herangehensweise an die Aufgabe war ein Fehlschlag. Wenn ich mich fleißiger an sie gewandt hĂ€tte, wĂ€re das Drehbuch sicher geschrieben worden.

Vorteile:

  • ideologische Einfachheit.

Nachteile:

  • die KomplexitĂ€t der Implementierung,
  • Die implementierte Lösung ist nur fĂŒr einen Datentyp geeignet.

Und ich möchte eine allgemeinere Lösung - damit sie nicht nur auf Yandex.Metrica-Daten angewendet werden kann, sondern auch andere Daten verschleiert.

Hier sind jedoch Verbesserungen möglich. Sie können Modelle nicht manuell auswĂ€hlen, sondern einen Katalog von Modellen implementieren und die besten unter ihnen auswĂ€hlen (beste Anpassung + eine Art Regularisierung). Oder Sie können Markov-Modelle fĂŒr alle Arten von Feldern verwenden, nicht nur fĂŒr Text. AbhĂ€ngigkeiten zwischen Daten können auch automatisch verstanden werden. Dazu mĂŒssen Sie die relativen Entropien (relative Informationsmenge) zwischen den Spalten oder einfacher die relativen KardinalitĂ€ten (etwa „wie viele verschiedene A-Werte im Durchschnitt fĂŒr einen festen Wert von B“) fĂŒr jedes Spaltenpaar berechnen. Dadurch wird beispielsweise deutlich, dass URLDomain vollstĂ€ndig von der URL abhĂ€ngig ist und nicht umgekehrt.

Aber ich habe diese Idee auch abgelehnt, weil es zu viele Optionen fĂŒr das gibt, was berĂŒcksichtigt werden muss, und das Schreiben wird lange dauern.

Neuronale Netze


Ich habe bereits gesagt, wie wichtig diese Aufgabe fĂŒr uns ist. Niemand dachte daran, sich in die Umsetzung einzuschleichen. GlĂŒcklicherweise arbeitete Kollege Ivan Puzyrevsky dann als Lehrer an der HSE und entwickelte gleichzeitig den YT-Kern. Er fragte mich, ob ich interessante Aufgaben hĂ€tte, die den Studenten als Diplomthema angeboten werden könnten. Ich bot ihm dieses an und er versicherte mir, dass es geeignet sei. Also gab ich diese Aufgabe einem guten Menschen „von der Straße“ - Sharif Anvardinov (die NDA ist fĂŒr die Arbeit mit Daten unterschrieben).

Er erzĂ€hlte ihm von all seinen Ideen, aber vor allem erklĂ€rte er, dass das Problem auf jede Weise gelöst werden kann. Eine gute Option wĂ€re es, die AnsĂ€tze zu verwenden, die ich ĂŒberhaupt nicht verstehe: Erstellen Sie beispielsweise einen Textdatendump mit LSTM. Es sah ermutigend aus, dank des Artikels Die unvernĂŒnftige Wirksamkeit wiederkehrender neuronaler Netze , der mir dann aufgefallen ist.

Das erste Merkmal der Aufgabe ist, dass Sie strukturierte Daten generieren mĂŒssen, nicht nur Text. Es war nicht offensichtlich, ob ein wiederkehrendes neuronales Netzwerk Daten mit der gewĂŒnschten Struktur erzeugen könnte. Es gibt zwei Möglichkeiten, dies zu lösen. Das erste besteht darin, separate Modelle zur Erzeugung der Struktur und fĂŒr den „FĂŒllstoff“ zu verwenden: Das neuronale Netzwerk sollte nur Werte erzeugen. Diese Option wurde jedoch auf spĂ€ter verschoben, danach jedoch nie mehr. Die zweite Möglichkeit besteht darin, einfach einen TSV-Speicherauszug als Text zu generieren. Die Praxis hat gezeigt, dass im Text ein Teil der Zeilen nicht der Struktur entspricht, diese Zeilen jedoch beim Laden weggeworfen werden können.

Das zweite Merkmal - ein wiederkehrendes neuronales Netzwerk erzeugt eine Folge von Daten, und die AbhÀngigkeiten in den Daten können nur in der Reihenfolge dieser Folge folgen. In unseren Daten ist die Reihenfolge der Spalten möglicherweise in Bezug auf die AbhÀngigkeiten zwischen ihnen umgekehrt. Wir haben mit dieser Funktion nichts gemacht.

Gegen Sommer erschien das erste funktionierende Python-Skript, das Daten generierte. Auf den ersten Blick ist die DatenqualitÀt anstÀndig:



Zwar wurden Schwierigkeiten aufgedeckt:

  1. Die GrĂ¶ĂŸe des Modells betrĂ€gt etwa ein Gigabyte. Und wir haben versucht, ein Modell fĂŒr Daten zu erstellen, deren GrĂ¶ĂŸe in der GrĂ¶ĂŸenordnung von mehreren Gigabyte liegt (fĂŒr den Anfang). Die Tatsache, dass das resultierende Modell so groß ist, wirft Bedenken auf: Plötzlich wird es möglich sein, echte Daten daraus zu erhalten, auf denen es trainiert wurde. Höchstwahrscheinlich nicht. Aber ich verstehe maschinelles Lernen und neuronale Netze nicht und habe den Python-Code von dieser Person nicht gelesen. Wie kann ich also sicher sein? Dann gab es Artikel darĂŒber, wie man neuronale Netze komprimiert, ohne an QualitĂ€t zu verlieren, aber dies blieb ohne Implementierung. Einerseits sieht dies nicht nach einem Problem aus - Sie können die Veröffentlichung des Modells ablehnen und nur die generierten Daten veröffentlichen. Andererseits können im Fall einer Umschulung die erzeugten Daten einen Teil der Quelldaten enthalten.
  2. Auf einem einzelnen Computer mit einer CPU betrĂ€gt die Datengenerierungsrate ungefĂ€hr 100 Zeilen pro Sekunde. Wir hatten die Aufgabe, mindestens eine Milliarde Zeilen zu generieren. Die Berechnung ergab, dass dies vor der Verteidigung des Diploms nicht möglich war. Die Verwendung anderer Hardware ist nicht praktikabel, da ich das Ziel hatte, das Datengenerierungstool fĂŒr eine breite Verwendung verfĂŒgbar zu machen.

Sharif versuchte, die DatenqualitĂ€t durch Vergleichen von Statistiken zu untersuchen. Zum Beispiel habe ich die HĂ€ufigkeit berechnet, mit der verschiedene Symbole in der Quelle und in den generierten Daten erscheinen. Das Ergebnis war atemberaubend - die hĂ€ufigsten Zeichen sind Ð und Ñ.

Keine Sorge - er hat sein Diplom perfekt verteidigt, danach haben wir diese Arbeit sicher vergessen.

Komprimierte Datenmutation


Angenommen, die Problemstellung wird auf einen Punkt reduziert: Sie mĂŒssen Daten generieren, fĂŒr die die KomprimierungsverhĂ€ltnisse genau den Originaldaten entsprechen, wĂ€hrend die Daten mit genau derselben Geschwindigkeit dekomprimiert werden mĂŒssen. Wie kann man das machen? Bytes komprimierter Daten mĂŒssen direkt bearbeitet werden! Dann Ă€ndert sich die GrĂ¶ĂŸe der komprimierten Daten nicht, aber die Daten selbst Ă€ndern sich. Ja, und alles wird schnell funktionieren. Als diese Idee auftauchte, wollte ich sie sofort umsetzen, obwohl sie ein anderes Problem als das ursprĂŒngliche löst. Es passiert immer.

Wie bearbeite ich eine komprimierte Datei direkt? Angenommen, wir interessieren uns nur fĂŒr LZ4. Mit LZ4 komprimierte Daten bestehen aus zwei Arten von Anweisungen:

  1. Literale: Kopieren Sie die nÀchsten N Bytes unverÀndert.
  2. Übereinstimmung (Übereinstimmung, die minimale WiederholungslĂ€nge betrĂ€gt 4): Wiederholen Sie N Bytes, die sich in der Datei in einem Abstand von M befanden.

Ausgangsdaten:
Hello world Hello .

Komprimierte Daten (bedingt):
literals 12 "Hello world " match 5 12 .

Lassen Sie in der komprimierten Datei die Übereinstimmung unverĂ€ndert, und in Literalen Ă€ndern wir die Bytewerte. Als Ergebnis erhalten wir nach der Dekomprimierung eine Datei, in der alle sich wiederholenden Sequenzen mit mindestens 4 LĂ€ngen ebenfalls wiederholt und in denselben AbstĂ€nden wiederholt werden, aber gleichzeitig aus einem anderen Satz von Bytes bestehen (bildlich gesprochen wurde kein einziges Byte aus der Originaldatei in der modifizierten Datei entnommen )

Aber wie kann man Bytes Ă€ndern? Dies ist nicht offensichtlich, da Daten neben Spaltentypen auch eine eigene interne implizite Struktur haben, die wir beibehalten möchten. Beispielsweise wird Text hĂ€ufig in UTF-8-Codierung gespeichert - und wir möchten auch in den generierten Daten gĂŒltiges UTF-8. Ich habe eine einfache Heuristik erstellt, um mehrere Bedingungen zu erfĂŒllen:

  • Null-Bytes und ASCII-Steuerzeichen wurden unverĂ€ndert gespeichert.
  • einige Interpunktion blieb bestehen,
  • ASCII wurde in ASCII ĂŒbersetzt, und im Übrigen wurde das höchstwertige Bit gespeichert (oder Sie können explizit ein if-Set fĂŒr verschiedene UTF-8-LĂ€ngen schreiben). Unter einer Klasse von Bytes wird ein neuer Wert gleichmĂ€ĂŸig zufĂ€llig ausgewĂ€hlt;
  • und auch um Fragmente von https:// und Ă€hnlichem zu speichern, sonst sieht alles zu albern aus.

Die Besonderheit dieses Ansatzes besteht darin, dass die Anfangsdaten selbst als Modell fĂŒr die Daten dienen, was bedeutet, dass das Modell nicht veröffentlicht werden kann. Damit können Sie die Datenmenge nicht mehr als das Original generieren. Zum Vergleich war es in frĂŒheren AnsĂ€tzen möglich, ein Modell zu erstellen und auf seiner Basis eine unbegrenzte Datenmenge zu generieren.

Beispiel fĂŒr URL:

http://ljc.she/kdoqdqwpgafe/klwlpm&qw=962788775I0E7bs7OXeAyAx
http://ljc.she/kdoqdqwdffhant.am/wcpoyodjit/cbytjgeoocvdtclac
http://ljc.she/kdoqdqwpgafe/klwlpm&qw=962788775I0E7bs7OXe
http://ljc.she/kdoqdqwdffhant.am/wcpoyodjit/cbytjgeoocvdtclac
http://ljc.she/kdoqdqwdbknvj.s/hmqhpsavon.yf#aortxqdvjja
http://ljc.she/kdoqdqw-bknvj.s/hmqhpsavon.yf#aortxqdvjja
http://ljc.she/kdoqdqwpdtu-Unu-Rjanjna-bbcohu_qxht
http://ljc.she/kdoqdqw-bknvj.s/hmqhpsavon.yf#aortxqdvjja
http://ljc.she/kdoqdqwpdtu-Unu-Rjanjna-bbcohu_qxht
http://ljc.she/kdoqdqw-bknvj.s/hmqhpsavon.yf#aortxqdvjja
http://ljc.she/kdoqdqwpdtu-Unu-Rjanjna-bbcohu-702130

Das Ergebnis hat mich gefreut - es war interessant, die Daten zu betrachten. Trotzdem stimmte etwas nicht. Die URLs sind immer noch strukturiert, aber an einigen Stellen war es zu einfach, Yandex oder Avito zu erraten. Es wurde eine Heuristik erstellt, die manchmal einige Bytes an einigen Stellen neu anordnet.

Andere Überlegungen machten sich Sorgen. Beispielsweise können vertrauliche Informationen in einer Spalte vom Typ FixedString in binĂ€rer Form dargestellt werden und bestehen aus irgendeinem Grund aus ASCII-Steuerzeichen und Interpunktion, die ich speichern wollte. Und ich berĂŒcksichtige keine Datentypen.

Ein weiteres Problem: Wenn Daten vom Typ "LĂ€nge, Wert" in einer Spalte gespeichert sind (so werden Spalten vom Typ String gespeichert), wie kann dann sichergestellt werden, dass die LĂ€nge nach der Mutation korrekt bleibt? Als ich versuchte, das Problem zu beheben, wurde die Aufgabe sofort uninteressant.

ZufÀllige Permutationen


Das Problem ist jedoch nicht gelöst. Wir haben mehrere Experimente durchgefĂŒhrt und es wurde nur noch schlimmer. Es bleibt nur nichts zu tun und zufĂ€llige Seiten im Internet zu lesen, da die Stimmung schon verdorben ist. GlĂŒcklicherweise wurde auf einer dieser Seiten der Algorithmus zum Rendern der Todesszene des Protagonisten im Spiel Wolfenstein 3D analysiert .



Schöne Animation - der Bildschirm fĂŒllt sich mit Blut. Der Artikel erklĂ€rt, dass dies tatsĂ€chlich eine pseudozufĂ€llige Permutation ist. ZufĂ€llige Permutation - eine zufĂ€llig ausgewĂ€hlte Eins-zu-Eins-Transformation einer Menge. Das heißt, die Anzeige der gesamten Menge, in der die Ergebnisse fĂŒr verschiedene Argumente nicht wiederholt werden. Mit anderen Worten, dies ist eine Möglichkeit, alle Elemente einer Menge in zufĂ€lliger Reihenfolge zu durchlaufen. Es ist ein solcher Prozess, der im Bild gezeigt wird - wir ĂŒbermalen jedes Pixel, das zufĂ€llig aus allen ausgewĂ€hlt wurde, ohne Wiederholung. Wenn wir bei jedem Schritt nur ein zufĂ€lliges Pixel auswĂ€hlen wĂŒrden, wĂŒrden wir lange brauchen, um das letzte zu ĂŒbermalen.

Das Spiel verwendet einen sehr einfachen Algorithmus fĂŒr die pseudozufĂ€llige Permutation - LFSR (Linear Feedback Shift Register). Wie Pseudozufallszahlengeneratoren können zufĂ€llige Permutationen bzw. deren Familien, die durch den SchlĂŒssel parametrisiert werden, kryptografisch stark sein - genau das benötigen wir, um die Daten zu konvertieren. Obwohl es möglicherweise nicht offensichtliche Details gibt. Beispielsweise kann eine kryptografisch starke VerschlĂŒsselung von N Bytes zu N Bytes mit einem voreingestellten SchlĂŒssel und einem Initialisierungsvektor anscheinend als pseudozufĂ€llige Permutation vieler N-Byte-Zeichenfolgen verwendet werden. In der Tat ist eine solche Transformation eins zu eins und sieht zufĂ€llig aus. Wenn wir jedoch fĂŒr alle unsere Daten dieselbe Transformation verwenden, kann das Ergebnis einer Analyse unterzogen werden, da der gleiche Initialisierungsvektor und die gleichen SchlĂŒsselwerte mehrmals verwendet werden. Dies Ă€hnelt dem Blockcode-VerschlĂŒsselungsmodus des elektronischen Codebuchs .

Wie kann man eine pseudozufĂ€llige Permutation erhalten? Sie können einfache Eins-zu-Eins-Transformationen durchfĂŒhren und daraus eine ziemlich komplexe Funktion zusammenstellen, die zufĂ€llig aussieht. Lassen Sie mich Ihnen ein Beispiel fĂŒr einige meiner bevorzugten Eins-zu-Eins-Transformationen geben:

  • Multiplikation mit einer ungeraden Zahl (z. B. einer großen Primzahl) in der Zweierkomplementarithmetik;
  • xor-shift: x ^= x >> N ,
  • CRC-N, wobei N die Anzahl der Bits des Arguments ist.

So wird beispielsweise aus drei Multiplikationen und zwei Xor-Shift-Operationen der Murmhash- Finalizer zusammengesetzt . Diese Operation ist eine pseudozufĂ€llige Permutation. Aber nur fĂŒr den Fall, ich stelle fest, dass Hash-Funktionen, auch N Bits in N Bits, nicht gegenseitig eindeutig sein mĂŒssen.

Oder hier ist ein weiteres interessantes Beispiel aus der Elementarzahlentheorie von Jeff Preshing.

Wie können wir pseudozufĂ€llige Permutationen fĂŒr unsere Aufgabe verwenden? Sie können damit alle numerischen Felder konvertieren. Dann ist es möglich, alle KardinalitĂ€ten und gegenseitigen KardinalitĂ€ten aller Feldkombinationen beizubehalten. Das heißt, COUNT (DISTINCT) gibt den gleichen Wert wie vor der Konvertierung und mit jedem GROUP BY zurĂŒck.

Es ist anzumerken, dass die Wahrung aller KardinalitĂ€ten der Aussage ĂŒber das Problem der Datenanonymisierung leicht widerspricht. , , , 10 , . 10 — , . , , , — , , . . , , , Google, , - Google. — , , ( ) ( ). , , .

, . , 10, . ?

, size classes ( ). size class , . 0 1 . 2 3 1/2 1/2 . 1024..2047 1024! () . Usw. .

, . , -. , .

, , , .

— , . . . Fabien Sanglard c Hackers News , . Redis — . , .

. — , . , .

  1. :
    arg: xxxxyyyy
    arg_l : xxxx
    arg_r : yyyy
  2. . xor :
    res: yyyyzzzz
    res_l = yyyy = arg_r
    res_r = zzzz = arg_l ^ F( arg_r )

, F 4 , .

: , , — , , !

. , , , . :

  • , , Electronic Codebook mode of operation;
  • ( ) , , .

. , LZ4 , , .


, , , . — . , , , . ( , ). ?

-, : , 256^10 10 , , . -, , .

, . , , . , . , - .

, — , N . N — . , N = 5, «» «». Order-N.

P( | ) = 0.9
P( | ) = 0.05
P( | ) = 0.01
...


. ( vesna.yandex.ru). LSTM, N, , . — , . : , , .

Title:

— . — , . , , — .@Mail.Ru — — - . ) — AUTO.ria.ua

, , . () , — . 0 N, N N − 1).

. , 123456 URL, . . -. . , .

: URL, , -. : https://www.yandex.ru/images/cats/?id=xxxxxx . , URL, , . : http://ftp.google.kz/cgi-bin/index.phtml?item=xxxxxx . - , 8 .

https://www.yandex.ru/ images/c ats/?id=12345
^^^^^^^^

distribution: [aaaa][b][cc][dddd][e][ff][g g ggg][h]...
hash(" images/c ") % total_count: ^

http://ftp.google.kz/c g ...

, . :

 -        | . -    
-  — .:      Lore - dfghf — . -   )  473682  -  
- !   »  -  —      
- !   » , 
-  .  c      @Mail.Ru - 
-     ,  2010 |  . 
- !    : 820 0000 .,    -
-   - DoramaTv.ru -   . -  ..    
-  .  2013 ,       ->  80 .
-  -    (.    , ,  
-   . 5, 69,  W* - ., ,      World of Tanks
- ,     . 2     @Mail.Ru
-      ,  .   

Ergebnis


, - , - . , . clickhouse obfuscator, : (, CSV, JSONEachRow), ( ) ( , ). .

clickhouse-client, Linux. , ClickHouse. , MySQL PostgreSQL , .

clickhouse obfuscator \
--seed "$(head -c16 /dev/urandom | base64)" \
--input-format TSV --output-format TSV \
--structure 'CounterID UInt32, URLDomain String, \
URL String, SearchPhrase String, Title String' \
< table.tsv > result.tsv

clickhouse obfuscator --help

, . , ? , , . , , . , ( --help ) .

, .

clickhouse-datasets.s3.yandex.net/hits/tsv/hits_v1.tsv.xz
clickhouse-datasets.s3.yandex.net/visits/tsv/visits_v1.tsv.xz

ClickHouse. , ClickHouse .

Source: https://habr.com/ru/post/de457354/


All Articles