sql? nosql? newsql?!? what’s a java developer to do? - jdc2012 cairo, egypt

83
SQL, NoSQL, NewSQL? What's a developer to do? Chris Richardson Author of POJOs in Action Founder of the original CloudFoundry.com @crichardson [email protected]

Upload: chris-richardson

Post on 07-May-2015

1.461 views

Category:

Technology


0 download

DESCRIPTION

The database world is undergoing a major upheaval. NoSQL databases such as MongoDB and Cassandra are emerging as a compelling choice for many applications. They can simplify the persistence of complex data models and offering significantly better scalability and performance. But these databases have a very different and unfamiliar data model and APIs as well as a limited transaction model. Moreover, the relational world is fighting back with so-called NewSQL databases such as VoltDB, which by using a radically different architecture offers high scalability and performance as well as the familiar relational model and ACID transactions. Sounds great but unlike the traditional relational database you can’t use JDBC and must partition your data.In this presentation you will learn about popular NoSQL databases – MongoDB, and Cassandra - as well at VoltDB. We will compare and contrast each database’s data model and Java API using NoSQL and NewSQL versions of a use case from the book POJOs in Action. We will learn about the benefits and drawbacks of using NoSQL and NewSQL databases.

TRANSCRIPT

Page 1: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

SQL, NoSQL, NewSQL? What's a developer to do?

Chris Richardson

Author of POJOs in Action Founder of the original CloudFoundry.com

@crichardson [email protected]

Page 2: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Overall presentation goal

The joy and pain of building Java

applications that use NoSQL and NewSQL

2

Page 3: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

About Chris

3

Page 4: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

About Chris

4

Page 5: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

(About Chris)

5

Page 6: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

About Chris()

6

Page 7: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

About Chris

7

Page 8: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

About Chris

http://www.theregister.co.uk/2009/08/19/springsource_cloud_foundry/

8

Page 9: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

About Chris

Developer Advocate for CloudFoundry.com

9

Signup at CloudFoundry.com using promo code EgyptJUG

Page 10: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Agenda

 Why NoSQL? NewSQL?   Persisting entities   Implementing queries

3/18/12 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 10

Page 11: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Food to Go

  Take-out food delivery service

  “Launched” in 2006   Used a relational

database (naturally)

11

Page 12: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Success Growth challenges

  Increasing domain model complexity   Increasing traffic   Increasing data volume  Distribute across data centers

But relational databases make this difficult…

Page 13: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Problem: Complex object graphs

ID COL1 COL2 COL… ?!

Poor performance •  Many inserts •  Many joins

13

Page 14: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Problem: Semi-structured data

Customer_Id Name Value

1 Region CA

1 Type Bank

… … …

Customer attribute table

•  Lack of constraints •  Poor query performance, e.g. multiple outer joins

14

Page 15: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Problem: Semi-structured data

Id Name Street … Other_Attributes

1 Acme Inc 180 Main XML/JSON/Blob

2 Failed Bank 1 Wall Street

… … …

Customer table

Can’t be queried

15

Page 16: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Problem: Schema evolution

Id First_Name Last_Name

1 Maria Doe

2 John Smith

… … …

9948429292 Ben Grayson

Id First_Name Last_Name DOB

1 Maria Doe 10/14/38

Locks? Application downtime?

16

Page 17: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Problem: Scaling

 Moore’s law is your friend BUT

 Scaling reads:   Master/slave   But beware of consistency issues

 Scaling writes   Extremely difficult/impossible/expensive   Vertical scaling is limited and requires $$   Horizontal scaling is limited/requires $$

Page 18: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Problem: distribution

3/18/12 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 18

Datacenter 1 Datacenter 2

App

DB

App

DB Synchronization

WAN

Many databases don’t support this out of the box

Page 19: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Solution: Buy high end technology

http://upload.wikimedia.org/wikipedia/commons/e/e5/Rising_Sun_Yacht.JPG

Page 20: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Solution: Hire more developers

 Application-level sharding  Build your own replication middleware  …

http://www.trekbikes.com/us/en/bikes/road/race_performance/madone_4_series/madone_4_5

