MICROSERVICES WITH JBOSS EAP / OPENSHIFT - Red Hat · Advantages of Microservices Faster and...
Transcript of MICROSERVICES WITH JBOSS EAP / OPENSHIFT - Red Hat · Advantages of Microservices Faster and...
MICROSERVICES WITH JBOSS EAP / OPENSHIFT
Babak Mozaffari, Consulting Software EngineerDiogenes Rettori, Principal Product ManagerJune 2016
Microservice Architecture
Define Microservice Architecture
● Software architectural style● Applications as a suite of small services● Each an independent process, in its own logical machine● Built around capabilities, single responsibility principle● Can independently replace / upgrade / scale / deploy services● Standard lightweight communication● Potentially heterogeneous environments are supported
Advantages of Microservices
● Faster and simpler deployment and rollback with smaller services● Ability to horizontally scale out individual services● Selecting the right tool, language and technology per service● Better ability to plan for fault isolation and avoiding chain failure● Continuous Delivery and Integration comes included● DevOps culture, higher service self-containment, less infrastructure maintenance● More autonomous teams, faster/better development.● Traditional divide and conquer benefits● A/B testing & canary deployments
Disadvantages of Microservices
● Less tooling / IDE support given the distributed nature● Tracing and monitoring becomes more complicated● QA, particularly integration testing can be difficult● Debugging is always more difficult for distributed systems● Higher complexity – higher fixed cost and overhead● Heterogenous environments are difficult and costly to maintain● Network reliability is always a challenge
Why Now?
● Global user base for software as a result of technological progress● Businesses demanding ever-greater agility● Cloud computing is cheaper and more widely available● DevOps, agile movement has made continuous integration and delivery common● Simply current iteration of applying the best practices of the past
What's Too Modular?
● The number of developers, between 5 and 10 per team?● Comfortable on the cutting edge of technology?● DevOps, not every organization is prepared for the required cultural change● How skilled are you at troubleshooting?● Can you afford higher up-front costs?● Can your network support the architecture?
Monolithic Applications
● Some Microservices advocates use the term monolithic disparagingly● We reserve judgement, it is the result of legitimate trade-offs● Preferable for certain situations and not for others● May be just as modular as microservices, but typically bundled as one unit● Example, a single EAR or WAR file deployed on a single application server● Modules take advantage of the same infrastructure● Maximize efficiency by minimize network traffic and latency● Sometimes even possible to pass arguments by reference
Monolithic Application
Monolithic Application, Clustered
Tactical Microservices
● Selectively embrace cost/benefits of microservices● Avoid proactively decomposing the application into microservices● Take advantage of common infrastructure/environment uniformity● Identify and extract microservices based on goals
Tactical Microservices
Tactical Microservices, HA
Strategic Microservices
● Fully embrace microservices and its costs/benefits● Decompose entire applications into microservices● Implement entire systems as separately deployed microservices
Strategic Microservices
Strategic Microservices, HA
Business-Driven Microservices
● Microservices, many real benefits, but with real costs● System complexity can grow exponentially with distributed components● Modularity of the services can determine the complexity● API Gateway Pattern, often with a bit of orchestration● Individual services rarely depend on one another
Business-Driven Microservices
Cross-Cutting Concerns
● Containerization● Service Discovery● Load Balancer● Cache● Throttling, Circuit Breaker, Composable Asynchronous Execution● Security● Monitoring and Management● Resilience Testing
Anatomy of a Microservice
● Microservice design and development not covered by architectural style description● Allowing choice for the developers of each microservice is a stated goal● Individual microservices largely resemble other enterprise software components● Each microservice will have its own significant dependencies and technical
requirements:– Persistence, database connection pooling, connection management– External dependencies, integration with legacy systems– Authentication and authorization, declarative security– Transactional behavior within the service
● Common enterprise requirements, leading to application servers / frameworks
JBoss EAP / OpenShift Enterprise
Red Hat JBoss Enterprise Application Platform 7
● Java EE 7– WebSockets– JSON– HTML5– Batch processing
● Lightweight, fast to startup, optimized for cloud and containers● Full Java EE across all environments – on-premise, virtual, cloud ● Rock solid reliability, stability, scalability● Security and compliance, including Common Criteria Certification
Integration ServicesBy JBoss Fuse
JBoss Application Services
Real time Decision ServiceBy JBoss BRMS
In Memory Data GridBy JBoss Data Grid
Messaging ServicesBy JBoss A-MQ
Java EE Application ServerBy JBoss EAP
TomcatBy JBoss Web Server
JBoss EAP for OpenShift
JBoss Data Grid for OpenShift
Fuse Integration Services
JBoss A-MQ for OpenShift
JBoss BRMS for OpenShift
JBoss BPM Suite for OpenShift
Integration ServicesBy JBoss Fuse
JBoss Application Services
Real time Decision ServiceBy JBoss BRMS
In Memory Data GridBy JBoss Data Grid
Messaging ServicesBy JBoss A-MQ
Java EE Application ServerBy JBoss EAP
TomcatBy JBoss Web Server
Single Sign On by RH SSO
Intelligent Process ServerBy JBoss BPM Suite
Red Hat SSO for OpenShift
Red Hat SSO for OpenShift
Red Hat SSO for OpenShift
Red Hat SSO for OpenShift
Red Hat SSO for OpenShift
Red Hat SSO for OpenShift
Red Hat SSO for OpenShift
Integration ServicesBy JBoss Fuse
JBoss Application Services
Real time Decision ServiceBy JBoss BRMS
In Memory Data GridBy JBoss Data Grid
Messaging ServicesBy JBoss A-MQ
Java EE Application ServerBy JBoss EAP
TomcatBy JBoss Web Server
Single Sign On by RH SSO
Intelligent Process ServerBy JBoss BPM Suite
API Management
Access Control Rate Limiting Developer Portal
Billing and Payments API DocumentationAnalytics
https://www.3scale.net/redhat-integration
Design and Development
Reference Application: Technology
● JBoss EAP 7– Java SE 8, Java EE 7– Java Persistence API (JPA)– JAX-RS 2.0– Concurrency API
● Maven● OpenShift Enterprise 3.2
– Docker / Kubernetes– Containerization, Service Discovery, Load Balancer, etc
Reference Application: Use Case
● Online Shopping example application● Customer interface is a simple Web App / API Gateway, called presentation● Core functionality implemented as 3 microservices:
– Product microservice: product catalog and availability– Sales microservice: customers and orders– Billing microservice: payment proxy service
● Product and sales each rely on their own database service
Data Model using JPA
Basic JPA Entity
● Annotate Java class as JPA Entity:
@Entity
public class Product
● Define fields and JavaBean accessors:
private String name;
private String description;
...
private Boolean featured;
private Integer availability;
private BigDecimal price;
private String image;
JPA Features
● Designate a primary key and allow the database to generate its value:
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long sku;
● Declare a named query to allow easy efficient access to data:
@NamedQuery(name = "Product.findFeatured",query = "SELECT p FROM Product p WHERE p.featured = true")
● Also annotate the class as a JAXB bean, to get XML/JSON marshaling:
@XmlRootElement
JPA Relationships
● Bidirectional many to many relationship, owning side:
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "PRODUCT_KEYWORD",
joinColumns = @JoinColumn(name = "SKU", referencedColumnName = "SKU"),
inverseJoinColumns = @JoinColumn(name = "KEYWORD",
referencedColumnName = "KEYWORD"))
private List<Keyword> keywords;
● Non-owning side:
@ManyToMany(fetch = FetchType.EAGER, mappedBy = "keywords")
private List<Product> products;
JPA Configuration
● Configure persistence.xml:
<persistence-unit name="primary">
<jta-data-source>java:jboss/datasources/ProductDS</jta-data-source>
<properties>
<!-- Properties for Hibernate -->
<property name="hibernate.hbm2ddl.auto" value="update" />
<property name="hibernate.show_sql" value="true" />
<property name="hibernate.dialectvalue="org.hibernate.dialect.MySQLDialect" />
</properties>
</persistence-unit>
OpenShift Database Service
OpenShift Enterprise Database Images
● This sample application uses database services built on the supported MySQL image● Single command to build a database instance and configure it:
oc new-app -e MYSQL_USER=product,MYSQL_PASSWORD=password,\
MYSQL_DATABASE=product,\
MYSQL_ROOT_PASSWORD=passwd \
mysql --name=product-db
REST with JAX-RS 2.0
Enabling JAX-RS Support
● Enable JAX-RS services in a web application by configuring its descriptor:
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<servlet-mapping>
<servlet-name>javax.ws.rs.core.Application</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
Creating JAX-RS Services
● Annotate Java class to create a JAX-RS service listening on a certain path:
@Path("/")
public class ProductService● Create an annotated Java method for each service operation● Each operation has its own path● Service operation address is comprised of the multiple paths leading to it:
– Application Context / JAX-RS Servlet / JAX-RS Service Path / Operation Path● Specify HTTP method for each operation with annotations● Annotate operation with request and response media type
Sample JAX-RS Operation
● To add a product by posting it as either JSON or XML:
@Path("/products")
@POST
@Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Product addProduct(Product product)
{
● The response is also returned as either JSON or XML● With JAX-RS servlet url pattern of /* and service path of /, this operation is accessible
at http://host:port/application/products
JAX-RS interaction with JPA
● JPA persistence may require a transactional context● Easier to rely on the container, then to leverage user transactions● Any class annotated as a REST service can also be a stateless session bean:
@Path("/")
@Stateless
@LocalBean
public class ProductService
● An entity manager can then be injected:
@PersistenceContext
private EntityManager em;
Error Handling
● Standard HTTP codes along with descriptive information to communicate errors● For example, return HTTP error code 422 when request is invalid:
throw new WebApplicationException( 422 );
● To return error description details, use a JAXB class:
@XmlRootElement
public class Error
{
private int code;
private String message;
private String details;
Error Handling
● Communicate errors by throwing WebApplicationException● Provide details by passing a JAX-RS Response to the exception constructor● Build a Response by providing a JAXB object to ResponseBuilder:
ResponseBuilder responseBuilder = Response.status( code );
responseBuilder = responseBuilder.entity( error );
throw new WebApplicationException( responseBuilder.build() );
Resource API Design
● No strict standards govern RESTful service API design● Conventions and common practice promote consistent behavior● Use standard HTTP methods for CRUD capabilities for a resource● Use the plural form of the resource name as the first path of URL● Specific HTTP methods or URL patterns are used for each of the CRUD operation
Create Resource
● Use HTTP POST to add a new resource instance● Receive the resource as the request content● Return the persisted resource, including generated content
@Path("/products")
@POST
@Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Product addProduct(Product product) {
em.persist( product );
return product;
Read Resource / Search
● Use GET against resource URL with potential query parameters:
@GET
@Path("/products")
@Produces({"application/json", "application/xml"})
public Collection<Product> getProducts(@Context UriInfo uriInfo) {
MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters();
if( queryParams.containsKey( "featured" ) )
{
return em.createNamedQuery( "Product.findFeatured"
Product.class ).getResultList();
}
Read Resource / Lookup
● Issue a GET request to resource address and append unique resource identifier● Example: http://host:port/application/products/1001
@GET
@Path("/products/{sku}")
@Produces({"application/json", "application/xml"})
public Product getProduct(@PathParam("sku") Long sku) {
Product product = em.find( Product.class, sku );
if( product == null )
throw new Error( HttpURLConnection.HTTP_NOT_FOUND,
"Product not found" ).asException();
return product;
Update Resource / Full Update
● When updating, the request does not always include every resource attribute● Distinguish between a full and partial update in a RESTful API● One common approach is to use the distinct HTTP methods of PUT and PATCH● For a full update:
@PUT
@Path("/products/{sku}")
@Consumes({"application/json", "application/xml"})
@Produces({"application/json", "application/xml"})
public Product updateProduct(@PathParam("sku") Long sku, Product product)
Update Resource / Partial Update
● No native support for PATCH, so first declare an annotation for this purpose
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@HttpMethod("PATCH")
public @interface PATCH
{
}
● Once declared, simply use PATCH instead of PUT as the annotation● Provide an implementation that ignores any fields missing in JSON or XML request
Delete Resource
● Use the DELETE method to remove a resource, providing a direct link to it:
@DELETE
@Path("/products/{sku}")
@Consumes({"application/json", "application/xml"})
@Produces({"application/json", "application/xml"})
public void deleteProduct(@PathParam("sku") Long sku)
{
Product product = getProduct( sku );
em.remove( product );
}
Sub-Resources
● Orders only exist in the context of customers, so they are modeled as sub-resources● In REST services, address sub-resources within the context of their parent resource.● The CRUD operations are otherwise the same. For example, to delete an order:
@DELETE
@Path("/customers/{customerId}/orders/{orderId}")
public void deleteOrder( @PathParam("customerId") Long customerId,
@PathParam("orderId") Long orderId)
{
...
Java EE Concurrency API
● Java EE 7 introduces ManagedExecutorService for server thread pools● In EAP 7, do a JNDI lookup to get a reference to this service :
ManagedExecutorService executorService =
InitialContext.doLookup( "java:comp/DefaultManagedExecutorService" );
● JBoss EAP 7 can configure to throttle and otherwise optimize managed executor service thread pools.
JAX-RS Asynchronous Processing
● JAX-RS 2.0 introduces async capability for both server and client-side● Annotate operation as Suspended and inject an AsyncResponse:
public void process( final Transaction transaction,
final @Suspended AsyncResponse asyncResponse) {
Runnable runnable = () -> {
Result result = processSync( transaction );
asyncResponse.resume( result );
};
getExecutorService().execute( runnable );
}
JAX-RS Client
● JAX-RS 2.0 introduces a client API● For example, to look up a product with a GET call to the resource API:
Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://product-service").path("/product");
target = target.path("products").path(sku);
Response response = webTarget.request(MediaType.APPLICATION_JSON).get();
If( response.getStatus() < HttpStatus.SC_BAD_REQUEST ) {
Product product = response.readEntity(Product.class);
}
OpenShift Enterprise Deployment
Red Hat xPaaS Images
● Red Hat xPaaS images are configured as image streams in OSE 3:
# oc get imagestreams
NAME DOCKER REPO
...
jboss-eap64-openshift registry.access.redhat.com/jboss-eap-6/eap64-openshift
jboss-eap70-openshift registry.access.redhat.com/jboss-eap-7/eap70-openshift
...
Build & Deploy
● OSE S2I allows source code to be pulled from a git repository, built and deployed● Provide a maven pom.xml file at the root● An optional EAP server configuration file can be provided in the project● Use context-dir if the application code is not at the root of the repository:
oc new-app
jboss-eap70-openshift~https://github.com/RHsyseng/MSA-EAP7-OSE.git
--context-dir=Billing
--name=billing-service
Configure EAP 7 Image
● The name of an OpenShift application is resolved to its address as a hostname● Environment variables may be used to configure a server image● Configure the product service to access the product database image:
oc new-app -e MYSQL_USER=product,MYSQL_PASSWORD=password
jboss-eap70-openshift~https://github.com/RHsyseng/MSA-EAP7-OSE.git
--context-dir=Product --name=product-service
OpenShift Router / Load Balancer
● Hardware load balancers such as the F5 BIG-IP® router can be configured● Alternatively, the provided software HAProxy Router may be used● Expose applications accessed externally to have the router forward requests:
oc expose service presentation –hostname=msa.example.com
● Once a service is exposed, requests pointing to router with the given hostname are routed and load balanced between the replicas of the intended service
Application Homepage