Webanwendungen mit Apache HBase entwickeln
Roman Roelofsen
Managing Director (aka Alpha Geek)
Weigle Wilczek GmbH
Twitter: romanroe

JAX, 19. April 2012

1
¨
WeigleWilczek - Uber Uns

IT-Beratung, Software-Entwicklung
Typische Anwendungen
”Web-Anwendungen”
Lagerverwaltung
Kennzahlenanalyse, Dashboards

Kein Facebook, Twitter, etc.

2
Typischer Stack

JVM
Jetty/Tomcat/WebSphere
Guice/Spring
Diverse Web-Frameworks
Diverse RDBMS (MySQL, PostreSQL, ...)
Ein paar Exoten
MongoDB
Prevayler

3
Probleme mit RDBMS

Schlechte horizontale Skalierung
Option A) Partitionierung nach Funktion
Option B) Partitionierung nach PK, Hash, etc.

Vertikale Skalierung ist teuer

4
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
Warum NoSQL?

6
Warum NoSQL?

7
Warum NoSQL?

8
Auswahl NoSQL

Sammelbegriff f¨r viele Datenbanken
u
Dokumenten-Datenbank
Graph-Datenbank
Key/Value Datenbank
Objekt-Datenbank
Google’s BigTable, Amazon’s Dynamo
...

9
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
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
Exkurs: HBase vs. Cassandra

HBase Vorteile
Konsistenz
Read-Performance > Write-Performance

Cassandra Vorteile
Write-Performance > Read-Performance

Wichtig f¨r Business-Anwendungen
u
Konsistenz
Read-Performance
Abfragen

12
HBase - Datendesign
Key/Value Datenbank
java.util.Map
Row
Map<ROW_ID, DATA>

13
HBase - Datendesign
Key/Value Datenbank
java.util.Map
Row
Map<ROW_ID, DATA>
Column Family
Map<ROW_ID, Map<FAMILY_ID, DATA>>

14
HBase - Datendesign
Key/Value Datenbank
java.util.Map
Row
Map<ROW_ID, DATA>
Column Family
Map<ROW_ID, Map<FAMILY_ID, DATA>>
Column
Map<ROW_ID, Map<FAMILY_ID, Map<COLUMN_ID, DATA>>>

15
HBase - Datendesign
Key/Value Datenbank
java.util.Map
Row
Map<ROW_ID, DATA>
Column Family
Map<ROW_ID, Map<FAMILY_ID, DATA>>
Column
Map<ROW_ID, Map<FAMILY_ID, Map<COLUMN_ID, DATA>>>

Alle Werte sind byte[]
Map<byte[], Map<byte[], Map<byte[], byte[]>>>

16
HBase - Datendesign

17
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
HBase - Column Families

Column Families werden in unterschiedlichen Dateien
gespeichert

19
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
HBase - Versionierung

Jede ”Zelle” wird mit einem Timestamp gespeichert und
automatisch versioniert

21
HBase - Versionierung

Jede ”Zelle” wird mit einem Timestamp gespeichert und
automatisch versioniert
Map<byte[], Map<byte[], Map<byte[], Map<Long, byte[]>>>>

22
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
HBase API Grundlagen

24
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
Exkurs: Ubuntu 11.10 und HBase

/etc/hosts
127.0.0.1
localhost
#127.0.1.1
servername
192.168.178.44 localhost

26
HBase API - Tabellen anlegen
Tabellen m¨ssen explizit angelegt werden
u
Shell
create ’person’, ’cfamily1’

27
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
HBase API - Daten speichern
Shell
put ’person’, ’id_1’, ’cfamily1:firstname’, ’John’
put ’person’, ’id_1’, ’cfamily1:lastname’, ’McCarthy’

29
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
HBase API - Daten lesen

Shell
hbase(main):001:0> scan ’person’
ROW COLUMN+CELL
id_1 column=cfamily1:firstname, timestamp=123,
value=John
id_1 column=cfamily1:lastname, timestamp=123,
value=McCarthy
1 row(s) in 0.1100 seconds

31
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
HBase API - Daten l¨schen
o

Shell
delete ’person’, ’id_1’, ’cfamily1:firstname’

33
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
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
HBase und Web-Anwendungen

36
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
Atomare Operationen, Isolierung

Atomare Operationen sind:
Put, Get, Delete, ...
Keine Gruppierung m¨glich!
o
Jeder Aufruf ist direkt ein RPC-call

38
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
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
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
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
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
Synchronisation uber Locks m¨glich
o
¨

