- edge server (responds to requests from RSS clients and gets feeds from middle-tier server)
- middle-tier server (pulls RSS feeds from content providers)
- services registry (eureka)
How to Build
RSS middle-tier and edge servers can be built and run using instructions provided here:
Eureka can be built using instructions here:
How to Run
Follow instructions here:
Note that:
- Default configuration requires that eureka be running on port 80, which would require you to launch the tomcat using sudo (as well as modify server.xml).
- Eureka services registry may be persisted using cassandra, or in-memory without using cassandra. The default is to use the in-memory persistence.
- Eureka by default is configured to talk to AWS, and there will be exceptions during start up if AWS properties aren't configured – however these exceptions may be safely ignored.
At the end the application is running at
Application Architecture
Deployment
There are 3 processes
- Eureka is running in tomcat container.
- RSS middle-tier is running in jetty container
- port 9191 is netty server port# Netty Configuration
netty.http.port=9191
netty.http.host=0.0.0.0 - port 9192 is healthcheck server port# Health Check Handler
com.netflix.karyon.health.check.handler.classname=com.netflix.recipes.rss.manager.MiddleTierHealthCheckHandler
netflix.platform.admin.resources.port=9192
com.netflix.karyon.unify.health.check.with.eureka=true
- port 9191 is netty server port
- RSS edge server is running in jetty container
- port 9090 is jetty port (this is the server user interacts with via browser http://localhost:9090/jsp/rss.jsp)# Jetty Configuration
jetty.http.port=9090 - port 9092 is healthcheck server port# Health Check Handler
com.netflix.karyon.health.check.handler.classname=com.netflix.recipes.rss.server.EdgeHealthCheckHandler
netflix.platform.admin.resources.port=9092
com.netflix.karyon.unify.health.check.with.eureka=true
- port 9090 is jetty port (this is the server user interacts with via browser http://localhost:9090/jsp/rss.jsp)
Middle-tier Server
Class MiddleTierResource.java implements REST Service using jax-ws annotations. Servo metrics are maintained by the same class and registered with servo which exposes them.
Example GET method in AddRSSCommand.java:
@GET
@Path("/rss/user/{user}")
@Produces({MediaType.APPLICATION_JSON})
public Response fetchSubscriptions (final @PathParam("user") String user) {// Start timer
Stopwatch stopwatch = getRSSStatsTimer.start();try {
getRSSRequestCounter.increment();Subscriptions subscriptions = RSSManager.getInstance().getSubscriptions(user);
return Response.ok(subscriptions).build();
} catch (Exception e) {
logger.error("Exception occurred when fetching subscriptions", e);
getRSSErrorCounter.increment();
return Response.serverError().build();
} finally {
stopwatch.stop();
getRSSStatsTimer.record(stopwatch.getDuration(TimeUnit.MILLISECONDS), TimeUnit.MILLISECONDS);
}
}
Communication between edge server and middle tier server. Example: edge server requests subscriptions:
GET /middletier/rss/user/default HTTP/1.1
Netflix.NFHttpClient.Version: 1.0
X-netflix-httpclientname: middletier-client
Host: C02LG18GF1G3.local:9191
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.2 (java 1.5)HTTP/1.0 200 OK
Content-Type: application/json{"subscriptions":[{"items":[{"description":"
Communication between middle-tier server and RSS content servers. Middle-tier server acts as a client and uses ribbon to pull RSS feeds. Example in RSSManager.java:
/**
* Fetch the RSS feed content using Ribbon
*/
private RSS fetchRSSFeed(String url) {RestClient client = (RestClient) ClientFactory.getNamedClient(RSSConstants.MIDDLETIER_REST_CLIENT);
HttpClientResponse response;
String rssData = null;try {
HttpClientRequest request = HttpClientRequest.newBuilder().setUri(new URI(url)).build();
response = client.execute(request);if (response != null) {
rssData = IOUtils.toString(response.getRawEntity(), Charsets.UTF_8);
logger.info("Status code for " + response.getRequestedURI() + " : " + response.getStatus());
}
} catch (URISyntaxException e) {
logger.error("Exception occurred when setting the URI", e);
} catch (Exception e) {
logger.error("Exception occurred when executing the HTTP request", e);
}return parseRSS(url, rssData);
}
Technologies used by application:
- jetty (http/servlet container, e.g. like tomcat)
- jersey (REST services framework)
- netty (NIO client framework)
Edge Server
Acts as a client talking to the middle-tier server, see sample JSON request in the section above.
Each request to the middle-tier server is wrapped in a hystrix command. Example:
/**
* Calls the middle tier Add RSS entry point
*/
public class AddRSSCommand extends HystrixCommand{ // RSS Feed Url (encoded)
private final String url;public AddRSSCommand(String url) {
super (
Setter.withGroupKey(
HystrixCommandGroupKey.Factory.asKey(RSSConstants.HYSTRIX_RSS_MUTATIONS_GROUP))
.andCommandKey(HystrixCommandKey.Factory.asKey(RSSConstants.HYSTRIX_RSS_ADD_COMMAND_KEY))
.andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey(RSSConstants.HYSTRIX_RSS_THREAD_POOL)
)
);
this.url = url;
}@Override
protected String run() {
try {
/*
* The named client param must match the prefix for the ribbon
* configuration specified in the edge.properties file
*/
RestClient client = (RestClient) ClientFactory.getNamedClient(RSSConstants.MIDDLETIER_REST_CLIENT);HttpClientRequest request = HttpClientRequest
.newBuilder()
.setVerb(Verb.POST)
.setUri(new URI("/"
+ RSSConstants.MIDDLETIER_WEB_RESOURCE_ROOT_PATH
+ RSSConstants.RSS_ENTRY_POINT
+ "?url=" + url))
.build();
HttpClientResponse response = client.executeWithLoadBalancer(request);return IOUtils.toString(response.getRawEntity(), Charsets.UTF_8);
} catch (Exception exc) {
throw new RuntimeException("Exception occurred when adding a RSS feed", exc);
}
}@Override
protected String getFallback() {
// Empty json
return "{}";
}
}
JMX
Both the edge server and the middletier server expose JMX metrics (mbeans in package com.netflix.servo).
No comments:
Post a Comment