4. Probleme mit RDBMS
Schlechte horizontale Skalierung
Option A) Partitionierung nach Funktion
Option B) Partitionierung nach PK, Hash, etc.
Vertikale Skalierung ist teuer
4
5. Warum NoSQL?
Buzzword! (== Spaß, meistens jedenfalls)
Partitionierungsf¨higkeiten sind wirtschaftlich interessant
a
Skaliert die Abfragezeit mit der Serveranzahl?
Kosten f¨r Redundanz k¨nnen berechnet werden
u
o
memcached, etc. wird uber߬ssig (weniger Administration)
u
¨
NoSQL-Architekturen passen gut zum Cloud-Trend
Apache Hadoop wird (in den USA) sehr gehyped
→ Evaluierung
5
9. Auswahl NoSQL
Sammelbegriff f¨r viele Datenbanken
u
Dokumenten-Datenbank
Graph-Datenbank
Key/Value Datenbank
Objekt-Datenbank
Google’s BigTable, Amazon’s Dynamo
...
9
10. Google’s BigTable
Verteilte Key/Value Datenbank
Basiert auf Google File System
Fehlertolerant
Skalierbar
L¨uft auf ”billiger” Hardware
a
Erlaubt Parallelisierung (MapReduce & Co.)
10
11. Apache Hadoop Stack
Hadoop
Verteiltes Dateisystem (HDFS)
Hive
Abfragen
MapReduce
Implementierung f¨r das HDFS
u
HBase
BigTable-Implementierung
MediaGuardian Innovation Awards: Innovator of the Year
Wikipedia: ”...Hervorgehoben wurde, dass Hadoop so
vielseitige und weitreichende Anwendungen erm¨glicht, dass es
o
sich als Beginn einer neuen Datenrevolution erweisen k¨nne.”
o
11
18. HBase - Datendesign
Zeilen IDs werden Byte-Lexikographisch sortiert
Innerhalb einer Zeile werden Spalten Byte-Lexikographisch
sortiert
Zeilen- und Spaltenabschnitte k¨nnen leicht ”gescannt”
o
werden
Wichtige Eigenschaft, um Indizes zu simulieren bzw. Abfragen
zu erm¨glichen
o
18
19. HBase - Column Families
Column Families werden in unterschiedlichen Dateien
gespeichert
19
20. HBase - Horizontale Skalierung
IDs werden in Regionen aufgeteilt
Regionen werden auf Region Servers gespeichert
Regionen und Region Server werden je nach Auslastung neu
angeordnet
20
22. HBase - Versionierung
Jede ”Zelle” wird mit einem Timestamp gespeichert und
automatisch versioniert
Map<byte[], Map<byte[], Map<byte[], Map<Long, byte[]>>>>
22
23. HBase - Versionierung
Jede ”Zelle” wird mit einem Timestamp gespeichert und
automatisch versioniert
Map<byte[], Map<byte[], Map<byte[], Map<Long, byte[]>>>>
Default: 3 Versionen
Timestamp wird beim Schreiben vom Server gesetzt,
kann aber vom Client uberschrieben werden
¨
23
25. HBase - Getting Started
Standalone Mode
Zur Entwicklung kann HBase im Standalone Modus gestartet
werden
HDFS wird dann nicht verwendet
HBase und ZooKeeper laufen in der selben JVM
Shell
bin/hbase shell
hbase(main):001:0> status
1 servers, 0 dead, 0.0000 average load
25
27. HBase API - Tabellen anlegen
Tabellen m¨ssen explizit angelegt werden
u
Shell
create ’person’, ’cfamily1’
27
28. HBase API - Tabellen anlegen
Tabellen m¨ssen explizit angelegt werden
u
Shell
create ’person’, ’cfamily1’
Java
Configuration c = new Configuration();
HBaseAdmin admin = new HBaseAdmin(c);
HTableDescriptor person = new
HTableDescriptor("person");
person.addFamily(new HColumnDescriptor("cfamily1"));
admin.createTable(person);
28
29. HBase API - Daten speichern
Shell
put ’person’, ’id_1’, ’cfamily1:firstname’, ’John’
put ’person’, ’id_1’, ’cfamily1:lastname’, ’McCarthy’
29
30. HBase API - Daten speichern
Shell
put ’person’, ’id_1’, ’cfamily1:firstname’, ’John’
put ’person’, ’id_1’, ’cfamily1:lastname’, ’McCarthy’
Java
Configuration c = new Configuration();
HTable person = new HTable(c, "person");
Put put = new Put(Bytes.toBytes("id_1"));
put.add(Bytes.toBytes("cfamily1"),
Bytes.toBytes("firstname"),
Bytes.toBytes("John"));
put.add(Bytes.toBytes("cfamily1"),
Bytes.toBytes("lastname"),
Bytes.toBytes("McCarthy"));
person.put(put);
30
32. HBase API - Daten lesen
Java
Configuration c = new Configuration();
HTable person = new HTable(c, "person");
Get get = new Get(Bytes.toBytes("id_1"));
get.addColumn(Bytes.toBytes("cfamily1"),
Bytes.toBytes("firstname"));
get.addColumn(Bytes.toBytes("cfamily1"),
Bytes.toBytes("lastname"));
Result result = person.get(get);
byte[] firstname =
result.getValue(Bytes.toBytes("cfamily1"),
Bytes.toBytes("firstname"));
..
32
33. HBase API - Daten l¨schen
o
Shell
delete ’person’, ’id_1’, ’cfamily1:firstname’
33
34. HBase API - Daten l¨schen
o
Shell
delete ’person’, ’id_1’, ’cfamily1:firstname’
Java
Configuration c = new Configuration();
HTable person = new HTable(c, "person");
Delete delete = new Delete(Bytes.toBytes("id_1"));
delete.setTimestamp(1);
person.delete(delete);
34
35. HBase API - Scanner
Java
Configuration c = new Configuration();
HTable person = new HTable(c, "person");
Scan s = new Scan(
Bytes.toBytes("id_1"),
Bytes.toBytes("id_5"));
s.addFamily(Bytes.toBytes("cfamily1"));
ResultScanner rs = person.getScanner(s);
// while....
Result r = rs.next();
r.getValue(Bytes.toBytes("cfamily1"),
Bytes.toBytes("firstname"));
...
35
37. Web-Anwendungen
Mehrere Threads im Server
API muss (sollte) Thread-safe sein
Synchronisation beim Datenbankzugriff notwendig
Locking, Isolierung, ...
Multi-User Umgebung
Gemeinsame Updates w¨ren w¨nschenswert
a
u
Viele Views auf die selben Daten
Anzahl Reads > Anzahl Writes
Viele, kurzlebige Ausf¨hrungen
u
37
39. Atomare Operationen, Isolierung
Atomare Operationen sind:
Put, Get, Delete, ...
Keine Gruppierung m¨glich!
o
Jeder Aufruf ist direkt ein RPC-call
Client-side Buffer
table.setAutoFlush(false)
Put-Operationen werden im Client gepuffert
Explizit senden mit table.flushCommits()
Implizit basierend auf Heap-Verbrauch
39
40. Atomare Operationen, Isolierung
Batch-Support
List<Row> ops = new LinkedList<Row>();
Put put1 = new Put(Bytes.toBytes("id1");
put1.add(Bytes.toBytes("cf"), Bytes.toBytes("col"),
Bytes.toBytes("abc"));
ops.add(put1);
Put put2 = new Put(Bytes.toBytes("id2");
put2.add(Bytes.toBytes("cf"), Bytes.toBytes("col"),
Bytes.toBytes("def"));
ops.add(put12;
Object[] result = new Object[ops.size()];
table.batch(ops, result);
40
41. Atomare Operationen, Isolierung
Reihenfolge im Batch-Betrieb ist nicht explizit und wird vom
Client optimiert
Daher sollten keine Put- und Delete-Operationen f¨r die
u
selben Rows gemischt werde
Egal wie und wann, andere Clients sehen Zwischenschritte
41
42. Compare and Swap
HBase erlaubt atomare compare-and-swap Operationen
Put update = new Put(Bytes.toBytes("id1"));
update.add(
Bytes.toBytes("cfamily1"),
Bytes.toBytes("firstname"),
Bytes.toBytes("Max"));
boolean wasUpdated = person.checkAndPut(
Bytes.toBytes("id1"),
Bytes.toBytes("cfamily1"),
Bytes.toBytes("version"),
Bytes.toBytes("3"),
update);
Erm¨glicht Optimistic-Locking
o
42
43. Synchronisation uber Locks m¨glich
o
¨
Mehrere Operationen k¨nnen nicht als eine, atomare
o
Operation durchgef¨hrt werden
u
Andere Clients werden immer Zwischenschritte sehen
Wenn Clients sich auf gemeinsame Locks einigen, ist
zumindest eine Synchronisation m¨glich
o
RowLock id1lock =
person.lockRow(Bytes.toBytes("id1"));
...
...
person.unlockRow(id1lock);
43
44. Synchronisation uber Locks m¨glich
o
¨
Probleme
Welche Rows eignen sich als gemeinsamer Lock?
Gefahr von Deadlocks
44
45. Thread-Sicherheit der API
HTable
Das Erstellen einer HTable-Instanz kann mehrere Sekunden
dauern
Instanzen sollten daher immer wiederverwendet werden
45
46. Thread-Sicherheit der API
HTable
Das Erstellen einer HTable-Instanz kann mehrere Sekunden
dauern
Instanzen sollten daher immer wiederverwendet werden
Problem: Instanzen sind nicht Thread-safe
46
47. Thread-Sicherheit der API
HTable
Das Erstellen einer HTable-Instanz kann mehrere Sekunden
dauern
Instanzen sollten daher immer wiederverwendet werden
Problem: Instanzen sind nicht Thread-safe
L¨sung: HTablePool
o
HTablePool pool = new HTablePool(c,
Integer.MAX_VALUE);
HTable table = pool.getTable("person");
...
table.close();
47
48. ”Transaction per View”
RDBMS + Web-Anwendung
F¨r jeden Request wird eine Transaction erstellt
u
RuntimeExceptions f¨hren zu einem Rollback,
u
... sonst Commit
48
49. ”Transaction per View”
RDBMS + Web-Anwendung
F¨r jeden Request wird eine Transaction erstellt
u
RuntimeExceptions f¨hren zu einem Rollback,
u
... sonst Commit
HBase + Web-Anwendung
Jeder Request braucht eigene HTable-Instanzen
49
50. ”Transaction per View”
RDBMS + Web-Anwendung
F¨r jeden Request wird eine Transaction erstellt
u
RuntimeExceptions f¨hren zu einem Rollback,
u
... sonst Commit
HBase + Web-Anwendung
Jeder Request braucht eigene HTable-Instanzen
Problem: Wir wissen vorher nicht, auf welche Tabellen
zugegriffen wird
50
51. ”Transaction per View”
RDBMS + Web-Anwendung
F¨r jeden Request wird eine Transaction erstellt
u
RuntimeExceptions f¨hren zu einem Rollback,
u
... sonst Commit
HBase + Web-Anwendung
Jeder Request braucht eigene HTable-Instanzen
Problem: Wir wissen vorher nicht, auf welche Tabellen
zugegriffen wird
L¨sung: Proxy Objekt + Thread-local HTable-Zuordnung
o
51
52. Row IDs erzeugen
ID Erzeugung ist nicht atomar
GET aktueller Wert
+1
PUT neuer Wert
52
53. Row IDs erzeugen
ID Erzeugung ist nicht atomar
GET aktueller Wert
+1
PUT neuer Wert
Counter
HTable table = new HTable(conf, "IDs");
long counter1 = table.incrementColumnValue(
Bytes.toBytes("person_ids"),
Bytes.toBytes("family"),
Bytes.toBytes("next_id"),
1);
53
57. Secondary Keys und Scanner - St¨dtenamen
a
Java
Configuration c = new Configuration();
HTable person = new HTable(c, "personFK");
Scan s = new Scan(
Bytes.toBytes("FK:Stadt:A"),
Bytes.toBytes("FK:Stadt:L"));
ResultScanner rs = person.getScanner(s);
...
57
58. Secondary Keys und Scanner - Postleitzahlen
Java
Configuration c = new Configuration();
HTable person = new HTable(c, "personFK");
Scan s = new Scan(
Bytes.toBytes("FK:PLZ:50667"),
Bytes.toBytes("FK:PLZ:51150"));
ResultScanner rs = person.getScanner(s);
...
58
59. Secondary Keys und Scanner - Alter?
Configuration c = new Configuration();
HTable person = new HTable(c, "personFK");
Scan s = new Scan(
Bytes.toBytes("FK:Alter:2"),
Bytes.toBytes("FK:Alter:51"));
ResultScanner rs = person.getScanner(s);
...
59
60. Secondary Keys und Scanner - Alter?
Configuration c = new Configuration();
HTable person = new HTable(c, "personFK");
Scan s = new Scan(
Bytes.toBytes("FK:Alter:2"),
Bytes.toBytes("FK:Alter:51"));
ResultScanner rs = person.getScanner(s);
...
Problem: IDs werden Byte-Lexikographisch sortiert
2
3
51
6
7
60
62. Secondary Keys und Scanner - Alter?
Padding
2 → 0002
12 → 0012
42 → 0042
135 → 0135
Probleme
Maximale Zahlenl¨nge muss bekannt sein
a
62
63. Secondary Keys und Scanner - Alter?
Wie w¨re eine andere Zahlendarstellung? (Additionssystem)
a
2→2
12 → 92
42 → 99992
135 → 99999999999995
63
64. Secondary Keys und Scanner - Alter?
Wie w¨re eine andere Zahlendarstellung? (Additionssystem)
a
2→2
12 → 92
42 → 99992
135 → 99999999999995
Probleme
Sehr ineffizient bzgl. Platzbedarf
Zahl ist nicht lesbar
64
65. Secondary Keys und Scanner - Alter?
L¨sung: Additionssystem und Stellenwertsystem kombinieren
o
2 → 1#2
12 → 2#12
42 → 2#42
135 → 3#135
65
66. Fazit 1/6
Entweder man macht es so, wie HBase es will, oder man l¨sst
a
es bleiben!
Bitte keine O/H(Base) Mapper!
66
67. Fazit 2/6
Kostenargumente sind schwer dem Kunden zu verkaufen,
wenn Oracle und Co. schon im Einsatz ist, Lizenzen
vorhanden sind, etc.
67
68. Fazit 3/6
HBase kann sehr gut mehrere Rechner nutzen
Jedoch muss man diese Eigenschaft nutzen, um uberhaupt
¨
erst eine gute Performance zu erhalten
68
72. Wir stellen ein!
Wir suchen professionelle Java-Geeks!
Wir bieten eine gesunde Mischung aus
Programmierer
Berater
Kicker-Profi
Bitte bei mir melden!
roelofsen@weiglewilczek.com
72