architecting for microservices part 2
TRANSCRIPT
Architecting for Microservices Part 2
Denver Code Club Meetup Bill Schwanitz, Technical ArchitectDecember 15, 2016 Craig Martin, Vice President of Engineering
Agenda
•Microservices (isn’t that what we are here for?)
• What is a microservice?•NETFLIX OSS
• Zuul• Eureka• Hystrix• Archaius
•Million Song Library code walkthrough•Build Million Song Library
An overview of Microservices
• N number of modular components joined together via the network.
• Decomposed by units of business or functionality• Combined makes up an entire backend system• Single Responsibility Principle (SRP)
• Code with a singleness of purpose• Interface Segregation Principle (ISP)
• No client should be forced to depend on methods it does not use
• Service grouped by business domain area or capability
• Many standalone “vertical” stack focused on a single domain
• Netflix OSS• “Gatekeeper”
RoutingMonitoringSecurity
• Makes endpoints available• Main use cases
Auth-N (not Auth-z)DDOSTransformation
• Groovy and JavaFilters in Groovy
Zuul
Challenges• Performance• Forgetting to open endpoints• Logging
• “Pre” filter - First line of defence Check URL (Sitemap)Auth-NStructure Data Transformation
• “routing” filtersEndpoint Mapping Service Discovery
• “post” filtersData transformationlogging
• “static” filtersHealthcheck
References:
MSL server/msl-zuul:github.com/kenzanlabs/msl-
zuul/tree/master/src/main/groovy/filters
Zuul - How does it work?
Lessons Learned• Keep it
lightweight• Can be used for
soaking
Other Options• NginX• ELBs• API
Gateway
• Netflix OSS Service Registry
• Used for “discovery”• Heartbeat of the
application• Why not use ELBs?
Fewer IPsCompromise Security
GroupsStateless
• Replicated across regions• Load balancing• “Push” heartbeat
monitoring
Eureka
Challenges• Only works with
AWS• Performance• Scalability
Other Options• Containerizatio
n (Kubernetes)• Consul• ELBs
What is it?
• Eureka ClientRegisters with Eureka ServerPart of the bootstrap processRoutinely updates
• Eureka ServerMaintains mapping of VIPs to
IPsRedundancyRound Robin Load BalancingNetflix OSS Service Registry
• Typically abstract discovery via Ribbon Client
Best Practices• Discovery shouldn’t be a dev
responsibility• Single point of failure • Scale “correctly”
Eureka How it works.
Hystrix - What is it?Controls the interactions between distributed services, by:
• Adding latency tolerance logic
• Adding fault tolerance logic
• Isolating points of access between the services
• Stopping cascading failures across them
• Providing fallback options
Hystrix - Why?Compared to Monolithic applications, Microservices strongly rely upon networks.
So failure detection and manipulation logic is essential.
Normal function (Closed)
When a system is functioning smoothly
Failure state (Open)
At this juncture, every call to the dependency is short-circuited with a HystrixRuntimeException, giving clear indication of its cause.
Half-open state
Once the sleep Interval passes, Hystrix checks system availability, letting other requests fail-fast until the response is obtained. If the call is successful, go to Closed; in case of failure, go back to Open
Hystrix - How?● Wrapping all external calls in a HystrixCommand or HystrixObservableCommand ● Timing-out calls when needed.● Maintaining a small thread-pool for each dependency (monitor load)● Measuring successes, failures , timeouts, and thread rejections.● Tripping a circuit-breaker to stop all requests to a particular service for a period of time● Performing fallback logic when a request fails, is rejected, times-out, or short-circuits.● Monitoring metrics and configuration changes in near real-time.
For Additional information: https://github.com/Netflix/Hystrix/wiki/How-it-Works
ArchaiusJava library that provides APIs to access and utilize properties that can change dynamically at runtime. It includes the following features:
● Dynamic, Typed Properties
● High throughput and Thread Safe Configuration operations
● A polling framework that allows users to obtain property changes to a Configuration Source
● Allows retrieval of properties from local properties files or a properties server
○ Darchaius.configurationSource.additionalUrls=file:///apps/myapp/application.properties
○ Darchaius.configurationSource.additionalUrls=http://myserver/properties
● Automatically updates to all servers
Million Song Library
• Java 8• Netflix OSS (Eureka, Hystrix,
Zuul, Archaius)• Datastax (Cassandra)• Swagger
Backend Tech
Platform Tech• Maven • Docker• Spinnaker
Documentation Tech• Swagger• Ascii Docs
Time to Look at Some Code
Netflix OSS• Zuul• Eureka• Hystrix• Archaius
Zuul - Example of Zuul Configuration - pom.xml• In MSL, we configure Zuul
via the pom.xml and Archaius properties
• So here you see the pom.xml:
Zuul runs in jettyWe can supply
additional configuration via Archaius
Zuul will listen on port 9000
Example:<plugin> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <version>${jetty-version}</version> <configuration> <systemProperties> <systemProperty> <name>archaius.deployment.applicationId</name> <value>zuul</value> </systemProperty> </systemProperties> . . . <httpConnector> <port>9000</port> </httpConnector> </configuration></plugin>
References:github.com/kenzanlabs/msl-zuul
Zuul - Example of Zuul Configuration - properties• In MSL, we configure Zuul
via the pom.xml and Archaius properties:
Locations of the pre, routing and post filters
Allowable and default clients
Configuration for one of those clients
• And an example of a URLNotice it goes to port
9000Has the client name
loginedgeThen the rest of the URL
is the URI to the client
• So Zuul redirects this request to login-edge:9001
Properties:zuul.filter.pre.path=src/main/groovy/filters/prezuul.filter.routing.path=src/main/groovy/filters/routezuul.filter.post.path=src/main/groovy/filters/post
zuul.niws.clientlist=loginedge|accountedge|catalogedge|ratingsedge
loginedge.zuul.client.DeploymentContextBasedVipAddresses=msl.login.edgeloginedge.zuul.client.Port=9001
Example URL:https://msl.kenzanlabs.com:9000/loginedge/login
References:github.com/kenzanlabs/msl-zuul/tree/master/src/main/resources
Eureka Example• Registration
Tell Eureka Server that a new instance of a microservice has started
Needs eureka properties
Needs Karyon to be instantiated
Handles routine heartbeat from client to server
• HealthcheckAllows Eureka Server
to check if instance is still up and running
Eureka Server will remove any down instance
Properties:eureka.name=loginedgeeureka.vipAddress=msl.login.edgeeureka.port=9001eureka.serviceUrl.default=http://localhost:8080/eureka/v2/eureka.region=defaulteureka.preferSameZone=trueeureka.registration.enabled=true
Karyon Startup:KaryonServer server = new KaryonServer();server.start();
Healthcheck ReST Endpoint:@Path("/healthcheck") public class HealthCheckResource { @GET @Produces(MediaType.APPLICATION_JSON) public Response healthcheck() { return Response.status(Response.Status.OK).build(); } }
Hystrix example
Setup• Create a subclass of
HystrixCommand• The command group key
groups commands for configuration, thread pooling, etc.
• Override the run() method• Optionally override the
getFallback() method
Calling• Instantiate your command
class• Call its execute() method
Code:class ValidateAccountCommand extends HystrixCommand<Boolean>{ private Account account;
protected ValidateAccountCommand(Account account) { super(Setter.withGroupKey(HystrixCommandGroupKey.Factory .asKey("validateAccount"))); this.account = account; }
@Override protected Boolean run() throws Exception { return AccountValidator.isValid(account); }
@Override protected Boolean getFallback() { return false; }}
public Boolean save(Account account) throws Exception { return (new ValidateAccountCommand(account).execute());}
Archaius Example• Configuration
Declare the properties source(s)
Can be a local file or a properties server
• UseProperties are typed
BooleanIntLongStringetc.
Only need to declare the DynamicXProperty once
Then just use x.get() whenever you need to use the value
Calling x.get() once and storing the result is an anti-pattern - doesn’t allow for dynamic reconfiguration
Properties:archaius.configurationSource.additionalUrls= file://msl-login-edge-config/edge-config.propertiesorarchaius.configurationSource.additionalUrls=http://myserver/properties
Code:static final DynamicLongProperty timeToWait = DynamicPropertyFactory .getInstance().getLongProperty("msl.sleep", 100);
void foo() { long t = timeToWait.get(); sleep(t)}
Anti-pattern:static final long t = DynamicPropertyFactory .getInstance().getLongProperty("msl.sleep", 100).get();
void foo() { sleep(t)}
Why?• The API is described in one place,
a yaml formatted file (can also be described using annotations in an existing Java file)
• From the yaml file, swagger tools generate client and server code stubs, and documentation
• Since code and documentation are created from the same yaml file, the code and the documentation will never diverge
Swagger - What?A specification and associated tools for describing, producing, consuming, and visualizing a ReST API
YAML File:
.
.
./catalog-edge/browse/album: x-swagger-router-controller: catalog_controller get: description: "Get browsing data for albums in the catalog" tags: - Catalog operationId: browse_albums parameters: - $ref: "#/parameters/PagingState" - $ref: "#/parameters/Items" - $ref: "#/parameters/Facets" responses: "200": description: Success schema: $ref: "#/definitions/AlbumList" "400": description: “Invalid pagingState or facet”...
Yaml Details• First line defines the URI path to
the endpoint• tags: grouping endpoints for docs• x-swagger-router-controller: the
name of the Node controller file• operationId: name of the function
in server stub• parameters: optional path and
query parameters
Swagger - Generated Server Stub
CatalogEdgeApi.java@Path("/catalog-edge")@Consumes({ "application/json" })@Produces({ "application/json" })public class CatalogEdgeApi {
private final CatalogEdgeApiService delegate = CatalogEdgeApiServiceFactory.getCatalogEdgeApi();
@GET @Path("/browse/album") @Consumes({ "application/json" }) @Produces({ "application/json" }) public Response browseAlbums( @QueryParam("items") Integer items, @QueryParam("pagingState") String pagingState, @QueryParam("facets") String facets) ) throws NotFoundException { return delegate.browseAlbums(items,pagingState,facets); } ...}
CatalogEdgeApiService.javapublic abstract class CatalogEdgeApiService { public abstract Response browseAlbums(Integer items,String pagingState,String facets) throws NotFoundException;}
MSL Local Installation
Prerequisites● git installed● personal git account created
CD to where you want to install itcd ~
Retrieve the main MSL repository from githubgit clone https://github.com/kenzanmedia/million-song-library
CD into the new directorycd million-song-library/bin
Be sure the setup script is executablechmod +x setup.sh
Run the setup script./setup.sh
Want to learn more?Follow us!
@kenzanmedia
www.linkedin.com/company/kenzan-media
techblog.kenzan.com
www.facebook.com/kenzanmedia/