Antes HystrixCommand , você pode usar uma fusão de solicitação ( HystrixCollapser é uma classe pai abstrata) para mesclar várias solicitações em uma e iniciar chamadas para o sistema de dependência de back -end.
A figura abaixo mostra o número de threads e o número de conexões de rede em dois casos: a primeira é não usar uma fusão, e a segunda é usar uma fusão de solicitação (assumindo que todos os links sejam paralelos em uma janela de tempo curto, como dentro de 10ms).
Por que usar a fusão de solicitação?
A mesclagem de solicitação é usada para reduzir o número de threads e conexões de rede necessárias para executar execuções simultâneas HystrixCommand . As mescladas de solicitação são executadas automaticamente e não forçam os desenvolvedores a coordenarem manualmente solicitações em lote.
Contexto Global - Contexto Global (abrangendo todos os threads Tomcat)
Esse tipo de mesclagem é feito no nível de aplicativo global; portanto, qualquer solicitação do usuário em qualquer thread do tomcat pode ser mesclada.
Por exemplo, se você configurar um HystrixCommand para oferecer suporte a qualquer dependência de solicitação do usuário para recuperar as classificações de filmes, quando qualquer tópico do usuário na mesma JVM fizer essa solicitação, a Hystrix adiciona sua solicitação junto com qualquer outra solicitação à mesma chamada de rede em colapso.
Contexto da solicitação do usuário - Contexto de solicitação (thread único Tomcat)
Se você configurar um HystrixCommand para lidar com solicitações de lote apenas para um único usuário, o Hystrix poderá mesclar solicitações em um thread Tomcat (solicitação).
Por exemplo, se um usuário quiser carregar um marcador de 300 objetos de vídeo, em vez de executar 300 solicitações de rede, a Hystrix poderá mesclá -los em um.
O Hystrix é um cento de solicitação por padrão. Para usar a função escopo de solicitação (cache de solicitação, colapso da solicitação, log de solicitação), você deve gerenciar o ciclo de vida HystrixRequestContext (ou implementar um HystrixConcurrencyStrategy alternativo)
Isso significa que você precisa executar o seguinte código antes de executar uma solicitação:
A cópia do código é a seguinte: hystrixRixRequestContext context = hystrixRixRequestContext.initializeContext ();
E executar no final da solicitação:
context.shutdown ();
Em aplicativos Javaweb padrão, você também pode usar um filtro de servlet para inicializar este ciclo de vida
classe pública HyStrixRequestContextServletFilter implementa filtro {public void Dofilter (Solicitação de servletRequest, resposta servletResponse, cadeia de filtro) lança IoException, servletexception {HyStrixRixRixEnTontext Context = HyStrixFestCestContexcept.initializeConText (); tente {Chain.dofilter (solicitação, resposta); } finalmente {context.shutdown (); }}}Em seguida, configure -o em web.xml
<filter> <liber-name> hystrixrequestContextServletFilter </sisplay-name> <filter-name> hystrixRequestContextServletFilter </filter-name> <filter-clSl> com.netflix.hyStrix.Contrib.RequestServlet.hyStrixRixFlix.hyStrix.Contrib.RequestServlet.hyStrixReflix. <filter-name> hystrixRixRequestContextServletFilter </filter-name> <url-tattern>/*</url-tattern> </filter-Mapping>
Se você estiver desenvolvendo Springboot, o código é o seguinte:
@WebFilter(filterName = "hystrixRequestContextServletFilter",urlPatterns = "/*")public class HystrixRequestContextServletFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse serverletResponse, filterhain filterchain) lança ioexception, servletexception {hystrixRequestContext context = hystrixRixRequestContext.initializeContext (); tente {filterChain.dofilter (servletRequest, servletResponse); } finalmente {context.shutdown (); }} @Override public void Destroy () {}} @SpringbooTApplication@Enablediscoveryclient@EnableFeignCliients@EnableHySTrix // Isso é necessário; caso contrário, o filtro é inválido @servletComponentsCanPublic Class Application {public static void main (string [] args) {new SpringApplicationBuilder (Application.Class). }}Qual é o custo de solicitar uma fusão?
O custo de ativar a fusão da solicitação é o atraso antes que o comando real seja executado. O maior custo é o tamanho da janela do lote, que é de 10 ms por padrão.
Se você possui um comando que leva 5ms para executar e possui uma janela de 10ms, o pior caso de tempo de execução é de 15 ms. Geralmente, a solicitação não ocorre quando a janela do lote for aberta, portanto o valor intermediário da janela de tempo é metade da janela de tempo, neste caso é 5ms.
Se esse custo vale a pena depende do comando que está sendo executado e os comandos de alta latência não são afetados por uma pequena quantidade de atraso médio adicional. Além disso, a quantidade de simultaneidade de um determinado comando também é fundamental: se menos de 1 ou 2 solicitações forem combinadas, o custo não vale a pena. De fato, a solicitação de iteração sequencial se fundir em um único thread será um grande gargalo de desempenho, e cada iteração aguardará o tempo de espera da janela de 10ms.
No entanto, se um comando específico for usado em grandes quantidades ao mesmo tempo e pode fazer dezenas ou até centenas de chamadas em lotes ao mesmo tempo, o custo geralmente é muito mais do que o aumento da taxa de transferência alcançada, porque a Hystrix reduz o número de encadeamentos que requer, dependências. (Esta passagem não é fácil de entender. De fato, se a simultaneidade for relativamente alta, o custo vale a pena, porque a Hystrix pode economizar muitos threads e recursos de conexão).
O processo de solicitação de fusão (como mostrado abaixo)
O conhecimento teórico foi explicado. Vamos dar uma olhada nos exemplos abaixo. Os exemplos abaixo integram Eureka+Feign+Hystrix. Para o exemplo completo, verifique: https://github.com/jingangwang/micro-service
Classe de entidade
Public class Usuário {ID inteiro privado; Nome de usuário privado de string; idade inteira privada; public user () {} public user (ID inteiro, nome de usuário da string, idade inteira) {this.id = id; this.UserName = Nome de usuário; this.age = idade; } public integer getId () {return id; } public void SetId (ID inteiro) {this.id = id; } public string getUserName () {return userName; } public void setUserName (string userName) {this.username = nome de usuário; } public integer getage () {retorna idade; } public void setage (idade inteira) {this.age = Age; } @Override public String tostring () {final StringBuffer sb = new StringBuffer ("user {"); sb.append ("id ="). Append (id); sb.append (", nome de usuário = '"). Append (nome de usuário) .append ('/''); sb.append (", AGE ="). Appender (idade); sb.append ('}'); return sb.toString (); }}Código do provedor de serviços
@RestController @requestmapping ("user") classe pública UserController {@RequestMapping ("getUser") Public User GetUser (ID de Inteiro) {return novo usuário (ID, "teste", 29); } @RequestMapping ("getAllUser") Lista pública <suser> getAllUser (string IDS) {String [] split = ids.split (","); retorno Arrays.asList (split) .stream () .map (id -> novo usuário (número inteiro.valueof (id), "teste"+id, 30)) .collect (collectors.tolist ()); }}Código do consumidor
UserFeignClient
@FeignClient (name = "eureka-provider", configuration = FeignConfiguration.class) interface pública UserFeignClient {/** * Encontre o usuário por id * @param ID ID do usuário * @return user */@requestMapp (value = user/getUser.json ("MetodEMMod.get) /*** Lista de usuários excede* @param IDS Lista de IDs* @Return User Collection*/@RequestMapping (value = "user/getalluser.json", método = requestmethod.get) list <user> findAllUser (@RequestParam ("ids") string);}}}UserService (definido como contexto global)
@ServicePublic Class UserService {@AUTOWIRED PRIVADO PRIVIDO DO USERFEIGNIENTEIGNIENCLIENT; / *] com.netflix.hystrix.hystrixcollapser.scope.global, BatchMethod = "FindAllUser", colapserProperties = {@hystrixProperty (name = "timerDelayInMillisEConds", value "5000"), @hysTrix "MAUTRIXTRIX (NamesTrrix), main) Futuro <suário> encontre (ID inteiro) {return null; } @HystrixCommand (commandKey = "findAllUser") Lista pública <suser> findAllUser (list <Teger> ids) {return userFeignClient.findalluser (stringutils.join (ids, ","); }}FeignCollaPSerController
@RequestMapping ("Usuário") @RestControllerPublic Classe FeignCollaPSerCOntroller {@AUTOWIRED UserService Uservice Service; @RequestMapping ("findUser") Usuário público getUser (ID inteiro) lança ExecutionException, interruptedException {return userservice.find (id) .get (); } No código acima, estamos no contexto global (todas as solicitações dos threads do Tomcat podem ser mesclados), a janela do tempo de mesclagem é de 5s (cada solicitação deve esperar 5s antes do início da solicitação) e o número máximo de fusão é 5. No Postman, iniciamos duas solicitações dentro de 5s, mas os IDs do usuário são diferentes.
localhost: 8082/user/finduser.json? id = 123189891
localhost: 8082/user/finduser.json? Id = 222222
O resultado é mostrado na figura abaixo e as duas solicitações são mescladas em uma solicitação de lotes de solicitação.
Vamos testar o contexto da solicitação (Solicitação-Scope), adicione HystrixRequestContextServletFilter mencionado acima e modifique o UserService
HystrixRequestContextServletFilter
/** * @author wjg * @date 2017/12/22 15:15 */@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, filtrohain FilterChain) lança IoException, servletexception {hystrixRequestContext Context = HyStrixRequestContext.InitializeConTextTextContext Context = HyStrixRequestContext.InitializeConText (); tente {filterChain.dofilter (servletRequest, servletResponse); } finalmente {context.shutdown (); }} @Override public void Destroy () {}}UserService (definido como contexto de solicitação)
@ServicePublic Class UserService {@AUTOWIRED PRIVADO PRIVIDO DO USERFEIGNIENTEIGNIENCLIENT; / *] com.netflix.hystrix.hystrixcollapser.Scope.Request, BatchMethod = "FindAllUser", COLLAPSERPROPERTIES = {@HySTRIXProperty (name = "timerDelayInMillisEConds", value "5000"), @hysTrix "MAURSTRIX (NamesTrrix)" Rualing = "5000"), @hysTrix (namesProperty (names), main), "5 - 5000") Futuro <suário> encontre (ID inteiro) {return null; } @HystrixCommand (commandKey = "findAllUser") Lista pública <suser> findAllUser (list <Teger> ids) {return userFeignClient.findalluser (stringutils.join (ids, ","); }}FeignCollaper2Controller
@RequestMapping ("Usuário") @RestControllerPublic Classe FeignCollapser2Controller {@AUTOWIRED Uservice privado Uservice Service; @RequestMapping ("findUser2") Lista pública <suser> getUser () lança ExecutionException, interruptEdException {FUTURT <suser> user1 = userservice.find (1989); Futuro <suário> user2 = userService.find (1990); List <suser> usuários = new ArrayList <> (); users.add (user1.get ()); users.add (user2.get ()); devolver usuários; }} Digitamos no Postman: localhost: 8082/user/finduser2.json
Você pode ver que duas chamadas consecutivas dentro de uma solicitação são mescladas. Observe que isso não é possível usar o userServer.find (1989) .get () diretamente, caso contrário, o processamento será executado diretamente de acordo com a sincronização e não será mesclado. Se duas páginas da guia chamarem o endereço acima ao mesmo tempo, é constatado que duas solicitações de lote foram iniciadas, o que significa que o escopo é o escopo da solicitação.
As referências são as seguintes:
https://github.com/netflix/hystrix/wiki/how-to-use
//www.vevb.com/article/140530.htm
O exposto acima é todo o conteúdo deste artigo. Espero que seja útil para o aprendizado de todos e espero que todos apoiem mais o wulin.com.