Probleme
Welche Rows eignen sich als gemeinsamer Lock?
Gefahr von Deadlocks

44
Thread-Sicherheit der API

HTable
Das Erstellen einer HTable-Instanz kann mehrere Sekunden
dauern
Instanzen sollten daher immer wiederverwendet werden

45
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
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
”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
”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
”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
”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
Row IDs erzeugen

ID Erzeugung ist nicht atomar
GET aktueller Wert
+1
PUT neuer Wert

52
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
Primary Keys

54
Secondary Keys

55
Secondary Keys - Backrefs

56
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
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
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
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
Secondary Keys und Scanner - Alter?

Padding
2 → 0002
12 → 0012
42 → 0042
135 → 0135

61
Secondary Keys und Scanner - Alter?

Padding
2 → 0002
12 → 0012
42 → 0042
135 → 0135

Probleme
Maximale Zahlenl¨nge muss bekannt sein
a

62
Secondary Keys und Scanner - Alter?

Wie w¨re eine andere Zahlendarstellung? (Additionssystem)
a
2→2
12 → 92
42 → 99992
135 → 99999999999995

63
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
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
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
Fazit 2/6

Kostenargumente sind schwer dem Kunden zu verkaufen,
wenn Oracle und Co. schon im Einsatz ist, Lizenzen
vorhanden sind, etc.

67
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
Fazit 4/6

HBase (& Co.): Imperativ
SQL: Deklarativ

69
Fazit 5/6

Es ist nicht leicht, im Team stabile Tests zu erstellen
Man vermisst jdbc:h2:mem:testdb

70
Fazit 6/6

Die Vorteile von HBase wurden durch Verzicht erm¨glicht
o

71
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
Vielen Dank f¨r Ihre Aufmerksamkeit!
u
Fragen?

73

