Apidays New York 2024 - The value of a flexible API Management solution for O...
Developing modular, polyglot applications with Spring (SpringOne India 2012)
1. Developing modular, polyglot applications with Spring
Chris Richardson
Author of POJOs in Action, Founder of the original CloudFoundry.com
@crichardson chris.richardson@springsource.com
http://plainoldobjects.com/
2. Presentation goal
Modular, polyglot applications:
what, why and how?
Why Spring is the ideal technology
for building these applications
17. Traditional web application
architecture
WAR
StoreFrontUI
Accounting
Service
MySQL
Browser Apache Database
InventoryService
Simple to Shipping
Service
develop
test Tomcat
deploy
scale
19. Users expect a rich, dynamic and
interactive experience
h
oug
d en
HTTP Request
oo
’t g
Browser
e isn Java Web Application
HTML/Javascript
ec tur
it
ar ch
e UI
s tyl
Old
HTML5/JavaScript browser applications
Real-time web ≅ NodeJS
20. Limitations of relational
databases
• Scalability
• Distribution
• Schema updates
• O/R impedance mismatch
• Handling semi-structured data
22. Scalability issues
• Different components have different scalability needs but
you can only scale the entire system
• Some components might not be scalable can’t scale system
23. Obstacle to frequent
deployments
• Need to redeploy everything to change one component
• Increases risk of failure, e.g. interrupts background jobs
Fear of change
• Extensive test cycle
• Updates will happen less often, e.g. Makes A/B testing UI really difficult
27. Agenda
• The (sometimes evil) monolith
• Refactoring to a modular, polyglot architecture
• Presentation layer design
• Using NoSQL databases
• Inter-service communication options
28.
29. The scale cube
Y axis -
functional
decomposition
ila g
sim nin
Scale by
r
ing ing tio
splitting
th litt r ti
sp pa
different things
by data
s
ale -
Sc is
ax
Z
X axis - horizontal
duplication
30. Y-axis scaling - application level
WAR
StoreFrontUI
Accounting
Service
InventoryService
Shipping
Service
31. Y-axis scaling - application level
accounting application
Accounting
Service
Store front web application inventory application
StoreFrontUI InventoryService
shipping application
Shipping
Service
Apply X axis cloning and/or Z axis partitioning to each service
32. Real world examples
http://techblog.netflix.com/
Between 100-150 services are accessed to build a
page.
http://highscalability.com/amazon-architecture
http://www.addsimplicity.com/downloads/
eBaySDForum2006-11-29.pdf
http://queue.acm.org/detail.cfm?id=1394128
33. Drawbacks of Y-axis splits
• Complexity
• Partitioned databases and transaction management
• Deciding when to use this approach
34. But there are many benefits
• Scales development: develop, deploy and scale each service
independently
• Enables frequent deployments
• Less for each developer to learn
• Doesn’t overload IDE or container
• Improves fault isolation
• Easily adopt new technologies
35. Two levels of architecture
System-level
Services
Inter-service glue: interfaces and communication mechanisms
Slow changing
Service-level
Internal architecture of each service
Each service can use a different technology stack
Rapidly evolving - regularly rewrite
Pick the best tool for the job
38. But there are lots of awesome,
and mature Spring projects
• Spring Framework • Spring Integration
• Spring Security • Spring AMQP
• Spring Mobile • Spring Social
• Spring Data • Spring Shell
• Spring Web Services • ...
• Spring Batch
39. Spring works with Scala
@Controller
class TwilioController {
@Autowired var surveyManagementService: SurveyManagementService = _
@RequestMapping(value = Array("/begincall.html"))
@ResponseBody
def beginCall(@RequestParam("From") callerId: String) = {
surveyManagementService.findSurveyByCallerId(callerId) match {
case None =>
<Response>
<Say>Sorry don't recognize your number</Say>
<Hangup/>
</Response>
case Some(survey) =>
<Response>
<Say>{ survey.prompt }</Say>
<Gather action="handleresponse.html" method="POST" numDigits="1">
{
for ((choice, index) <- survey.choices zipWithIndex)
yield <Say>Press { index } for { choice }</Say>
}
</Gather>
<Say>We are sorry you could not decide</Say>
<Hangup/>
</Response>
}
}
40. The Spring Scala project
class
PersonConfiguration
extends
FunctionalConfiguration
{
val
jack
=
bean()
{
new
Person("Jack",
"Doe")
}
• Scala-style “setters/getters”
val
jane
=
bean()
{
new
Person("Jane",
"Doe")
}
• Bean configuration DSL
val
john
=
bean()
{
val
john
=
new
Person("John",
"Doe")
john.father
=
jack()
• Scala-style template classes
john.mother
=
jane()
john
}
}
https://github.com/SpringSource/spring-scala
48. Why NodeJS?
• Familiar JavaScript
• High-performance, scalable event-driven, non-blocking I/O
model
• Compact runtime, e.g. 64M
• Over 13,000 17,000 modules developed by the community
• ManyJavaScript client frameworks have a NodeJS
counterpart, e.g. socket.io and SockJS
50. Dealing with JavaScript
“...Still the consequence of this is
that we must take javascript
seriously as a first-class language and
concentrate on how to limit the
damage its flaws cause....”
http://martinfowler.com/bliki/gotoAarhus2012.html
51. NodeJS as a mediator...
Node JS Service 1
Browser
Server app
Static content
REST Service 2
HTML 5
Application Events
Socket.io Socket.io
client server ...
52. ...NodeJS as a mediator
REST REST
Service
Node JS
Events AMQP AMQP
socket.io RabbitMQ Service
53. Example NodeJS application
var express = require('express')
, http = require('http')
, amqp = require(‘amqp’)
, server = http.createServer(app)
, io = require('socket.io').listen(server)
....;
server.listen(8081); Handle socket.io
... connection
var amqpCon = amqp.createConnection(...);
io.sockets.on('connection', function (socket) {
Republish as
function amqpMessageHandler(message, headers, deliveryInfo) {
var m = JSON.parse(message.data.toString());
socket.io event
socket.emit(‘tick’, m);
};
amqpCon.queue(“”, {}, Subscribe to AMQP
function(queue) {
queue.bind(“myExchange”, “myBindingKey”); queue
queue.subscribe(amqpMessageHandler);
});
});
54. Example browser application
<html>
<body>
The event is <span data-bind="text: ticker"></span>
<script src="/socket.io/socket.io.js"></script>
<script src="/knockout-2.0.0.js"></script>
<script src="/clock.js"></script>
</body> Bind to model Connect to
</html>
socket.io server
clock.js
var socket = io.connect(location.hostname);
function ClockModel() {
self.ticker = ko.observable(1); Subscribe to tick
socket.on('tick', function (data) { event
self.ticker(data);
});
};
Update model
ko.applyBindings(new ClockModel());
55. About Cujojs & s2js
Dependency Injection
www.cujojs.com
github.com/s2js
JavaScript
Portable Aspect-
Service Oriented
Abstractions Programming
56. Agenda
• The (sometimes evil) monolith
• Refactoring to a modular, polyglot architecture
• Presentation layer design
• Using NoSQL databases
• Inter-service communication options
58. Example NoSQL Databases
Database Key features
Cassandra Extensible column store, very scalable, distributed
Neo4j Graph database
Document-oriented, fast, scalable
MongoDB
Redis Key-value store, very fast
http://nosql-database.org/ lists 122+ NoSQL
databases
59. NoSQL and the scale cube
nin a ing
itio dr rd
r t an ha
pa ss s
Ca DB
g
go
on
M
MongoDB replica sets
Cassandra replication
60. The future is polyglot
IEEE Software Sept/October 2010 - Debasish Ghosh / Twitter @debasishg
61. Polyglot persistence architecture
accounting application
Accounting
Service MySQL
storefront web application inventory application
StoreFrontUI InventoryService Redis
shipping application
ShippingService Mongo
62. Spring Data = simplifying data
access
• Redis
• MongoDB
• Neo4j
• JPA
• REST
• Apache Hadoop
• Gemfire
http://www.springsource.org/spring-data
63. Agenda
• The (sometimes evil) monolith
• Refactoring to a modular, polyglot architecture
• Presentation layer design
• Using NoSQL databases
• Inter-service communication options
64. Inter-service communication
options
• Synchronous HTTP asynchronous AMQP
• Formats: JSON, XML, Protocol Buffers, Thrift, ...
• JSON is fashionable and easier to debug
• Binary format is more efficient
65. Asynchronous message-based communication
wgrus-billing.war
Accounting
Service
wgrus-store.war wgrus-inventory.war
RabbitMQ
StoreFrontUI (Message InventoryService MySQL
Broker)
wgrus-shipping.war
ShippingService
66. Benefits
• Decouples caller from server
• Caller unaware of server’s coordinates (URL)
• Message broker buffers message when server is down/slow
• Supports a variety of communication patterns
67. Drawbacks
• Additional complexity of message broker
• Request/reply using messaging is more complex
• Firewall unfriendly
68. Spring AMQP
• Encapsulates low-level Producer Consumer
details
• Simplifiessending and Amqp Listener
receiving of messages Template Container
Spring AMQP
AMQP
69. Spring Integration
• Provides the building blocks for a pipes and
filters architecture
• Enables development of application
components that are
• loosely coupled
• insulated from messaging infrastructure
• Messaging defined declaratively
70. Development time: same JVM
@Service
public class OrderServiceImpl {
@Service
public class ShippingServiceImpl {
@Autowired
private ShippingService shippingService;
public void shipOrder(String orderId) {
....
public void placeOrder() {
}
String orderId = generateOrderId();
…
}
shippingService.shipOrder(orderId);
}
}
Order Shipping
Service service
shipOrder()
Messaging
Gateway
Channel Service
Activator
71. Test and production: distributed
Application code is
unchanged
Order Shipping
Service service
Messaging
Gateway RabbitMQ
Channel AMQP AMQP Channel Service
Activator
72. Synchronous REST
wgrus-billing.war
Accounting
Service
wgrus-store.war REST wgrus-shipping.war
StoreFrontUI Shipping MySQL
Service
wgrus-inventory.war
...
InventoryService
73. Pros and cons of REST
• Pros • Cons
• Simple and familiar • Only supports request/
reply
• Request/reply is easy
• Server must be available
• Firewall friendly
• Clientneeds to know
• No intermediate broker URL(s) of server(s)
75. Not all APIs are RESTful
From http://martinfowler.com/articles/richardsonMaturityModel.html
76. About Hypertext As The
Engine Of Application State
• Single well known URL
• Entity representation has typed relationship links
• Client discovers what it can do to an entity via those links
See http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
77. About HATEOAS
The well known
URL
$ curl http://cf-auto-scaler.cloudfoundry.com
{"links": [
{"rel":"autoscaledapps", "href":"http://cf-auto-scaler.cloudfoundry.com/autoscaledapps"}
]}
Link
link type
$ curl http://cf-auto-scaler.cloudfoundry.com/autoscaledapps
{"content":[
{"name":"vertx-clock",
"links":[
{"rel":"self","href":"http://cf-auto-scaler.cloudfoundry.com/autoscaledapps/vertx-clock"},
{"rel":"rules","href":"http://cf-auto-scaler.cloudfoundry.com/autoscaledapps/vertx-clock/rules"}
]
}],
... Links to act on this app
}
78. Spring HATEOAS
@Controller
@RequestMapping(value = "/autoscaledapps")
public class AutoscaledAppController {
@RequestMapping(value = "/{appName}", method = RequestMethod.GET)
public HttpEntity<AutoscaledAppResource> get(@PathVariable String appName) {
AutoscaledAppResource ar = new AutoscaledAppResource(appName);
ar.add(linkTo(AutoscaledAppController.class)
.slash(appName).withSelfRel());
ar.add(linkTo(AutoscaledAppController.class)
.slash(appName).slash("rules").withRel("rules"));
return new HttpEntity<AutoscaledAppResource>(ar);
}
... public class AutoscaledAppResource
} extends ResourceSupport {
private String name;
https://github.com/SpringSource/spring-hateoas
80. The Spring REST shell
$ rest-shell
http://localhost:8080:> baseUri http://cf-auto-scaler.cloudfoundry.com
http://cf-auto-scaler.cloudfoundry.com:> discover
rel href
=======================================================================
autoscaledapps http://cf-auto-scaler.cloudfoundry.com/autoscaledapps
http://cf-auto-scaler.cloudfoundry.com:> follow --rel autoscaledapps
http://cf-auto-scaler.cloudfoundry.com/autoscaledapps:> post --from src/test/resources/examplejson/createapp1.json
--follow true
1 files uploaded to the server using POST
http://cf-auto-scaler.cloudfoundry.com/autoscaledapps/vertx-clock:> discover
rel href
================================================================================
self http://cf-auto-scaler.cloudfoundry.com/autoscaledapps/vertx-clock
rules http://cf-auto-scaler.cloudfoundry.com/autoscaledapps/vertx-clock/rules
http://cf-auto-scaler.cloudfoundry.com/autoscaledapps/vertx-clock:> follow --rel rules
http://cf-auto-scaler.cloudfoundry.com/autoscaledapps/vertx-clock/rules:> post
--from src/test/resources/examplejson/createrule1.json --follow true
1 files uploaded to the server using POST
http://cf-auto-scaler.cloudfoundry.com/autoscaledapps/vertx-clock/rules/idle:> up
http://cf-auto-scaler.cloudfoundry.com/autoscaledapps/vertx-clock/rules:> up
81. Original architecture
WAR
StoreFrontUI
Accounting
Service
MySQL
Browser Apache Database
InventoryService
Simple to Shipping
Service
develop
test Tomcat
deploy
scale
82. Modular, polyglot architecture
Desktop Browser Native Mobile application HTML5 mobile application
oy
StoreUI StoreUI StoreUI
pl
NodeJS
!?! e
Asynchronous, NodeJS Javascript
scalable
is d
StoreUI
communication
th we
RabbitMQ
Spring/Scala
do
web application Inventory Standalone
Inventory Shipping Service
Service Shipping “headless”
Service
Spring
ow
Integration/Java
applications
Billing Service Redis Inventory Mongo Order
H
Database Database
MySQL
Customer
Database
83. OSS community
vFabric
Postgres Ap
Private
Clouds
p
Data Services
lica
'o
n
S
vFabric
Public
erv
RabbitMQTM
ice
Msg Services
Clouds
In
ter
fac
Micro
e
Other Services
Clouds
Additional partners services …
87. Summary
• Modern applications have a modular, polyglot
architecture
• Springis the ideal technology for building these
applications
• Cloud Foundry is the ideal way to deploy these
applications