Avant HystrixCommand , vous pouvez utiliser une fusion de demande ( HystrixCollapser est une classe parentale abstraite) pour fusionner plusieurs demandes en une seule, puis lancer des appels au système de dépendance backend.
La figure ci-dessous montre le nombre de threads et le nombre de connexions réseau dans deux cas: la première consiste à ne pas utiliser de fusion, et la seconde consiste à utiliser une fusion de demande (en supposant que toutes les liaisons sont parallèles dans une courte fenêtre de temps, comme dans les 10 ms).
Pourquoi utiliser la demande de demande?
La demande de demande est utilisée pour réduire le nombre de threads et les connexions réseau requises pour effectuer des exécutions simultanées HystrixCommand . Les fusions de demande sont effectuées automatiquement et n'offrent pas les développeurs à coordonner manuellement les demandes de lots.
Contexte global - contexte global (couvrant tous les threads Tomcat)
Ce type de fusion est effectué au niveau mondial de l'application, de sorte que toute demande de l'utilisateur sur n'importe quel thread Tomcat peut être fusionnée ensemble.
Par exemple, si vous configurez un HystrixCommand pour prendre en charge les dépendances de demande utilisateur pour récupérer les cotes de film, lorsque tout thread utilisateur dans le même JVM fait une telle demande, Hystrix ajoute sa demande avec toute autre demande à l'appel réseau effondré.
Contexte de demande de l'utilisateur - Contexte de demande (thread Tomcat unique)
Si vous configurez un HystrixCommand pour gérer les demandes de lots uniquement pour un seul utilisateur, Hystrix peut fusionner les demandes dans un thread TomCat (demande).
Par exemple, si un utilisateur souhaite charger un signet de 300 objets vidéo, au lieu d'exécuter 300 demandes de réseau, Hystrix peut les fusionner en un.
Hystrix est la demande de demande par défaut. Pour utiliser la fonction de demande de demande (mise en cache de demande, effondrement de la demande, journal de demande), vous devez gérer le cycle de vie de HystrixRequestContext (ou implémenter une autre HystrixConcurrencyStrategy )
Cela signifie que vous devez exécuter le code suivant avant d'exécuter une demande:
La copie de code est la suivante: HystrixRequestContext context = HystrixRequestContext.InitializEContext ();
Et exécuter à la fin de la demande:
context.shutdown ();
Dans les applications Javaweb standard, vous pouvez également utiliser un filtre de servlet pour initialiser ce cycle de vie
classe publique HystrixRequestContextServletFilter implémente Filter {public void Dofilter (ServletRequest Request, ServletResponse Response, FilterChain Chain) lance ioException, Servlexception {HystrixRequestContext context = HystrixRequestContext.InitialiseContext (); essayez {chain.dofilter (demande, réponse); } enfin {context.shutdown (); }}}Puis configurez-le dans web.xml
<filter> <splay-name> HystrixRequestContextServletFilter </ Display-Name> <Lilter-Name> HystrixRequestContextServletFilter </filter-Name> <Filter-Class> Com.netflix.hystrix.contrib.requestServert.hystrixrequestContextServletfletfilter </filter-class> </ filter> <Imlter-mapping> <filter-name> HystrixRequestContextServletFilter </filter-name> <Url-Pattern> / * </url-potern> </filter-mapping>
Si vous développez Springboot, le code est le suivant:
@WebFilter (filterName = "HystrixRequestContextServletFilter", urlpatterns = "/ *") classe publique HystrixRequestContexTServletFilter implémente filter {@Override public Void init (filterConfig filterConFig) Throws ServLeest {} @Override public Dofilter (ServLesterSquest, @Override public Dofilter (ServLesterSquest. ServletResponse ServletResponse, filterChain FilterChain) lève IOException, ServletException {HystrixRequestContext context = HystrixRequestContext.InitializEContext (); essayez {filterchain.dofilter (servletRequest, servletResponse); } enfin {context.shutdown (); }} @Override public void destre () {}} @ SpringbootApplication @veablediscoveryClient @ activerfeignClient @ activerhystrix // Ceci est requis, sinon le filtre est invalide @servletcomponentsCanpublic class application {public static void main (String [] args) {new SpringApplicationBuilder (application.class) .web (true) .run (args); }}Quel est le coût de la demande d'une fusion?
Le coût d'activation de la demande de demande est le retard avant l'exécution de la commande réelle. Le coût le plus important est la taille de la fenêtre par lots, qui est de 10 ms par défaut.
Si vous avez une commande qui prend 5 ms à exécuter et a une fenêtre de lot de 10 ms, le pire des cas de temps d'exécution est de 15 ms. Généralement, la demande ne se produira pas lorsque la fenêtre par lots est juste ouverte, de sorte que la valeur intermédiaire de la fenêtre temporelle est la moitié de la fenêtre de temps, dans ce cas, elle est de 5 ms.
Que ce coût en vaut la peine dépend de la commande exécutée, et les commandes à latence élevée ne sont pas affectées par une petite quantité de retard moyen supplémentaire. De plus, le montant de la concurrence d'une commande donnée est également essentiel: si moins de 1 ou 2 demandes sont combinées, le coût n'en vaut pas la peine. En fait, la fusion de la demande d'itération séquentielle dans un seul thread sera un goulot d'étranglement majeur, et chaque itération attendra le temps d'attente de la fenêtre de 10 ms.
Cependant, si une commande particulière est utilisée en grande quantité en même temps et peut effectuer des dizaines, voire des centaines d'appels en lots en même temps, le coût est généralement bien plus que l'augmentation du débit obtenu, car Hystrix réduit le nombre de fils dont il a besoin, les dépendances. (Ce passage n'est pas facile à comprendre. En fait, si la concurrence est relativement élevée, le coût en vaut la peine, car Hystrix peut économiser beaucoup de threads et de ressources de connexion).
Le processus de demande de fusion (comme indiqué ci-dessous)
Les connaissances théoriques ont été expliquées. Jetons un coup d'œil aux exemples ci-dessous. Les exemples ci-dessous intègrent Eureka + Feign + Hystrix. Pour l'exemple complet, veuillez consulter: https://github.com/jingangwang/micro-service
Classe d'entité
classe publique User {ID entier privé; Nom d'utilisateur de chaîne privée; Âge entier privé; Utilisateur public () {} Utilisateur public (ID entier, nom d'utilisateur de chaîne, âge entier) {this.id = id; this.userName = nom d'utilisateur; this.age = âge; } public Integer getID () {return id; } public void setid (INGER ID) {this.id = id; } public String getUserName () {return username; } public void setUsername (String username) {this.userName = username; } public Integer Getage () {Return Age; } public void Setage (entier Âge) {this.age = age; } @Override public String toString () {final stringBuffer sb = new StringBuffer ("user {"); SB.APPEND ("ID ="). APPEND (ID); SB.APPEND (", nom d'utilisateur = '"). APPEND (nom d'utilisateur) .append (' / ''); SB.APPEND (", Age ="). APPEND (Age); sb.append ('}'); return sb.toString (); }}Code du fournisseur de services
@ RestController @ requestmapping ("user") public class userController {@RequestMapping ("getuser") public utilisateur GetUser (INTER ID) {return nouvel utilisateur (id, "test", 29); } @RequestMapping ("GetAlLuser") Liste publique <User> GetAlLuser (String ids) {String [] Split = ids.split (","); return arrays.aslist (Split) .Stream () .map (id -> nouvel utilisateur (Integer.ValueOf (id), "test" + id, 30)) .Collect (collecors.tolist ()); }}Code de consommation
UserFeignClient
@FeignClient (name = "eureka-provider", configuration = feignConfiguration.class) interface publique userFeignClient {/ ** * Rechercher l'utilisateur par id * @param id id * @return user * / @requestmaping (value = "user / geserer.json", méthode = requestMethod.get) utilisateur finseserbyid (@requestparam ("id) Id); / ** * dépasser la liste d'utilisateurs * @param ids id list * @return utilisateur collection * / @requestmapping (value = "user / getAlUser.json", méthode = requestMethod.get) list <serv> findalLuser (@RequestParam ("ids") String ids);};Service d'utilisateur (défini sur le contexte mondial)
@ServicePublic Class userservice {@autowired private userFeignClient userFeignClient; / ** * MaxRequestSinBatch Cette propriété définit le nombre maximum de demandes de traitement par lots, la valeur par défaut est Integer.max_value * TimerDelayInMilliseconds Cette propriété définit le temps qu'il faut pour compter le traitement par lots (collapserkey = "findCollapser" / @HystrixCollapses (collapserke com.netflix.hystrix.hystrixcollapser.scope.global, batchMethod = "findalLuser", collapserProperties = {@hystrixproperty (name = "TimerDelayInMillisEconds", value = "5000"), @hystrixproperty (name = "maxrequestsinbatch", ") Future <User> find (INTER ID) {return null; } @HystrixCommand (CommandKey = "FindAlUser") public List <Derser> FindAlUser (list <Integer> ids) {return userFeignClient.findAlUser (stringUtils.join (ids, ",")); }}FeignCollapserController
@RequestMapping ("utilisateur") @ RestControllerPublic Class feignCollApserController {@autowired privé UserService UserService; @RequestMapping ("FindUser") Utilisateur public GetUser (INTER ID) lève ExecutionException, InterruptedException {return userservice.find (id) .get (); } Dans le code ci-dessus, nous sommes dans le contexte global (toutes les demandes de threads Tomcat peuvent être fusionnées), la fenêtre de temps de fusion est de 5s (chaque demande doit attendre les 5 avant la demande de la demande), et le nombre maximum de fusions est de 5. Dans Postman, nous entamons deux demandes dans les 5S, mais les ID utilisateur sont différents.
LocalHost: 8082 / User / FindUser.json? Id = 123189891
LocalHost: 8082 / User / FindUser.json? Id = 222222
Le résultat est illustré dans la figure ci-dessous et les deux demandes sont fusionnées dans une demande de lots d'une demande.
Tissons le contexte de la demande (demande-scope), ajoutons HystrixRequestContextServletFilter mentionnée ci-dessus et modifiez le service d'utilisateur
HystrixRequestContextServletFilter
/ ** * @Author WJG * @Date 2017/12/22 15:15 * / @ webFilter (filterName = "HystrixRequestContextServletFilter", UrlPatterns = "/ *") public HystrixRequestContexServletFilter Impldences Filter {@override public Void Init Init (FilterConfig FilterConfig) Filter {@OVERRID {} @Override public void dofilter (servletRequest ServletRequest, servletResponse ServletResponse, filterchain filterChain) lance ioexception, servletException {HystrixRequestContext context = HystrixRequestContext.InitializEConText (); essayez {filterchain.dofilter (servletRequest, servletResponse); } enfin {context.shutdown (); }} @Override public void destre () {}}UserService (Définir en tant que contexte de demande)
@ServicePublic Class userservice {@autowired private userFeignClient userFeignClient; / ** * MaxRequestSinBatch Cette propriété définit le nombre maximum de demandes de traitement par lots, la valeur par défaut est Integer.max_value * TimerDelayInMilliseconds Cette propriété définit le temps qu'il faut pour compter le traitement par lots (Collapserke com.netflix.hystrix.hystrixcollapser.scope.request, batchMethod = "findalLuser", collapserProperties = {@hystrixproperty (name = "timerDelayInMillisEconds", value = "5000"), @hystrixproperty (name = "maxrequestsinbatch", ") Future <User> find (INTER ID) {return null; } @HystrixCommand (CommandKey = "FindAlUser") public List <Derser> FindAlUser (list <Integer> ids) {return userFeignClient.findAlUser (stringUtils.join (ids, ",")); }}FeignCollapser2Controller
@RequestMapping ("User") @ RestControllerPublic Class feignCollapser2Controller {@Autowired Private UserService UserService; @RequestMapping ("FindUser2") Liste publique <User> getuser () lève ExecutionException, InterruptedException {futur <User> user1 = userService.find (1989); Futur <User> user2 = userService.find (1990); List <ser utilisateur> users = new ArrayList <> (); users.add (user1.get ()); users.add (user2.get ()); retourner les utilisateurs; }} Nous tapons Postman: LocalHost: 8082 / User / FindUser2.json
Vous pouvez voir que deux appels consécutifs dans une demande sont fusionnés. Notez que cela n'est pas possible d'utiliser USERSERVERVER.FIND (1989) .get () directement, sinon le traitement sera effectué directement en fonction de la synchronisation et ne sera pas fusionné. Si deux pages d'onglet appellent l'adresse ci-dessus en même temps, il est constaté que deux demandes de lots ont été lancées, ce qui signifie que la portée est la portée de la demande.
Les références sont les suivantes:
https://github.com/netflix/hystrix/wiki/how-to-use
//www.vevb.com/article/140530.htm
Ce qui précède est tout le contenu de cet article. J'espère que cela sera utile à l'apprentissage de tous et j'espère que tout le monde soutiendra davantage Wulin.com.