Webanwendungen mit Apache HBase entwickeln

  • 1.
    Webanwendungen mit ApacheHBase entwickeln Roman Roelofsen Managing Director (aka Alpha Geek) Weigle Wilczek GmbH Twitter: romanroe JAX, 19. April 2012 1
  • 2.
    ¨ WeigleWilczek - UberUns IT-Beratung, Software-Entwicklung Typische Anwendungen ”Web-Anwendungen” Lagerverwaltung Kennzahlenanalyse, Dashboards Kein Facebook, Twitter, etc. 2
  • 3.
    Typischer Stack JVM Jetty/Tomcat/WebSphere Guice/Spring Diverse Web-Frameworks DiverseRDBMS (MySQL, PostreSQL, ...) Ein paar Exoten MongoDB Prevayler 3
  • 4.
    Probleme mit RDBMS Schlechtehorizontale 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 uberfl¨ssig (weniger Administration) u ¨ NoSQL-Architekturen passen gut zum Cloud-Trend Apache Hadoop wird (in den USA) sehr gehyped → Evaluierung 5
  • 6.
  • 7.
  • 8.
  • 9.
    Auswahl NoSQL Sammelbegriff f¨rviele Datenbanken u Dokumenten-Datenbank Graph-Datenbank Key/Value Datenbank Objekt-Datenbank Google’s BigTable, Amazon’s Dynamo ... 9
  • 10.
    Google’s BigTable Verteilte Key/ValueDatenbank Basiert auf Google File System Fehlertolerant Skalierbar L¨uft auf ”billiger” Hardware a Erlaubt Parallelisierung (MapReduce & Co.) 10
  • 11.
    Apache Hadoop Stack Hadoop VerteiltesDateisystem (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
  • 12.
    Exkurs: HBase vs.Cassandra HBase Vorteile Konsistenz Read-Performance > Write-Performance Cassandra Vorteile Write-Performance > Read-Performance Wichtig f¨r Business-Anwendungen u Konsistenz Read-Performance Abfragen 12
  • 13.
    HBase - Datendesign Key/ValueDatenbank java.util.Map Row Map<ROW_ID, DATA> 13
  • 14.
    HBase - Datendesign Key/ValueDatenbank java.util.Map Row Map<ROW_ID, DATA> Column Family Map<ROW_ID, Map<FAMILY_ID, DATA>> 14
  • 15.
    HBase - Datendesign Key/ValueDatenbank java.util.Map Row Map<ROW_ID, DATA> Column Family Map<ROW_ID, Map<FAMILY_ID, DATA>> Column Map<ROW_ID, Map<FAMILY_ID, Map<COLUMN_ID, DATA>>> 15
  • 16.
    HBase - Datendesign Key/ValueDatenbank java.util.Map Row Map<ROW_ID, DATA> Column Family Map<ROW_ID, Map<FAMILY_ID, DATA>> Column Map<ROW_ID, Map<FAMILY_ID, Map<COLUMN_ID, DATA>>> Alle Werte sind byte[] Map<byte[], Map<byte[], Map<byte[], byte[]>>> 16
  • 17.
  • 18.
    HBase - Datendesign ZeilenIDs 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 - ColumnFamilies Column Families werden in unterschiedlichen Dateien gespeichert 19
  • 20.
    HBase - HorizontaleSkalierung IDs werden in Regionen aufgeteilt Regionen werden auf Region Servers gespeichert Regionen und Region Server werden je nach Auslastung neu angeordnet 20
  • 21.
    HBase - Versionierung Jede”Zelle” wird mit einem Timestamp gespeichert und automatisch versioniert 21
  • 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
  • 24.
  • 25.
    HBase - GettingStarted 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
  • 26.
    Exkurs: Ubuntu 11.10und HBase /etc/hosts 127.0.0.1 localhost #127.0.1.1 servername 192.168.178.44 localhost 26
  • 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
  • 31.
    HBase API -Daten lesen Shell hbase(main):001:0> scan ’person’ ROW COLUMN+CELL id_1 column=cfamily1:firstname, timestamp=123, value=John id_1 column=cfamily1:lastname, timestamp=123, value=McCarthy 1 row(s) in 0.1100 seconds 31
  • 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
  • 36.
  • 37.
    Web-Anwendungen Mehrere Threads imServer 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
  • 38.
    Atomare Operationen, Isolierung AtomareOperationen sind: Put, Get, Delete, ... Keine Gruppierung m¨glich! o Jeder Aufruf ist direkt ein RPC-call 38
  • 39.
    Atomare Operationen, Isolierung AtomareOperationen 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 Reihenfolgeim 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 HBaseerlaubt 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 Locksm¨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 Locksm¨glich o ¨ Probleme Welche Rows eignen sich als gemeinsamer Lock? Gefahr von Deadlocks 44
  • 45.
    Thread-Sicherheit der API HTable DasErstellen einer HTable-Instanz kann mehrere Sekunden dauern Instanzen sollten daher immer wiederverwendet werden 45
  • 46.
    Thread-Sicherheit der API HTable DasErstellen 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 DasErstellen 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 IDErzeugung ist nicht atomar GET aktueller Wert +1 PUT neuer Wert 52
  • 53.
    Row IDs erzeugen IDErzeugung 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
  • 54.
  • 55.
  • 56.
    Secondary Keys -Backrefs 56
  • 57.
    Secondary Keys undScanner - 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 undScanner - 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 undScanner - 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 undScanner - 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
  • 61.
    Secondary Keys undScanner - Alter? Padding 2 → 0002 12 → 0012 42 → 0042 135 → 0135 61
  • 62.
    Secondary Keys undScanner - Alter? Padding 2 → 0002 12 → 0012 42 → 0042 135 → 0135 Probleme Maximale Zahlenl¨nge muss bekannt sein a 62
  • 63.
    Secondary Keys undScanner - Alter? Wie w¨re eine andere Zahlendarstellung? (Additionssystem) a 2→2 12 → 92 42 → 99992 135 → 99999999999995 63
  • 64.
    Secondary Keys undScanner - 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 undScanner - 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 manmacht 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 sindschwer dem Kunden zu verkaufen, wenn Oracle und Co. schon im Einsatz ist, Lizenzen vorhanden sind, etc. 67
  • 68.
    Fazit 3/6 HBase kannsehr gut mehrere Rechner nutzen Jedoch muss man diese Eigenschaft nutzen, um uberhaupt ¨ erst eine gute Performance zu erhalten 68
  • 69.
    Fazit 4/6 HBase (&Co.): Imperativ SQL: Deklarativ 69
  • 70.
    Fazit 5/6 Es istnicht leicht, im Team stabile Tests zu erstellen Man vermisst jdbc:h2:mem:testdb 70
  • 71.
    Fazit 6/6 Die Vorteilevon HBase wurden durch Verzicht erm¨glicht o 71
  • 72.
    Wir stellen ein! Wirsuchen professionelle Java-Geeks! Wir bieten eine gesunde Mischung aus Programmierer Berater Kicker-Profi Bitte bei mir melden! roelofsen@weiglewilczek.com 72
  • 73.
    Vielen Dank f¨rIhre Aufmerksamkeit! u Fragen? 73