Page 21: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Solution: Use NoSQL

Higher performance Higher scalability Richer data-model Schema-less

Limited transactions Relaxed consistency Unconstrained data

Ben

efits

Draw

backs

21

Page 22: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

MongoDB

 Document-oriented database   JSON-style documents: Lists, Maps, primitives   Schema-less

  Transaction = update of a single document  Rich query language for dynamic queries   Tunable writes: speed reliability  Highly scalable and available

22

Page 23: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

MongoDB use cases

 Use cases   High volume writes   Complex data   Semi-structured data

 Who is using it?   Shutterfly, Foursquare   Bit.ly Intuit   SourceForge, NY Times   GILT Groupe, Evite,   SugarCRM

3/18/12 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 23

Page 24: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Apache Cassandra

  Column-oriented database/Extensible row store   Think Row ~= java.util.SortedMap

  Transaction = update of a row   Fast writes = append to a log   Tunable reads/writes: consistency

latency/availability   Extremely scalable

  Transparent and dynamic clustering   Rack and datacenter aware data replication

  CQL = “SQL”-like DDL and DML

24

Page 25: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Cassandra use cases  Use cases

•  Big data •  Multiple Data Center distributed database •  Persistent cache •  (Write intensive) Logging •  High-availability (writes)

 Who is using it   Digg, Facebook, Twitter, Reddit, Rackspace   Cloudkick, Cisco, SimpleGeo, Ooyala, OpenX   “The largest production cluster has over 100

TB of data in over 150 machines.“ – Casssandra web site

3/18/12 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 25

Page 26: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Other NoSQL databases

http://nosql-database.org/ lists 122+ NoSQL databases

Type Examples

Extensible columns/Column-oriented

Hbase SimpleDB DynamoDB

Graph Neo4j

Key-value Redis Membase

Document CouchDb

26

Page 27: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Solution: Use NewSQL

 Relational databases with SQL and ACID transactions

AND

 New and improved architecture  Radically better scalability and

performance

 NewSQL vendors: ScaleDB, NimbusDB, …, VoltDB

3/18/12 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 27

Page 28: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Stonebraker’s motivations

28

“…Current databases are designed for 1970s hardware …”

Stonebraker: http://www.slideshare.net/VoltDB/sql-myths-webinar

Significant overhead in “…logging, latching, locking, B-tree, and buffer management

operations…”

SIGMOD 08: Though the looking glass: http://dl.acm.org/citation.cfm?id=1376713

Page 29: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

About VoltDB

 Open-source   In-memory relational database  Durability thru replication; snapshots

and logging   Transparent partitioning   Fast and scalable

3/18/12 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 29

http://www.mysqlperformanceblog.com/2011/02/28/is-voltdb-really-as-scalable-as-they-claim/

…VoltDB is very scalable; it should scale to 120 partitions, 39 servers, and 1.6 million complex transactions per second at over 300 CPU cores…

Page 30: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

The future is polyglot persistence

IEEE Software Sept/October 2010 - Debasish Ghosh / Twitter @debasishg

e.g. Netflix •  RDBMS •  SimpleDB •  Cassandra •  Hadoop/Hbase

30

Page 31: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Spring Data is here to help

http://www.springsource.org/spring-data

NoSQL databases

31

For

Page 32: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Spring Data sub-projects

  Various sub-projects   SQL: Spring Data JPA, JDBC extensions   Commons: Polyglot persistence   Key-Value: Redis, Riak   Document: MongoDB   Graph: Neo4j   GORM for NoSQL

  What you get:   Wrapper classes analogous to JDBC

template   Generic Repository   Cross-store persistence   …

32

Page 33: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Proceed with caution

 Don’t commit to a NoSQL DB until you have done a significant POC

  Encapsulate your data access code so you can switch

 Hope that one day you won’t need ACID (or complex queries)

33

Page 34: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Agenda

 Why NoSQL? NewSQL?  Persisting entities   Implementing queries

3/18/12 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 34

Page 35: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Food to Go – Place Order use case

1.  Customer enters delivery address and delivery time

