JPA avec Cassandra, grâce à Achilles

1,960 views

Published on

0 Comments
2 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,960
On SlideShare
0
From Embeds
0
Number of Embeds
455
Actions
Shares
0
Downloads
34
Comments
0
Likes
2
Embeds 0
No embeds

No notes for slide

JPA avec Cassandra, grâce à Achilles

  1. 1. https://github.com/doanduyhai/AchillesJPA avec Cassandra ?Mission pas impossible !1
  2. 2. https://github.com/doanduyhai/Achilles• Développeur Java freelance full-stack• Bidouilleur Cassandra, créateur d’Achilles• En mission chez• doanduyhai.wordpress.com• @doanduyhai2Duy Hai DOAN
  3. 3. https://github.com/doanduyhai/AchillesAchillesPrésentation3
  4. 4. https://github.com/doanduyhai/AchillesAchilles• Framework de persistance JPA pour C*• Support des annotations/opérations JPA• Extensions spécifiques à C*• 2 implémentations : Thrift & CQL3*4
  5. 5. https://github.com/doanduyhai/AchillesPourquoi Achilles ?• Voulez-vous écrire ça ?5
  6. 6. https://github.com/doanduyhai/AchillesPourquoi Achilles ?• ou ça ?6
  7. 7. https://github.com/doanduyhai/AchillesPourquoi Achilles?• Librairies trop bas niveau (Hector, Thrift)• Virage vers SQL avec CQL3 par Datastax• Object mapper nécessaire pour lierentités/requêtes• Concepts JPA: bien connus et maîtrisés7
  8. 8. https://github.com/doanduyhai/AchillesMapping d’entités• Annotations JPA– @Entity, @Table– @Id, @EmbededId, @Column, @JoinColumn– @OneToOne, @OneToMany …• Spécifiques à Cassandra– @WideRow– @Consistency– @Key (composite)– @Lazy8
  9. 9. https://github.com/doanduyhai/Achilles 9Mapping d’entités@Entitypublic class UserBean@Idprivate Long id;@Columnprivate String name;@Lazy@Columnprivate List<Long> friendIds;@Columnprivate WideMap<UUID, String> tweets;@ManyToOne@JoinColumnprivate UserBean referer;
  10. 10. https://github.com/doanduyhai/AchillesTypes spécifiques Cassandra• WideMap<K,V>: miroir d’une column family– KeyValue<K,V>: représente une colonne– KeyValueIterator<K,V>: itérateur• Counter: compteur distribué10puissancealfred batgirl catwoman lois_lane robin1 6 7 1 8WideMap<String,Integer>KeyValue<String,Integer>
  11. 11. https://github.com/doanduyhai/Achilles 11Entity Manager• find(Entity.class,pk)– retourne entité « managed » (proxy)• getReference(Entity.class,pk)*– retourne proxy sans chargement initial– peut servir pour du direct-update• persist(entity)– écrase/met à jour toute valeur existante– persist(User(fn,ln,age)) puis persist(User(fn,ln)) ?
  12. 12. https://github.com/doanduyhai/AchillesEntity Manager• merge(entity)– dirty check + flush à C*– retourne entité « managed » si transient– entité retournée == entité mergée• remove(entity)– effacer + cascade delete des types de C*• refresh(entity)– recharge l’entité– identique à find()12
  13. 13. https://github.com/doanduyhai/AchillesPersistance avec Thrift• Persistance des champs « simples »1310firstname lastname ageDuyHai DOAN 32• Persistance des listes100 1 2 3Java Cassandra Scala Angular JS
  14. 14. https://github.com/doanduyhai/Achilles 14Persistance avec Thrift• Persistance des Sets101265231 68754 546546#Cassandra #Achilles #Tatami• Persistance des Maps10113131 6543213 51313 65465464{language:Java} {database:Cassandra} … …
  15. 15. https://github.com/doanduyhai/AchillesDirty check• Interception seulement sur getter (internal calls )• Pas d’update atomique des collections/maps• Dirty check des collections/maps coûteux en ThriftImpl– (read + delete) + write pour mettre à jour (pas de slicedelete)– optimisation possible pour Set & Map– list.add(2,peter) ???– faible cardinalité conseillée (10 -20)15friends0 1 2 3 4bob alice john helen richard
  16. 16. https://github.com/doanduyhai/AchillesLazy Loading• @Lazy, typiquement collections/maps• Champs chargés à l’appel du getter• Chargement complet des collections/maps parslice query• Champs de jointure toujours lazy, par choix deconception16
  17. 17. https://github.com/doanduyhai/AchillesJointures• Besoin de cohérence forte au détriment de laperformance• Join collections/maps ->– Optimisation avec MultiGet Slice Query auchargement• 1 lecture pour n clés primaires dans la collection/map• 1 multiget slice query pour charger les n jointures (nlectures côté C*)– Batch mutation pour sauvegarder– Jointure possible sur les WideMap17
  18. 18. https://github.com/doanduyhai/AchillesCascading• No cascade• PERSIST– écrase l’entité existante• MERGE– écrase les colonnes existantes si modifiées• REFRESH -> rien• REMOVE -> interdit/non supporté/mal• ALL -> tout sauf REMOVE18
  19. 19. https://github.com/doanduyhai/AchillesWideMap API19@Entity@Table(name=«user»)class User@Idprivate Long userId;@Columnprivate String firstname;…..@Column(table=« tweet »)WideMap<UUID,String> tweets;10067e6162-3b6f-… 54947df8-0e9e-… 38400000-8cf0-…Hello world! #IppEvent avec #Achilles Ceci est un tweet...10firstname lastname ageJulien DUBOIS ???
  20. 20. https://github.com/doanduyhai/AchillesWideMap API• insert(K key, V value, int ttl)• V get(K key)• remove(K key)• List<KeyValue<K, V>> find(K start, K end, int count)• List<KeyValue<K, V>> findBoundsExclusive(K start, K end,int count)• List<KeyValue<K, V>> findReverse(K start, K end, int count)• List<KeyValue<K,V>> findFirst(int count)• List<KeyValue<K,V>> findLast(int count)• KeyValueIterator<K,V> iterator(int count)• ...20
  21. 21. https://github.com/doanduyhai/AchillesWideRow• Entité avec une primary Key + WideMap• Représente directement une column family21@Entity@WideRowpublic class TweetLine@Idprivate Long id;@Columnprivate WideMap<UUID, String> tweets;10uuid1 uuid2 uuid3 uuid4 uuid5Test Hellow World Démo Achilles CQL3 Ipp Event
  22. 22. https://github.com/doanduyhai/AchillesCounter API• get()• incr(), incr(n)• decr(), decr(n)• Pas de suppression de compteur, c’est mal• WideMap<xxx,Counter> possible -> column familycounter dédiée22@Idprivate Long userId;@ColumnCounter tweetsCount;"User:10"tweetsCount friendsCount followersCount150 1000 420"Tweet:067e6162-3b6f"likesCount retweetCount5000 15000
  23. 23. https://github.com/doanduyhai/AchillesUsage23user.getTweets().insert(uuid, «content »);List<KeyValue<UUID,String>> first10 = user.getTweets().findFirst(10);List<String> last10Tweets = user.getTweets().findLastValues(10);user.setTweets(xxx);• WideMapLong tweetCount = user.getTweetCount().get();user.getTweetCount().incr(3);user.setTweetCount(xxx);• Counter
  24. 24. https://github.com/doanduyhai/AchillesDémoComment faire un clone de Twitteravec Achilles24
  25. 25. https://github.com/doanduyhai/AchillesCompromis• La lecture des tweets doit être très très rapide• L’envoi des tweets doit être relativementrapide• La suppression des tweets peut être lente25
  26. 26. https://github.com/doanduyhai/AchillesScénario 1• Modéliser un utilisateur• Modéliser la liste des amis/suiveurs• Implémenter un compteur d’amis/suiveurs• Implémenter la fonctionnalité « A suit B »• Donner la liste des amis/suiveurs d’unutilisateur• Donner les détails sur un utilisateur26
  27. 27. https://github.com/doanduyhai/AchillesScénario 2• Modéliser un « Tweet »• Implémenter l’envoi de tweet• Dupliquer le tweet– dans la liste des tweets propres à l’utilisateur– dans la timeline de l’utilisateur– dans la timeline de tous ses suiveurs27
  28. 28. https://github.com/doanduyhai/AchillesScénario 3• Supprimer un tweet– de la liste des tweets de l’utilisateur– de la timeline de l’utilisateur– de la timeline de tous ses suiveurs28
  29. 29. https://github.com/doanduyhai/AchillesScénario 4• Implémenter la gestion des hashtags• Créer une tag-line pour les tags• Gérer l’effacement du tweet de la taglinelorsque le tweet est effacé29
  30. 30. https://github.com/doanduyhai/AchillesScénario 5• Donner la possibilité de mettre un tweet en« favori » -> favoriteline• Détecter les personnes citées dans les tweets(@login) -> mentionline• Gérer l’effacement de la favoriteline et de lamentionline lorsque le tweet est effacé30
  31. 31. https://github.com/doanduyhai/AchillesClés Composite• Interface marqueur MultiKey• Annotation dédiée @Key(order=x)31@JoinColumnprivate WideMap<UserIndex, User> user;public class UserIndex implements MultiKey{@Key(order=1)private String login;@Key(order=2)private Long id;}
  32. 32. https://github.com/doanduyhai/AchillesConsistency Level• Par annotation32@Consistency(read=ONE,write=QUORUM)public class User@Column@Consistency(read=ONE,write=QUORUM)private Counter tweetsCount;@Column@Consistency(read=ONE,write=THREE)private WideMap<UUID,String> tweets;• Au runtime– persist(tweet,QUORUM)– merge(user,ALL)– tweetWideMap.insert(uuid1, «a tweet», ONE)
  33. 33. https://github.com/doanduyhai/AchillesTTL33• Sur les opérations JPA– persist(entity, ttl)– persist(entity, ttl, writeCL)– merge(entity, ttl)– merge(entity, ttl, writeCL)• Sur les WideMap– user.getTweets().insert(uuid, «content», ttl)• Pas de TTL sur les counters (pas de tombstones)
  34. 34. https://github.com/doanduyhai/AchillesLe futureQue nous réserve Achilles dansquelques mois ?34
  35. 35. https://github.com/doanduyhai/AchillesProjection• Support complet de CQL3– @NamedQuery, query data mapper– Prepared statement (perf)– Batches « atomiques »– Row key composite (clustering)• Interceptors (@PrePersist,@PreRemove…)• Listeners• Bean Validation (JSR 303)• Secondary index• Callable, Future<>…35
  36. 36. https://github.com/doanduyhai/AchillesRetour d’expérience CQL3• PreparedStatement (select fn,ln,age from User where userId=?)– Stocké côté serveur (100.000 max) et par Node– Seules les valeurs sont envoyées à l’exécution– Valeurs nulles possible -> effacer le champ– Pas possible de binder CL, TTL, Timestamp,possible dans C* 2.0– Pas de batch de PS, possible dans C* 2.0– Pas de IN (?) binding pour faire du MultiGet36
  37. 37. https://github.com/doanduyhai/Achilles 37Retour d’expérience CQL3• List/Set/Map démystifié– Nouveaux serializers:• ColumnToCollectionType• ListType, SetType,MapType– List: index = timeUUID généré• insertion rapide avec append/prepend• ré-écriture + décalage si insertion par index• read-before-write pour enlever un élément quelconque– Set: valeur stockée directement dans ColumnName– Map: columnName contient la clé
  38. 38. https://github.com/doanduyhai/AchillesRetour d’expérience CQL3CREATE TABLE users (user_id int PRIMARY KEY,emails set<text>,top_places list<text>,todo map<int, text>);INSERT INTO users(user_id,emails,top_places,todo)VALUES(1,{ddoan@test.com,dhdoan@gmail.com},[Paris,Chatillon’],{1:Demo Achilles, 2:Implement CQL3});RowKey: 1=> (column=, value=, timestamp=1362010585307000)=> (column=emails:64646f616e40746573742e636f6d,value=, timestamp=1362010585307000)=> (column=emails:6468646f616e40676d61696c2e636f6d,value=, timestamp=1362010585307000)=> (column=todo:00000001,value=44656d6f20416368696c6c6573, timestamp=1362010585307000)=> (column=todo:00000002,value=496d706c656d656e742043514c33,timestamp=1362010585307000)=> (column=top_places:16ae51c0813c11e289730dd4d81b4c6b,value=5061726973, timestamp=….)=> (column=top_places:16ae51c1813c11e289730dd4d81b4c6b,value=43686174696c6c6f6e, timestamp=…)38
  39. 39. https://github.com/doanduyhai/AchillesAchilles est open-source donc …39We need you !!!github.com/doanduyhai/Achilles

×