Using Hystrix to daemonize the application (3)

Monitor HystrixCommand

In addition to isolating the calls of dependent services, Hystrix also provides near real-time monitoring. Hystrix will record all the execution information about HystrixCommand in real time, including how many requests are executed per second, how many successes, how many failures, etc. For more metrics, check out: https://github.com/Netflix/Hystrix/wiki/Metrics-and-Monitoring

Export monitoring data

With these metrics, Netflix also provides a class library ( hystrix-metrics-event-stream: https://github.com/Netflix/Hystrix/tree/master/hystrix-contrib/hystrix-metrics-event-stream ) to put These metrics information is open to external use in the format of 'text/event-stream'. The usage is very simple. First, add the hystrix-metrics-event-stream library to the project:

dependencies {
    compile(
    		 ...
            'com.netflix.hystrix:hystrix-metrics-event-stream:1.3.9',
            ...
    )
}

Then, configure a servlet in web.xml to get the data provided by Hystrix:

<servlet>
  <description></description>
  <display-name>HystrixMetricsStreamServlet</display-name>
  <servlet-name>HystrixMetricsStreamServlet</servlet-name>
  <servlet-class>com.netflix.hystrix.contrib.metrics.eventstream.HystrixMetricsStreamServlet</servlet-class>
    </servlet>
    <servlet-mapping>
  <servlet-name>HystrixMetricsStreamServlet</servlet-name>
  <url-pattern>/hystrix.stream</url-pattern>
    </servlet-mapping>

Once configured, restart the application. Visit http://hostname:port/appname/hystrix.stream, you can see the following output:

data: {"type":"HystrixCommand","name":"Address","group":"Address","currentTime":1393154954462,"isCircuitBreakerOpen":false,"errorPercentage":0,"errorCount":0,"requestCount":0,"rollingCountCollapsedRequests"......

The system will continuously refresh to obtain real-time data.

Dashboard

As can be seen from the above output, the readability of such pure character output is too poor, and it is difficult for operation and maintenance personnel to see the current state of the system, so Netflix has developed an open source project (Dashboard: https://github. .com/Netflix/Hystrix/wiki/Dashboard ) to visualize these data and help operation and maintenance personnel to understand the current state of the system more intuitively. Dashboard is very convenient to use, it is a web project, you only need to put the war package ( http: //search.maven.org/#browse%7C1045347652 ) Download it and put it in a web container (Tomcat, Jetty, etc.).

Start WebContainer to access the Dashboard home page, you can see the following interface:

Fill in the URL above to get hystrix.stream, click Monitor, you can see the real-time monitoring screen:

Dashboard mainly displays two types of information. One is the execution of HystrixCommand. The Hystrix Wiki details the meaning of each indicator on the graph:

The second is the status of the thread pool, including the thread pool name, size, the current active thread, the maximum number of active threads, the size of the queue, etc.

Turbine

In a complex distributed system, hundreds or even thousands of nodes of the same service often need to be deployed. In many cases, operation and maintenance personnel hope to display the node status of the same service in the form of an overall cluster, which can better grasp the state of the entire system. To this end, Netflix also provides an open source project (Turbine) to provide aggregation of multiple hystrix.stream content into a data source for Dashboard display.

Turbine has two usages, one is to embed Turbine into your project; the other is to treat Turbine as an independent Module. Regardless of the usage, the configuration files are the same. Turbine will look for the configuration file in the classpath by default: config.properties, which will configure:

1. Which clusters are Turbine monitoring: turbine.aggregator.clusterConfig=cluster-1, cluster-2

2. How Turbine obtains node monitoring information (hystrix.stream): turbine.instanceUrlSuffix.<cluster-name> = :/HystrixDemo/hystrix.stream

3. Which nodes are under the cluster: turbine.ConfigPropertyBasedDiscovery.cluster-1.instances=localhost:8080,localhost:8081

The above are the simplest configuration methods Turbine uses another Netflix open source project Archaius ( https://github.com/Netflix/archaius ) for configuration file management, which provides a very powerful configuration file management strategy, Students in need can study it in depth ( https://github.com/Netflix/Turbine/wiki/Configuration ).

The steps to use Turbine are generally as follows:

1. Download Turbine.war (https://github.com/downloads/Netflix/Turbine/turbine-web-1.0.0.war ) and place it in a web container .

2. Create a configuration file config.properties in the WEB-INF/classes directory of the Turbine project:

3. Start Turbine service

4. Fill in the stream provided by the Tubine project in the Dashboard project: http://hostname:port/turbine/turbine.stream can also add the ?cluster=<cluster-name> parameter to monitor only a certain Cluster. The indicators displayed on the Dashboard It's the same as before, except that the data is already aggregated.

Add Hystrix for legacy systems

Finally, let's see how to add Hystrix support to the application without changing the existing code. In the Spring world, the best solution to add functionality without changing the existing code is aop, or use the above example, Assuming that there is already a Customer Service, Customer Service will call ContactDao and AddressDao to obtain Contact and Address information. as follows:

public Customer getCustomerThroughDao(String customerId) {
  logger.info("Get Customer {}", customerId);
  try {
      Customer customer = new Customer(customerId, "xianlinbox");
      customer.setContact(contactDao.getContact(customerId));
      customer.setAddress(addressDao.getAddress(customerId));
      return customer;
  } catch (Exception e) {
      e.printStackTrace ();
  }
  return null;
    }
public class AddressDao {
    private Logger logger = LoggerFactory.getLogger(AddressDao.class);
    public Address getAddress(String customerId) throws IOException {
  logger.info("Get address for customer {}", customerId);
  String response = Request.Get("http://localhost:9090/customer/" + customerId + "/address")
    .connectTimeout(1000)
    .socketTimeout(1000)
    .execute()
    .returnContent()
    .asString();
  return new ObjectMapper().readValue(response, Address.class);
    }
}
public class ContactDao {
    private Logger logger = LoggerFactory.getLogger(ContactDao.class);
    public Contact getContact(String customerId) throws IOException {
  logger.info("Get contact for customer {}", customerId);
  String response = Request.Get("http://localhost:9090/customer/" + customerId + "/contact")
    .connectTimeout(1000)
    .socketTimeout(1000)
    .execute()
    .returnContent()
    .asString();
  return new ObjectMapper().readValue(response, Contact.class);
    }
}

Let's take a look at how to encapsulate ContactDao and AddressDao into HystixCommand without changing the existing code. First, create HystrixComnandAdvice, which will create a HystrixCommand, and then encapsulate the aspect into the HystrixCommand:

public class HystrixCommandAdvice {
  private String groupName;
  private String commandName;
  public Object runCommand(final ProceedingJoinPoint pjp) {
    return wrapWithHystrixCommnad (pjp) .execute ();
  }
  private HystrixCommand<Object> wrapWithHystrixCommnad(final ProceedingJoinPoint pjp) {
    return new HystrixCommand<Object>(setter()) {
      @Override
      protected Object run() throws Exception {
        try {
          return pjp.proceed ();
        } catch (Throwable throwable) {
          throw (Exception) throwable;
        }
      }
      @Override
      protected Object getFallback() {
        return null;
      }
    };
  }
  private HystrixCommand.Setter setter() {
    return HystrixCommand.Setter
        .withGroupKey(HystrixCommandGroupKey.Factory.asKey(groupName))
        .andCommandKey(HystrixCommandKey.Factory.asKey(commandName));
  }
  public void setGroupName(String groupName) {
    this.groupName = groupName;
  }
  public void setCommandName(String commandName) {
    this.commandName = commandName;
  }
}

Then, you only need to configure the example of this class for ContactDao and AddressDao:

<bean id="contactDaoCommand" class="com.xianlinbox.hystrix.dao.HystrixCommandAdvice">
    <property name="groupName" value="Contact"/>
    <property name="commandName" value="Contact"/>
  </bean>
  <bean id="addressDaoCommand" class="com.xianlinbox.hystrix.dao.HystrixCommandAdvice">
    <property name="groupName" value="Address"/>
    <property name="commandName" value="Address"/>
  </bean>
  <aop:config>
    <aop:aspect id="contactServiceAspect" ref="contactDaoCommand">
      <aop:pointcut id="contactServiceTarget"
              expression="execution(* com.xianlinbox.hystrix.dao.ContactDao.getContact(..))"/>
      <aop:around method="runCommand" pointcut-ref="contactServiceTarget"/>
    </aop:aspect>
  </aop:config>
  <aop:config>
    <aop:aspect id="addressServiceAspect" ref="addressDaoCommand">
      <aop:pointcut id="addressServiceTarget"
              expression="execution(* com.xianlinbox.hystrix.dao.AddressDao.getAddress(..))"/>
      <aop:around method="runCommand" pointcut-ref="addressServiceTarget"/>
    </aop:aspect>
  </aop:config>

The system behavior of this example is exactly the same as the previous build using HystrixCommand directly.

Summarize

From the content involved in the full text, it is not difficult to see that Netflix has built a complete Hystrix ecosystem, which makes Hystrix very easy to use, and has a lot of configuration options and advanced usage to meet the individual needs of different systems. For such a tool, I believe every developer will like it. In addition, I can't help but admire Netflix for turning its own experience into a tool for the benefit of the entire community.

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326746742&siteId=291194637