2.  System displays available restaurants 3.  Customer picks restaurant 4.  System displays menu 5.  Customer selects menu items 6.  Customer places order

35

Page 36: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Food to Go – Domain model (partial)

class Restaurant { long id; String name; Set<String> serviceArea; Set<TimeRange> openingHours; List<MenuItem> menuItems; }

class MenuItem { String name; double price; }

class TimeRange { long id; int dayOfWeek; int openingTime; int closingTime; }

36

Page 37: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Database schema ID Name …

1 Ajanta

2 Montclair Eggshop

Restaurant_id zipcode

1 94707

1 94619

2 94611

2 94619

Restaurant_id dayOfWeek openTime closeTime

1 Monday 1130 1430

1 Monday 1730 2130

2 Tuesday 1130 …

RESTAURANT table

RESTAURANT_ZIPCODE table

RESTAURANT_TIME_RANGE table

37

Page 38: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Restaurant aggregate

How to implement the repository?

public interface AvailableRestaurantRepository {

void add(Restaurant restaurant); Restaurant findDetailsById(int id); … }

38

Restaurant

MenuItem TimeRange ?

Page 39: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Server

Database: Food To Go

Collection: Restaurants

MongoDB: persisting restaurants is easy

{ "_id" : ObjectId("4bddc2f49d1505567c6220a0") "name": "Ajanta", "serviceArea": ["94619", "99999"], "openingHours": [

{ "dayOfWeek": 1, "open": 1130, "close": 1430 }, { "dayOfWeek": 2, "open": 1130, "close": 1430 }, …

] }

BSON = binary JSON

Sequence of bytes on disk fast i/o

39

Page 40: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Using the MongoDB CLI

> r = db.restaurants.findOne({name:"Ajanta"}) { "_id" : ObjectId("4e555dd9646e338dca11710c"), "name" : "Ajanta" }

> r.type= "Indian” > db.restaurants.save(r)

40

> r = {name: 'Ajanta'}

> db.restaurants.save(r) > r { "_id" : ObjectId("4e555dd9646e338dca11710c"), "name" : "Ajanta" }

> db.restaurants.update({name:"Ajanta"}, {$set: {name:"Ajanta Restaurant"}, $push: { menuItems: {name: "Chicken Vindaloo"}}}) > db.restaurants.find() { "_id" : ObjectId("4e555dd9646e338dca11710c"), "menuItems" :

[ { "name" : "Chicken Vindaloo" } ], "name" : "Ajanta Restaurant", "type" : "Indian" }

> db.restaurants.remove(r.id)

Page 41: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Spring Data for Mongo code @Repository public class AvailableRestaurantRepositoryMongoDbImpl

implements AvailableRestaurantRepository {

public static String AVAILABLE_RESTAURANTS_COLLECTION = "availableRestaurants";

@Autowired private MongoTemplate mongoTemplate;

@Override public void add(Restaurant restaurant) { mongoTemplate.insert(restaurant, AVAILABLE_RESTAURANTS_COLLECTION); }

@Override public Restaurant findDetailsById(int id) { return mongoTemplate.findOne(new Query(where("_id").is(id)),

Restaurant.class, AVAILABLE_RESTAURANTS_COLLECTION); } }

41

Page 42: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Spring Configuration

@Configuration public class MongoConfig extends AbstractDatabaseConfig {

@Value("#{mongoDbProperties.databaseName}") private String mongoDbDatabase;

@Bean public Mongo mongo() throws UnknownHostException, MongoException { return new Mongo(databaseHostName); }

@Bean public MongoTemplate mongoTemplate(Mongo mongo) throws Exception { MongoTemplate mongoTemplate = new MongoTemplate(mongo, mongoDbDatabase); mongoTemplate.setWriteConcern(WriteConcern.SAFE); mongoTemplate.setWriteResultChecking(WriteResultChecking.EXCEPTION); return mongoTemplate; } }

42

Page 43: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Keyspace

Column Family

K1

Cassandra data model

N1 V1 TS1 N2 V2 TS2 N3 V3 TS3

