Netflix Hystrix

repository·master·Indexed 12 days ago

https://github.com/netflix/hystrix

A latency and fault tolerance library designed to isolate points of access to remote systems, services, and 3rd party libraries. It prevents cascading failures in distributed systems using circuit breakers, thread/semaphore isolation, and fallbacks. Includes support for Clojure bindings, Coda Hale Metrics publishing, and Javanica for annotation-based command execution with AspectJ or Spring AOP.

Tokens
19.9K
Snippets
72
Records
85
Agent score
95%

What's inside Hystrix

  1. Understand the purpose of hystrix-contrib submodules

    master

    The hystrix-contrib module serves as a parent container for various Hystrix extension submodules. These submodules provide alternative implementations of core Hystrix strategies or integrations with specific request lifecycles and monitoring tools.

    Common types of contrib submodules include:

    • Alternative implementations of HystrixMetricsPublisher.
    • Alternative implementations of HystrixPropertiesStrategy.
    • Request lifecycle implementations (e.g., hystrix-request-servlet).
    • Implementations of HystrixEventNotifier.
    • Dashboard and monitoring tools.

    Note: Third-party libraries that wrap Hystrix are not part of this repository but are documented in the Hystrix Wiki [Libraries] page.

  2. Supported and Unsupported Async/Sync Fallback combinations

    master

    The compatibility between the command execution type and the fallback execution type is strictly defined.

    Supported Combinations:

    • Sync Command $\rightarrow$ Sync Fallback: Standard synchronous execution.
    • Async Command $\rightarrow$ Sync Fallback: The command returns a Future, but the fallback returns the raw type.
    • Async Command $\rightarrow$ Async Fallback: Both the command and the fallback return a Future (e.g., using AsyncResult).

    Unsupported (Prohibited) Combinations:

    • Sync Command $\rightarrow$ Async Fallback: A synchronous caller cannot benefit from an asynchronous fallback because the execution must block until the fallback completes. This is prohibited.
    // Supported: Async command, async fallback
    @HystrixCommand(fallbackMethod = "fallbackAsync")
    Future<User> getUserById(String id) {
        throw new RuntimeException("getUserById command failed");
    }
    
    @HystrixCommand
    Future<User> fallbackAsync(String id) {
        return new AsyncResult<User>() {
            @Override
            public User invoke() {
                return new User("def", "def");
            }
        };
    }
  3. Manage request caching with Javanica annotations

    master

    Javanica provides three primary annotations to enable and manage request caching for Hystrix commands. These annotations must be used in conjunction with @HystrixCommand.

    AnnotationDescriptionProperties
    @CacheResultMarks a method whose results should be cached.cacheKeyMethod
    @CacheRemoveMarks a method used to invalidate the cache of a command. The generated cache key must match the key used by @CacheResult.commandKey, cacheKeyMethod
    @CacheKeyMarks a method argument as part of the cache key.value

    Cache Key Generation Rules

    1. Default Behavior: If no parameters are annotated with @CacheKey, all parameters are included in the key. If @CacheKey is used, only annotated parameters are included.
    2. cacheKeyMethod Priority: If @CacheResult or @CacheRemove specifies a cacheKeyMethod, method arguments are ignored for key generation, even if they are annotated with @CacheKey. The cacheKeyMethod must be in the same class, have the same signature (except the return type, which must be String), and takes full responsibility for the key.
    3. @CacheKey Property: The value property allows specifying a nested property of an object (e.g., @CacheKey("profile.email") User user). If a nested property is null, it is ignored and results in an empty string.
    // Example: Using @CacheKey with nested properties
    @CacheResult
    @HystrixCommand
    public void getUserByProfileName(@CacheKey("profile.email") User user) {
        storage.getUserByProfileName(user.getProfile().getName());
    }
    
    // Example: Using cacheKeyMethod for custom logic
    @CacheResult(cacheKeyMethod = "getUserByNameCacheKey")
    @HystrixCommand
    public User getUserByName(String name) {
        return storage.getByName(name);
    }
    
    private String getUserByNameCacheKey(String name) {
        return name;
    }
  4. Understand Hystrix Javanica weaving modes

    master

    Javanica supports different weaving modes for applying aspects:

    • Runtime Weaving (RTW): The standard approach. Use the regular hystrix-javanica-X.Y.Z artifact.
    • Compile Time Weaving (CTW): Requires the specific hystrix-javanica-ctw-X.Y.Z artifact (assembled with the AJC compiler). You must start your application with the JVM property -DWeavingMode=compile.
    • Load Time Weaving (LTW): Has not been explicitly tested but is supported.

    Warning: Javanica depends on internal AspectJ features. If you update your AspectJ version (tested with 1.8.7), you may encounter issues.

  5. Understand the hystrix-metrics-event-stream data format

    master

    The module emits metrics in a text/event-stream format. There are two primary types of data emitted:

    HystrixCommand

    Emits real-time statistics for individual Hystrix commands, including error percentages, circuit breaker status, and latency percentiles (0, 25, 50, 75, 90, 95, 99, 99.5, 100).

    HystrixThreadPool

    Emits statistics for Hystrix thread pools, including current pool size, active thread counts, and queue sizes.

    // Example HystrixCommand data
    data: {
      "type": "HystrixCommand",
      "name": "PlaylistGet",
      "group": "PlaylistGet",
      "isCircuitBreakerOpen": false,
      "errorPercentage": 0,
      "requestCount": 121,
      "latencyExecute": {
        "0": 3,
        "50": 8,
        "99": 75,
        "100": 252
      }
    }
    
    // Example HystrixThreadPool data
    data:
    {
      "type": "HystrixThreadPool",
      "name": "ABClient",
      "currentPoolSize": 30,
      "currentActiveCount": 0,
      "currentQueueSize": 0
    }
  6. How to use HystrixCommand

    master

    To isolate code, wrap it inside the run() method of a class extending HystrixCommand. You must provide a HystrixCommandGroupKey in the constructor.

    Once defined, you can execute the command synchronously, asynchronously via a Future, or reactively using Observable.

    public class CommandHelloWorld extends HystrixCommand<String> {
    
        private final String name;
    
        public CommandHelloWorld(String name) {
            super(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"));
            this.name = name;
        }
    
        @Override
        protected String run() {
            return "Hello " + name + "!";
        }
    }
    
    // Usage:
    String s = new CommandHelloWorld("Bob").execute();
    Future<String> s = new CommandHelloWorld("Bob").queue();
    Observable<String> s = new CommandHelloWorld("Bob").observe();
  7. Implement Fallback Methods with @HystrixCommand

    master

    You can achieve graceful degradation by specifying a fallbackMethod in the @HystrixCommand annotation.

    Requirements:

    • The Hystrix command and the fallback method must be in the same class.
    • The fallback method must have the same method signature as the original command (the only exception is that the fallback can optionally include an additional Throwable parameter to capture the cause of failure).

    Fallback Types:

    1. Simple Fallback: A standard method used to process logic when the command fails.
    2. Nested Fallback: If you annotate the fallback method itself with @HystrixCommand, that fallback method can have its own fallbackMethod, allowing for multi-layered degradation.

    Access Modifiers: The fallback method can have any access modifier (e.g., private).

        @HystrixCommand(fallbackMethod = "defaultUser")
        public User getUserById(String id) {
            return userResource.getUserById(id);
        }
    
        private User defaultUser(String id) {
            return new User("def", "def");
        }
  8. Install hystrix-core via Maven or Ivy

    master

    To use the core Hystrix functionality, add the hystrix-core dependency to your project.

    Maven Coordinates:

    • GroupId: com.netflix.hystrix
    • ArtifactId: hystrix-core

    Ivy Coordinates:

    • Org: com.netflix.hystrix
    • Name: hystrix-core
    <!-- Maven -->
    <dependency>
        <groupId>com.netflix.hystrix</groupId>
        <artifactId>hystrix-core</artifactId>
        <version>1.2.0</version>
    </dependency>
    
    <!-- Ivy -->
    <dependency org="com.netflix.hystrix" name="hystrix-core" rev="1.2.0" />
  9. Install hystrix-request-servlet via Maven or Ivy

    master

    To use the Hystrix Request Servlet Filters in your J2EE/Servlet environment, add the following dependency to your build configuration.

    Note: The version used in these examples is 1.1.2. Check Maven Central for the latest available version.

    <!-- Maven -->
    <dependency>
        <groupId>com.netflix.hystrix</groupId>
        <artifactId>hystrix-request-servlet</artifactId>
        <version>1.1.2</version>
    </dependency>
    
    <!-- Ivy -->
    <dependency org="com.netflix.hystrix" name="hystrix-request-servlet" rev="1.1.2" />
  10. Implement the Get-Set-Get pattern for cache invalidation

    master

    To maintain data consistency, use the Get-Set-Get pattern: use @CacheResult for retrieval (GET) and @CacheRemove for updates (SET) to ensure the cache is flushed when data changes.

    Note: @CacheRemove can be used without @HystrixCommand if you add the com.netflix.hystrix.contrib.javanica.aop.aspectj.HystrixCacheAspect to your AOP configuration.

    public class UserService {
        @CacheResult
        @HystrixCommand
        public User getUserById(@CacheKey String id) { // GET
            return storage.get(id);
        }
    
        @CacheRemove(commandKey = "getUserById")
        @HystrixCommand
        public void update(@CacheKey("id") User user) { // SET
            storage.put(user.getId(), user);
        }
    }
  11. Install hystrix-servo-metrics-publisher

    master

    To use Hystrix metrics with Netflix Servo, add the hystrix-servo-metrics-publisher dependency to your project. You can find the latest binaries and dependency information on Maven Central.

    <!-- Maven -->
    <dependency>
        <groupId>com.netflix.hystrix</groupId>
        <artifactId>hystrix-servo-metrics-publisher</artifactId>
        <version>1.1.2</version>
    </dependency>
    
    <!-- Ivy -->
    <dependency org="com.netflix.hystrix" name="hystrix-servo-metrics-publisher" rev="1.1.2" />