Antes de HystrixCommand , puede usar una fusión de solicitud ( HystrixCollapser es una clase madre abstracta) para fusionar múltiples solicitudes en una e luego iniciar llamadas al sistema de dependencia de backend.
La siguiente figura muestra el número de subprocesos y el número de conexiones de red en dos casos: la primera es no usar una fusión, y la segunda es usar una fusión de solicitud (suponiendo que todos los enlaces son paralelos en una ventana de tiempo corto, como dentro de los 10 ms).
¿Por qué utilizar la solicitud de solicitud?
La fusión de la solicitud se utiliza para reducir el número de subprocesos y conexiones de red necesarias para realizar ejecuciones concurrentes HystrixCommand . Las fusiones de solicitud se realizan automáticamente y no obligan a los desarrolladores a coordinar manualmente las solicitudes de lotes.
Contexto global: contexto global (que abarca todos los hilos de Tomcat)
Este tipo de fusión se realiza en el nivel de aplicación global, por lo que cualquier solicitud de usuario en cualquier hilo de Tomcat se puede fusionar.
Por ejemplo, si configura un HystrixCommand para admitir las dependencias de solicitud de usuario para recuperar las calificaciones de películas, cuando cualquier subproceso de usuario en la misma JVM realiza dicha solicitud, Hystrix agrega su solicitud junto con cualquier otra solicitud a la misma llamada de red colapsada.
Contexto de solicitud de usuario: contexto de solicitud (hilo de Tomcat único)
Si configura un HystrixCommand para manejar las solicitudes de lotes solo para un solo usuario, Hystrix puede fusionar las solicitudes en un subproceso de Tomcat (solicitud).
Por ejemplo, si un usuario desea cargar un marcador de 300 objetos de video, en lugar de ejecutar 300 solicitudes de red, Hystrix puede fusionarlos en uno.
Hystrix es Solic-Scope de forma predeterminada. Para utilizar la función con escolta de solicitud (almacenamiento en caché de solicitud, colapso de solicitudes, registro de solicitudes) debe administrar el ciclo de vida del HystrixRequestContext (o implementar una alternativa HystrixConcurrencyStrategy )
Esto significa que debe ejecutar el siguiente código antes de ejecutar una solicitud:
La copia del código es la siguiente: hytrixrequestContext context = hytrixRequestContext.InitializeContext ();
Y ejecutar al final de la solicitud:
context.shutdown ();
En aplicaciones estándar de Javaweb, también puede usar un filtro de servlet para inicializar este ciclo de vida
La clase pública HystrixRequestContextEspervletFilter implementa filtro {public void dofilter (ServletRequest Solicitud, Respuesta ServLetResponse, FilterChain Chain) lanza ioexception, servletException {hytrixRequestContext context = hytrixRequestContext.InitializeContext ();; intente {chain.dofilter (solicitud, respuesta); } finalmente {context.shutdown (); }}}Luego configúralo en web.xml
<filter> <display-name>HystrixRequestContextServletFilter</display-name> <filter-name>HystrixRequestContextServletFilter</filter-name> <filter-class>com.netflix.hystrix.contrib.requestservlet.HystrixRequestContextServletFilter</filter-class> </filter> <filter-mapping> <Scilter-Name> HystrixRequestContextServletFilter </filter-name> <url-pattern>/*</sl-Pattern> </filter-mapping>
Si está desarrollando SpringBoot, el código es el siguiente:
@WebFilter(filterName = "hystrixRequestContextServletFilter",urlPatterns = "/*")public class HystrixRequestContextServletFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse ServLetResponse, FilterChain FilterChain) lanza ioexception, servletException {hytrixRequestContext context = hytrixrequestContext.initializeContext (); intente {FilterChain.DoFilter (ServLetRequest, ServLetResponse); } finalmente {context.shutdown (); }} @Override public void destruye () {}} @SpringBootApplication@habilitados en el consultorio@enablefeignClients@enablehystrix // Esto es necesario, de lo contrario, el filtro no es válido @ServletComponentsCanPublic Class Application {public static void main (string [] args) {New SpringAplicationBuLeer (Application.Class) .Web (True) .Run (args); }}¿Cuál es el costo de solicitar una fusión?
El costo de habilitar la fusión de la solicitud es el retraso antes de ejecutar el comando real. El mayor costo es el tamaño de la ventana por lotes, que es de 10 ms de forma predeterminada.
Si tiene un comando que requiere 5 ms para ejecutar y tiene una ventana por lotes de 10 ms, el peor caso de tiempo de ejecución es de 15 ms. En general, la solicitud no ocurrirá cuando se acaba de abrir la ventana por lotes, por lo que el valor intermedio de la ventana de tiempo es la mitad de la ventana de tiempo, en este caso son 5 ms.
Si este costo vale la pena depende del comando que se esté ejecutando, y los comandos de alta latencia no se ven afectados por una pequeña cantidad de retraso promedio adicional. Además, la cantidad de concurrencia de un comando dado también es clave: si se combinan menos de 1 o 2 solicitudes, entonces el costo no vale la pena. De hecho, la solicitud de iteración secuencial se fusiona en un solo hilo será un cuello de botella de rendimiento importante, y cada iteración esperará el tiempo de espera de la ventana de las 10 ms.
Sin embargo, si se usa un comando en particular en grandes cantidades al mismo tiempo y puede hacer docenas o incluso cientos de llamadas en lotes al mismo tiempo, el costo suele ser mucho más que el aumento en el rendimiento alcanzado, porque Hystrix reduce el número de hilos que requiere, dependencias. (Este pasaje no es fácil de entender. De hecho, si la concurrencia es relativamente alta, el costo vale la pena, porque Hystrix puede ahorrar muchos hilos y recursos de conexión).
El proceso de solicitud de fusión (como se muestra a continuación)
El conocimiento teórico ha sido explicado. Echemos un vistazo a los ejemplos a continuación. Los ejemplos a continuación integran Eureka+Feign+Hystrix. Para ver el ejemplo completo, consulte: https://github.com/jingangwang/micro-service
Clase de entidad
Usuario de clase pública {ID de entero privado; nombre de usuario de cadena privada; edad de entero privado; Public User () {} Public User (ID de Integer, String UserName, Integer Age) {this.id = id; this.Username = UserName; this.age = edad; } public integer getId () {return id; } public void setid (ID de entero) {this.id = id; } public String getUsername () {return UserName; } public void setUsername (String UserName) {this.Username = username; } public Integer GetAge () {return Age; } public void setAge (edad entera) {this.age = edad; } @Override public string toString () {final stringbuffer sb = new StringBuffer ("User {"); sb.append ("id ="). append (id); sb.append (", username = '"). append (nombre de usuario) .append ('/''); sb.append (", edad ="). append (edad); sb.append ('}'); return sb.ToString (); }}Código de proveedor de servicios
@RestController @requestMapping ("Usuario") Class pública UserController {@RequestMapping ("GetUser") Public User GetUser (ID de Integer) {return New User (id, "Test", 29); } @RequestMapping ("getAlluser") Lista pública <serem> getAlluser (String IDS) {String [] Split = id.split (","); return arrays.aslist (dividido) .stream () .map (id -> nuevo usuario (integer.valueOf (id), "test"+id, 30)) .collect (coleccions.tolist ()); }}Código de consumo
UserFeignClient
@FeignClient (name = "eureka-provider", configuración = feignConfiguration.class) interfaz pública userfeignClient {/** * Buscar user por id * @param ID ID de usuario * @return user */@RequestMapping (valor = "user/getUser.json", método = requestmethod.get) user finduserByid (@RequParam ("Id"); "Id"); "Id"); /*** exceder la lista de usuarios* @param IDS ID LIST* @return Collection de usuario*/@RequestMapping (valor = "user/getAlluser.json", método = requestmethod.get) list <serer> findalluser (@requestparam ("ids") IDS de cadena);}UserService (establecido en contexto global)
@ServicePublic Class UserService {@aUtowired userfeignClient UserFeignClient; /** * maxRequestsInBatch This property sets the maximum number of requests for batch processing, the default value is Integer.MAX_VALUE * timerDelayInMilliseconds This property sets how long it takes to count batch processing, the default is 10ms * @param id * @return */ @HystrixCollapses(collapserKey = "findCollapserKey",scope = com.netflix.hystrix.hystrixcollapser.scope.global, batchmethod = "findalluser", collapserProperties = {@hystrixproperty (name = "timerDelayInMilliseConds", value = "5000"), @hystrixProperty (name = "maxReCeSQuestonds", value = "5000"), @hystrixProperty (name = "maxReCeSquestInbatchsInbatch"). Public Future <serem> Find (Integer ID) {return null; } @HystrixCommand (commandkey = "findalluser") Lista pública <serem> findalluser (list <integer> ids) {return userFeignClient.findalluser (stringUtils.Join (ids, ",")); }}FeignCollapserController
@RequestMapping ("User") @RestControllerPublic Class FeignCollApSerController {@autewired private UserService UserSerVice; @RequestMapping ("FindUser") Public User GetUser (ID de Integer) lanza ExecutionException, InterruptedException {return UserService.Find (id) .get (); } En el código anterior, estamos en el contexto global (todas las solicitudes de los subprocesos de TomCat se pueden fusionar), la ventana de tiempo de fusión es 5s (cada solicitud tiene que esperar 5s antes de que se inicie la solicitud), y el número máximo de fusiones es 5. En Postman, iniciamos dos solicitudes dentro de 5s, pero las ID de usuario son diferentes.
Localhost: 8082/user/finduser.json? Id = 123189891
Localhost: 8082/user/finduser.json? Id = 222222
El resultado se muestra en la figura a continuación, y las dos solicitudes se fusionan en una solicitud de lote de solicitud.
Probemos el contexto de solicitud (Solicitud-ESCOPE), agregue HystrixRequestContextServletFilter mencionado anteriormente y modifique el UserService
HystrixRequestContextServletFilter
/** * @author wjg * @date 2017/12/22 15:15 */ @webFilter (filtername = "hytrixRequestContextExtEspletFilter", urlpatterns = "/ *") clase pública hytrixRequestContextExtEspletFilter implements Filter {@Override Void Initerfil {} @Override public void dofilter (ServLetRequest ServLetRequest, ServLetResponse ServletResponse, FilterChain FilterChain) lanza ioexception, servletException {hytrixRequestContext context = hystrixrequestContext.initializeContext ();; intente {FilterChain.DoFilter (ServLetRequest, ServLetResponse); } finalmente {context.shutdown (); }} @Override public void destruye () {}}UserService (establecido como contexto de solicitud)
@ServicePublic Class UserService {@aUtowired userfeignClient UserFeignClient; /** * maxRequestsInBatch This property sets the maximum number of requests for batch processing, the default value is Integer.MAX_VALUE * timerDelayInMilliseconds This property sets how long it takes to count batch processing, the default is 10ms * @param id * @return */ @HystrixCollapses(collapserKey = "findCollapserKey",scope = com.netflix.hystrix.hystrixcollapser.scope.request, batchmethod = "findalluser", collapserProperties = {@hystrixproperty (name = "timerDelayInMilliseConds", valor = "5000"), @hystrixproperty (name = "maxReCeSquestiSinBatchsInbeTsInbeSinBeath"). Public Future <serem> Find (Integer ID) {return null; } @HystrixCommand (commandkey = "findalluser") Lista pública <serem> findalluser (list <integer> ids) {return userFeignClient.findalluser (stringUtils.Join (ids, ",")); }}FeignCollaPser2Controller
@RequestMapping ("User") @RestControllerPublic FeignCollaPser2Controller {@aUtoWired private UserService UserService; @RequestMapping ("FindUser2") Lista pública <serem> getUser () lanza ExecutionException, InterruptedException {Future <Serem> User1 = UserService.Find (1989); Futuro <serem> user2 = Userservice.find (1990); List <serem> users = new ArrayList <> (); ussers.add (user1.get ()); ussers.add (user2.get ()); devolver usuarios; }} Escribimos Postman: Localhost: 8082/user/finduser2.json
Puede ver que se fusionan dos llamadas consecutivas dentro de una solicitud. Tenga en cuenta que esto no es posible usar UserServer.Find (1989) .get () directamente; de lo contrario, el procesamiento se realizará directamente de acuerdo con la sincronización y no se fusionará. Si dos páginas de pestaña llaman a la dirección anterior al mismo tiempo, se encuentra que se han iniciado dos solicitudes de lotes, lo que significa que el alcance es el alcance de la solicitud.
Las referencias son las siguientes:
https://github.com/netflix/hystrix/wiki/how-to-use
//www.vevb.com/article/140530.htm
Lo anterior es todo el contenido de este artículo. Espero que sea útil para el aprendizaje de todos y espero que todos apoyen más a Wulin.com.