N1 V1 TS1 N2 V2 TS2 N3 V3 TS3 K2

Column Name

Column Value

Timestamp Row Key

43

Column name/value: number, string, Boolean, timestamp, and composite

Page 44: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

CF.insert(key=K1, (N4, V4, TS4), …)

Cassandra– inserting/updating data

Idempotent= transaction

Column Family

K1 N1 V1 TS1

N2 V2 TS2 N3 V3 TS3

Column Family

K1 N1 V1 TS1

N2 V2 TS2 N3 V3 TS3 N4 V4 TS4

44

Page 45: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

CF.slice(key=K1, startColumn=N2, endColumn=N4)

Cassandra– retrieving data Column Family

K1 N1 V1 TS1

N2 V2 TS2 N3 V3 TS3 N4 V4 TS4

K1 N2 V2 TS2 N3 V3 TS3 N4 V4 TS4

45

Cassandra has secondary indexes but they aren’t helpful for these use cases

Page 46: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Option #1: Use a column per attribute

Column Family: RestaurantDetails

1

name Ajanta

type indian

serviceArea[0] 94619

serviceArea[1] 94707

openingHours[0].dayOfWeek Monday

openingHours[0].open 1130

2

name Egg shop

type Break Fast

serviceArea[0] 94611

serviceArea[1] 94619

openingHours[0].dayOfWeek Monday

openingHours[0].open 0830

Column Name = path/expression to access property value

openingHours[0].close 1430

openingHours[0].close 1430

Page 47: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

2 attributes: { name: “Montclair Eggshop”, … }

Column Family: RestaurantDetails

1 attributes { name: “Ajanta”, …}

2

Option #2: Use a single column

attributes { name: “Eggshop”, …}

✔ 47

Column value = serialized object graph, e.g. JSON

Page 48: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Cassandra code

public class AvailableRestaurantRepositoryCassandraKeyImpl implements AvailableRestaurantRepository {

@Autowired private final CassandraTemplate cassandraTemplate;

public void add(Restaurant restaurant) { cassandraTemplate.insertEntity(keyspace,

RESTAURANT_DETAILS_CF, restaurant);

}

public Restaurant findDetailsById(int id) { String key = Integer.toString(id); return cassandraTemplate.findEntity(Restaurant.class,

keyspace, key, RESTAURANT_DETAILS_CF); … }

48

Home grown wrapper class

http://en.wikipedia.org/wiki/Hector

Page 49: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Using VoltDB

 Use the original schema  Standard SQL statements

BUT YOU MUST

 Write stored procedures and invoke them using proprietary interface

  Partition your data

3/18/12 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 49

Page 50: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

About VoltDB stored procedures

 Key part of VoltDB  Replication = executing stored

procedure on replica   Logging = log stored procedure

invocation  Stored procedure invocation =

transaction

3/18/12 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 50

Page 51: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

About partitioning

3/18/12 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 51

ID Name …

1 Ajanta

2 Eggshop

Partition column

RESTAURANT table

Page 52: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Example cluster

3/18/12 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 52

VoltDB Server 1

ID Name …

1 Ajanta

VoltDB Server 2

ID Name …

2 Eggshop

VoltDB Server 3

ID Name …

… ..

Partition 1a Partition 2a Partition 3a

ID Name …

1 Ajanta

ID Name …

2 Eggshop

ID Name …

… ..

Partition 3b Partition 1b Partition 2b

Page 53: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Single partition procedure: FAST

3/18/12 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 53

VoltDB Server 1

ID Name …

1 Ajanta

VoltDB Server 2

ID Name …

1 Eggshop

VoltDB Server 3

ID Name …

… ..

SELECT * FROM RESTAURANT WHERE ID = 1

High-performance lock free code

Page 54: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Multi-partition procedure: SLOWER

3/18/12 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 54

VoltDB Server 1

ID Name …

1 Ajanta

VoltDB Server 2

ID Name …

1 Eggshop

VoltDB Server 3

ID Name …

… ..

SELECT * FROM RESTAURANT WHERE NAME = ‘Ajanta’

Communication/Coordination overhead

Page 55: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Chosen partitioning scheme

55

<partitions> <partition table="restaurant" column="id"/> <partition table="service_area" column="restaurant_id"/> <partition table="menu_item" column="restaurant_id"/> <partition table="time_range" column="restaurant_id"/> <partition table="available_time_range" column="restaurant_id"/> </partitions>

Performance is excellent: much faster than MySQL

Page 56: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Stored procedure – AddRestaurant @ProcInfo( singlePartition = true, partitionInfo = "Restaurant.id: 0”)

public class AddRestaurant extends VoltProcedure {

public final SQLStmt insertRestaurant = new SQLStmt("INSERT INTO Restaurant VALUES (?,?);");

public final SQLStmt insertServiceArea = new SQLStmt("INSERT INTO service_area VALUES (?,?);");

public final SQLStmt insertOpeningTimes = new SQLStmt("INSERT INTO time_range VALUES (?,?,?,?);");

public final SQLStmt insertMenuItem = new SQLStmt("INSERT INTO menu_item VALUES (?,?,?);");

public long run(int id, String name, String[] serviceArea, long[] daysOfWeek, long[] openingTimes, long[] closingTimes, String[] names, double[] prices) {

voltQueueSQL(insertRestaurant, id, name);

for (String zipCode : serviceArea) voltQueueSQL(insertServiceArea, id, zipCode);

for (int i = 0; i < daysOfWeek.length ; i++) voltQueueSQL(insertOpeningTimes, id, daysOfWeek[i], openingTimes[i], closingTimes[i]);

for (int i = 0; i < names.length ; i++) voltQueueSQL(insertMenuItem, id, names[i], prices[i]);

voltExecuteSQL(true);

return 0; } }

56

Page 57: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

VoltDb repository – add() @Repository public class AvailableRestaurantRepositoryVoltdbImpl

implements AvailableRestaurantRepository {

@Autowired private VoltDbTemplate voltDbTemplate;

@Override public void add(Restaurant restaurant) { invokeRestaurantProcedure("AddRestaurant", restaurant); }

private void invokeRestaurantProcedure(String procedureName, Restaurant restaurant) { Object[] serviceArea = restaurant.getServiceArea().toArray(); long[][] openingHours = toArray(restaurant.getOpeningHours()); Object[][] menuItems = toArray(restaurant.getMenuItems());

voltDbTemplate.update(procedureName, restaurant.getId(), restaurant.getName(), serviceArea, openingHours[0], openingHours[1],

openingHours[2], menuItems[0], menuItems[1]); }

57

Flatten Restaurant

Page 58: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

VoltDbTemplate wrapper class public class VoltDbTemplate {

private Client client;

public VoltDbTemplate(Client client) { this.client = client; }

public void update(String procedureName, Object... params) { try { ClientResponse x =

client.callProcedure(procedureName, params); … } catch (Exception e) { throw new RuntimeException(e); } }

58

VoltDB client API

Page 59: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

VoltDb server configuration

voltcompiler target/classes \ src/main/resources/sql/voltdb-project.xml foodtogo.jar

59

<?xml version="1.0"?> <project> <info> <name>Food To Go</name> ... </info> <database> <schemas> <schema path='schema.sql' /> </schemas>

<partitions> <partition table="restaurant" column="id"/> ...

</partitions>

<procedures> <procedure class='net.chrisrichardson.foodToGo.newsql.voltdb.procs.AddRestaurant' /> ... </procedures> </database> </project>

<deployment> <cluster hostcount="1"

sitesperhost="5" kfactor="0" /> </deployment>

bin/voltdb leader localhost catalog foodtogo.jar deployment deployment.xml

Page 60: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Performance

3/18/12 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 60

Mongo Cassandra VoltDB

Insert for PK Awesome Fast* Awesome

Find by PK Awesome Fast Incredible

* Cassandra can be clustered for improved write performance

Benchmarking is still work in progress but so far

http://www.youtube.com/watch?v=b2F-DItXtZs

Page 61: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Agenda

 Why NoSQL? NewSQL?   Persisting entities   Implementing queries

3/18/12 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 61

Page 62: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Finding available restaurants Available restaurants =

Serve the zip code of the delivery address

AND Are open at the delivery time

public interface AvailableRestaurantRepository {

List<AvailableRestaurant> findAvailableRestaurants(Address deliveryAddress, Date deliveryTime); …

}

62

Page 63: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Finding available restaurants on Monday, 6.15pm for 94619 zip

select r.* from restaurant r inner join restaurant_time_range tr on r.id =tr.restaurant_id inner join restaurant_zipcode sa on r.id = sa.restaurant_id Where ’94619’ = sa.zip_code and tr.day_of_week=’monday’ and tr.openingtime <= 1815 and 1815 <= tr.closingtime

Straightforward three-way join

63

Page 64: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

MongoDB = easy to query

Find a restaurant that serves the 94619 zip code and is open at 6.15pm on a Monday

{ serviceArea:"94619", openingHours: { $elemMatch : { "dayOfWeek" : "Monday", "open": {$lte: 1815}, "close": {$gte: 1815} } } }

DBCursor cursor = collection.find(qbeObject); while (cursor.hasNext()) { DBObject o = cursor.next(); … }

64

db.availableRestaurants.ensureIndex({serviceArea: 1})

Page 65: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

MongoTemplate-based code @Repository public class AvailableRestaurantRepositoryMongoDbImpl implements AvailableRestaurantRepository {

@Autowired private final MongoTemplate mongoTemplate;

@Override public List<AvailableRestaurant> findAvailableRestaurants(Address deliveryAddress,

Date deliveryTime) { int timeOfDay = DateTimeUtil.timeOfDay(deliveryTime); int dayOfWeek = DateTimeUtil.dayOfWeek(deliveryTime);

Query query = new Query(where("serviceArea").is(deliveryAddress.getZip()) .and("openingHours”).elemMatch(where("dayOfWeek").is(dayOfWeek) .and("openingTime").lte(timeOfDay) .and("closingTime").gte(timeOfDay)));

return mongoTemplate.find(AVAILABLE_RESTAURANTS_COLLECTION, query, AvailableRestaurant.class);

}

mongoTemplate.ensureIndex(“availableRestaurants”, new Index().on("serviceArea", Order.ASCENDING));

65

Page 66: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

BUT how to do this with Cassandra??!

  How can Cassandra support a query that has   A 3-way join   Multiple =   > and < ?

Queries instead of data model drives NoSQL database design

66

We need to implement an index

Page 67: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

... And use a slice operation

3/18/12 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 67

columnFamily.slice(key=keyVal, startColumn=startVal, endColumn=endVal)

= select * from columnFamily where key = keyVal and col >= startVal and col <= endVal

Page 68: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Simplification #1: Denormalization

Restaurant_id Day_of_week Open_time Close_time Zip_code

1 Monday 1130 1430 94707

1 Monday 1130 1430 94619

1 Monday 1730 2130 94707

1 Monday 1730 2130 94619

2 Monday 0700 1430 94619

SELECT restaurant_id FROM time_range_zip_code WHERE day_of_week = ‘Monday’ AND zip_code = 94619 AND 1815 < close_time

AND open_time < 1815

Simpler query:   No joins   Two = and two <

68

Page 69: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Simplification #2: Application filtering

SELECT restaurant_id, open_time FROM time_range_zip_code WHERE day_of_week = ‘Monday’ AND zip_code = 94619 AND 1815 < close_time

AND open_time < 1815

Even simpler query •  No joins •  Two = and one <

69

Page 70: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Simplification #3: Eliminate multiple =’s with concatenation

SELECT restaurant_id, open_time FROM time_range_zip_code WHERE zip_code_day_of_week = ‘94619:Monday’ AND 1815 < close_time

Restaurant_id Zip_dow Open_time Close_time

1 94707:Monday 1130 1430

1 94619:Monday 1130 1430

1 94707:Monday 1730 2130

1 94619:Monday 1730 2130

2 94619:Monday 0700 1430

key

range

70

Page 71: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Column Family: AvailableRestaurants

94619:Monday (1430,0700,2) JSON FOR EGG

(1430,1130,1) JSON FOR AJANTA

(2130,1730,1) JSON FOR AJANTA

Column family with composite column names as an index

Restaurant_id Zip_dow Open_time Close_time

1 94707:Monday 1130 1430

1 94619:Monday 1130 1430

1 94707:Monday 1730 2130

1 94619:Monday 1730 2130

2 94619:Monday 0700 1430

94619:Monday 1430 2 0700

Page 72: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

slice(key= 94619:Monday, sliceStart = (1815, *, *), sliceEnd = (2359, *, *))

Querying with a slice

94619:Monday

72

Column Family: AvailableRestaurants

94619:Monday (1430,0700,2) JSON FOR

EGG

(1430,1130,1) JSON FOR AJANTA

(2130,1730,1) JSON FOR AJANTA

18:15 is after 17:30 {Ajanta}

(2130,1730,1) JSON FOR AJANTA

Page 73: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

private void insertAvailability(Restaurant restaurant) {

for (String zipCode : (Set<String>) restaurant.getServiceArea()) { for (TimeRange tr : (Set<TimeRange>) restaurant.getOpeningHours()) { String dayOfWeek = format2(tr.getDayOfWeek()); String openingTime = format4(tr.getOpeningTime()); String closingTime = format4(tr.getClosingTime()); String restaurantId = format8(restaurant.getId());

String key = formatKey(zipCode, dayOfWeek); String columnValue = toJson(restaurant);

Composite columnName = new Composite(); columnName.add(0, closingTime); columnName.add(1, openingTime); columnName.add(2, restaurantId);

ColumnFamilyUpdater<String, Composite> updater = compositeCloseTemplate.createUpdater(key);

updater.setString(columnName, columnValue);

compositeCloseTemplate.update(updater);

} } }

Needs a few pages of code

73

@Override public List<AvailableRestaurant> findAvailableRestaurants(Address deliveryAddress, Date deliveryTime) { int dayOfWeek = DateTimeUtil.dayOfWeek(deliveryTime); int timeOfDay = DateTimeUtil.timeOfDay(deliveryTime); String zipCode = deliveryAddress.getZip(); String key = formatKey(zipCode, format2(dayOfWeek));

HSlicePredicate<Composite> predicate = new HSlicePredicate<Composite>(new CompositeSerializer()); Composite start = new Composite(); Composite finish = new Composite(); start.addComponent(0, format4(timeOfDay), ComponentEquality.GREATER_THAN_EQUAL); finish.addComponent(0, format4(2359), ComponentEquality.GREATER_THAN_EQUAL); predicate.setRange(start, finish, false, 100);

final List<AvailableRestaurantIndexEntry> closingAfter = new ArrayList<AvailableRestaurantIndexEntry>();

ColumnFamilyRowMapper<String, Composite, Object> mapper = new ColumnFamilyRowMapper<String, Composite, Object>() {

@Override public Object mapRow(ColumnFamilyResult<String, Composite> results) { for (Composite columnName : results.getColumnNames()) { String openTime = columnName.get(1, new StringSerializer()); String restaurantId = columnName.get(2, new StringSerializer()); closingAfter.add(new AvailableRestaurantIndexEntry(openTime, restaurantId, results.getString(columnName))); } return null; } };

compositeCloseTemplate.queryColumns(key, predicate, mapper);

List<AvailableRestaurant> result = new LinkedList<AvailableRestaurant>();

for (AvailableRestaurantIndexEntry trIdAndAvailableRestaurant : closingAfter) { if (trIdAndAvailableRestaurant.isOpenBefore(timeOfDay)) result.add(trIdAndAvailableRestaurant.getAvailableRestaurant()); }

return result; }

Page 74: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

What did I just do to query the data?

 Wrote code to maintain an index  Reduced performance due to extra

writes

74

Page 75: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Mongo vs. Cassandra

3/18/12 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 75

DC1

Shard A Master

DC1 Client

DC2

Shard B Master

DC2 Client

Remote MongoDB

DC1

Cassandra

DC1 Client

DC2

Cassandra

DC2 Client

Async

Or

Sync Cassandra

Page 76: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

VoltDB - attempt #1

3/18/12 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 76

ERROR 10:12:03,251 [main] COMPILER: Failed to plan for statement type(findAvailableRestaurants_with_join) select r.* from restaurant r,time_range tr, service_area sa Where ? = sa.zip_code and r.id =tr.restaurant_id and r.id = sa.restaurant_id and tr.day_of_week=? and tr.open_time <= ? and ? <= tr.close_time Error: "Unable to plan for statement. Likely statement is joining two partitioned tables in a multi-partition statement. This is not supported at this time." ERROR 10:12:03,251 [main] COMPILER: Catalog compilation failed.

Bummer!

@ProcInfo( singlePartition = false) public class FindAvailableRestaurants extends VoltProcedure { ... }

Page 77: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

VoltDB - attempt #2

3/18/12 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 77

@ProcInfo( singlePartition = true, partitionInfo = "Restaurant.id: 0”) public class AddRestaurant extends VoltProcedure {

public final SQLStmt insertAvailable= new SQLStmt("INSERT INTO available_time_range VALUES (?,?,?, ?, ?, ?);");

public long run(....) { ...

for (int i = 0; i < daysOfWeek.length ; i++) { voltQueueSQL(insertOpeningTimes, id, daysOfWeek[i], openingTimes[i], closingTimes[i]); for (String zipCode : serviceArea) { voltQueueSQL(insertAvailable, id, daysOfWeek[i], openingTimes[i],

closingTimes[i], zipCode, name); } }

... voltExecuteSQL(true); return 0; } }

Works but queries are only slightly faster than MySQL!

public final SQLStmt findAvailableRestaurants_denorm = new SQLStmt( "select restaurant_id, name from available_time_range tr " + "where ? = tr.zip_code " + "and tr.day_of_week=? " + "and tr.open_time <= ? " + " and ? <= tr.close_time ");

Page 78: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

VoltDB - attempt #3

78

<partitions> ... <partition table="available_time_range" column="zip_code"/> </partitions>

Queries are really fast but inserts are not

Partitioning scheme – optimal for some use cases but not others

@ProcInfo( singlePartition = false, ...) public class AddRestaurant extends VoltProcedure { ... }

@ProcInfo( singlePartition = true, partitionInfo = "available_time_range.zip_code: 0") public class FindAvailableRestaurants extends VoltProcedure { ... }

Page 79: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Performance

3/18/12 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 79

Mongo Cassandra VoltDB

Insert for find available Awesome Ok* Ok

Find available restaurants

Ok Ok Awesome

* Cassandra can be clustered for improved write performance

Benchmarking is still work in progress but so far

Page 80: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Is NewSQL/NoSQL a good fit for Food To Go?

Cassandra Mongo VoltDB

Representing restaurants

Easy Very easy Easy

PK-lookup Easy Easy Easy

Find available restaurants query

Lots of code Easy Tricky

Use as SOR Yes – if distribution required

Yes – for single datacenter

Yes

80

Page 81: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Summary…

  Relational databases are great BUT there are limitations

  Each NoSQL database solves some problems BUT   Limited transactions: NoSQL = NoACID   One day needing ACID major rewrite   Query-driven, denormalized database design   …

  NewSQL databases such as VoltDB provides SQL, ACID transactions and incredible performance BUT   Not all operations are fast   Non-JDBC API

81

Page 82: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

… Summary

 Very carefully pick the NewSQL/NoSQL DB for your application

 Consider a polyglot persistence architecture

  Encapsulate your data access code so you can switch

 Startups = avoid NewSQL/NoSQL for shorter time to market?

3/18/12 Copyright (c) 2011 Chris Richardson. All rights reserved. Slide 82

Page 83: SQL? NoSQL? NewSQL?!? What’s a Java developer to do? - JDC2012 Cairo, Egypt

Thank you!

My contact info:

[email protected]

@crichardson

83

Signup at CloudFoundry.com using promo code EgyptJUG