Dubbo
Artigo Diretório
1. Visão geral do dubbo
- Dubbo é uma estrutura Java RPC para fornecer soluções de invocação de serviço remoto de alto desempenho e soluções de governança de serviço SOA
Em termos simples, Dubbo é usado para fornecer aos consumidores uma interface de chamada (registrar a interface no registro)
- Fluxograma de operação dubbo
Descrição da função do nó:
● Provedor: o provedor de serviços que expõe o serviço
● Consumidor: o consumidor do serviço que chama o serviço remoto
● Contêiner: o contêiner em execução do serviço
● Registro: o registro para registro e descoberta do serviço
● Monitor: o centro de monitoramento que conta o número de serviços ligações e o tempo da ligação
- Explicação de texto do processo de execução do Dubbo
(1) Inicie o contêiner, carregue e execute o provedor de serviços
(2) Quando o provedor iniciar, registre o serviço que ele fornece no registro
(3) Quando o consumidor iniciar, assine o serviço de que precisa no registro
(4) O o registro é usado para O URL fornecido pelo provedor de gerenciamento; ZooKeeper é o centro de registro recomendado por Dubbo
(5) O centro de monitoramento gerencia todo o processo
- Considere falhas ou mudanças
(1) O registro retorna a lista de endereços do provedor ao consumidor. Se houver uma mudança, o registro envia os dados alterados ao consumidor.
(2) O consumidor seleciona um provedor da lista de endereços do provedor para ligar. Se a chamada falhar , Escolha outro
(3) O consumidor e o provedor registram o número de chamadas e o tempo da chamada na memória, e enviam estatísticas para a central de monitoramento a cada minuto
Dois, exemplo de execução de Dubbo
Crie dois módulos, um como provedor e outro como consumidor. O consumidor pode ligar remotamente o serviço prestado pelo serviço através do Dubbo, e iniciar as duas partes separadamente para teste
Nota: Ambas as partes devem ser projetos de guerra executáveis de forma independente, sem depender de chamar o serviço do provedor por meio do maven
- Desenvolvimento de interfaces que ambas as partes precisam usar
Razões para usar a interface como um módulo independente:
(1) O provedor precisa implementar esta interface para definir um método específico (serviço), então ele precisa definir esta interface
(2) O consumidor precisa definir esta interface para chamar os métodos na interface (usando o serviço fornecido por este interface)
Isso leva à duplicação da definição desta interface entre as duas partes. Uma vez que a interface é alterada, a modificação das duas partes é complicada, portanto a interface pública é considerada um módulo independente
package com.itheima.service;
public interface UserService {
public String sayHello();
}
//并且需要将此模块install成为jar包
- Desenvolvimento de provedor
(1) O conteúdo do arquivo pom.xml
<groupId>com.itheima</groupId>
<artifactId>dubbo-service</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<!-- war项目 -->
<!-- jar包版本控制 -->
<properties>
<spring.version>5.1.9.RELEASE</spring.version>
<dubbo.version>2.7.4.1</dubbo.version>
<zookeeper.version>4.0.0</zookeeper.version>
</properties>
<dependencies>
<!--Dubbo服务所需jar包-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
</dependency>
<!--ZooKeeper服务所需jar包-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>${zookeeper.version}</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>${zookeeper.version}</version>
</dependency>
<!--依赖公共的接口模块-->
<dependency>
<groupId>com.itheima</groupId>
<artifactId>dubbo-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!--以及其余必须的如spring、springmvc、Log4J等jar包-->
<!--以及tomcat服务器的插件-->
</dependencies>
(2) Conteúdo em web.xml
<context-param>
<param-name>contextConfigLocation</param-name>
<!-- 监听Spring配置文件 -->
<param-value>classpath*:spring/applicationContext*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
(3) Conteúdo em UserServiceImpl
//导入公共接口所在类的包
/**
* 1. @Service注解是Dubbo包下的,并不是Spring包下的
* 2. 使用了此注解的类提供的方法将会对外发布,并将访问地址,端口等注册到注册中心中
*/
@Service
public class UserServiceImpl implements UserService {
@Override
public String sayHello() {
return "hello Dubbo !";
}
}
(4) Conteúdo em applicationContext.xml
<!--Dubbo的配置-->
<!-- 1. 配置项目的名称(自定义),用于注册中心计算项目之间依赖关系,唯一 -->
<dubbo:application name="dubbo-service"/>
<!-- 2. 配置注册中心的地址,用于连接注册中心,address为Zookeeper所在Linux的ip地址及ZooKeeper端口号 -->
<dubbo:registry address="zookeeper://192.168.200.130:2181"/>
<!-- 3. 配置Dubbo的包扫描,使用了Dubbo包下的@Service注解的类会被发布为服务 -->
<dubbo:annotation package="com.itheima.service.impl" />
- Desenvolvimento do consumidor
(1) Conteúdo em pom.xml
<groupId>com.itheima</groupId>
<artifactId>dubbo-web</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<!-- war项目 -->
<!-- jar包版本控制 -->
<properties>
<spring.version>5.1.9.RELEASE</spring.version>
<dubbo.version>2.7.4.1</dubbo.version>
<zookeeper.version>4.0.0</zookeeper.version>
</properties>
<dependencies>
<!--Dubbo服务所需jar包-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
</dependency>
<!--ZooKeeper服务所需jar包-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>${zookeeper.version}</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>${zookeeper.version}</version>
</dependency>
<!--依赖公共的接口模块-->
<dependency>
<groupId>com.itheima</groupId>
<artifactId>dubbo-interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- web模块并没有直接依赖service模块,通过远程调用方式 -->
<!--以及其余必须的如spring、springmvc、Log4J等jar包-->
<!--以及tomcat服务器的插件-->
</dependencies>
(2) Conteúdo em web.xml
<!-- Springmvc -->
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/springmvc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
(3) Conteúdo no UserController
//导入公共接口所在类的包
@RestController
@RequestMapping("/user")
public class UserController {
/**
* 1. @Reference注解导入的为Dubbo包
* 2. @Reference注解作用:
* (1) 从zookeeper注册中心获取提供方的访问url
* (2) 进行远程调用RPC
* (3) 将结果封装为一个代理对象,赋值给userService对象
*/
@Reference
private UserService userService;
@RequestMapping("/sayHello")
public String sayHello(){
return userService.sayHello();
}
}
(4) O conteúdo em springmvc.xml
<mvc:annotation-driven/>
<!-- 扫描使用了Controller注解的类 -->
<context:component-scan base-package="com.itheima.controller"/>
<!--dubbo的配置-->
<!-- 1.配置项目的名称,唯一 -->
<dubbo:application name="dubbo-web" >
<!-- 在同一台机器上同时部署提供方和消费方需要区分二者,否则二者同时使用默认端口22222,冲突 -->
<!-- 实际开发中,提供方与消费方通常部署在不同的机器上,无需关心此项-->
<dubbo:parameter key="qos.port" value="33333"/>
</dubbo:application>
<!-- 2. 配置注册中心的地址-->
<dubbo:registry address="zookeeper://192.168.200.130:2181"/>
<!-- 3. 配置dubbo包扫描,扫描使用了Dubbo包下的@Reference注解 -->
<dubbo:annotation package="com.itheima.controller" />
- resultado da operação
(1) Execute este comando no módulo de serviço e no módulo web separadamente, como os dois projetos de guerra do provedor e do consumidor
(2) As informações de registro após a execução do módulo da web são as seguintes
(3) O efeito da operação é o seguinte
Três, serialização
Quando o provedor (produtor) e o consumidor (consumidor) precisam passar o tipo Pojo, a classe Pojo precisa implementar a interface serializável no pacote IO e se tornar um fluxo binário para transmissão
Quatro, cache de endereço
-
Pergunta: Depois que a central de registro desligar, o serviço pode ser acessado normalmente?
-
Resposta: Sim; porque o consumidor armazenará em cache o endereço do produtor localmente ao chamar o serviço pela primeira vez e não passará pelo registro ao acessar esse endereço posteriormente; quando o endereço do produtor for alterado, o registro notificará O mecanismo notifica os consumidores sobre o novo endereço;
Nota: Depois que a central de registro é desligada, os consumidores existentes podem acessar o serviço, mas os novos consumidores não poderão acessar o serviço
Cinco tempo limite
-
Quando o consumidor chama o serviço do produtor, se houver um bloqueio, espera, etc., o consumidor vai esperar para sempre
-
Em um determinado momento de pico, se um grande número de solicitações for bloqueado, isso causará um fenômeno de avalanche
-
Dubbo usa um mecanismo de tempo limite para resolver este problema. Defina um período de tempo limite. Se o acesso ao serviço não puder ser concluído dentro desse tempo, ele se desconectará automaticamente e relatará um erro de tempo limite.
-
Use o atributo timeout para configurar o período de tempo limite, o valor padrão é 1000, em milissegundos
//timeout属性设置超时时间,单位毫秒;
@Service(timeout = 3000)
- As
@Reference
anotações do consumidor também podem usar o atributo de tempo limite, mas geralmente é recomendado usá-lo no produtor, porque definir o serviço no produtor pode estimar o tempo necessário e facilitar a configuração do tempo limite
Seis, tente novamente
-
Um período de tempo limite foi definido. Se a chamada de serviço não puder ser completada dentro desse tempo, a conexão será automaticamente desconectada e um erro será relatado
-
Se houver um jitter de rede (a rede está instável e temporariamente interrompida, mas rapidamente recuperada), a solicitação falhará
-
Dubbo usa um mecanismo de repetição para evitar tais problemas
-
Defina o número de tentativas por meio do atributo retries, o padrão é dois (mais a primeira solicitação, um total de três)
//retries属性设置重传次数
@Service(timeout = 3000, retries = 3)
Sete, várias versões
-
Quando uma nova versão do serviço do produtor aparecer, nem todos os consumidores terão permissão para acessar esta versão, mas alguns consumidores terão permissão para chamar esta versão primeiro, e após a confirmação de que não há problema, todos os consumidores irão chamar esta versão, que é chamado de liberação de grau cinza
-
Dubbo usa o atributo version para definir e chamar diferentes versões da mesma interface
Código do produtor:
@Service(version = "v1.0", timeout = 3000)
public class UserServiceImpl1 implements UserService {
...}
@Service(version = "v2.0")
public class UserServiceImpl2 implements UserService {
...}
Código do consumidor:
@Reference(version = "v2.0")
private UserService userService;
//成功调用v2.0版本的服务
Oito, balanceamento de carga
- Os consumidores precisam usar estratégias de balanceamento de carga para acessar o cluster produtor. Existem quatro tipos:
(1) Aleatório: Estratégia padrão; definir probabilidade aleatória por peso, quanto maior o peso, mais fácil será acessado
(2) RoundRobin: Sondagem por solicitação
(3) LeastActive: quanto menor o tempo de resposta, mais fácil é ser acessado
(4) ConsistentHash: a mesma solicitação sempre chama o mesmo serviço
Observação: as quatro estratégias são semelhantes à estratégia de balanceamento de carga do Nginx
- Configuração do produtor, defina o peso por meio do atributo de peso, o valor padrão é 100
@Service(weight = 200)
- Configuração do consumidor, defina a política por meio do atributo loadbalance, o valor padrão é aleatório
@Reference(loadbalance = "random")
@Reference(loadbalance = "roundrobin")
@Reference(loadbalance = "leastactive")
@Reference(loadbalance = "consistenthash")
- Nota: Para iniciar vários serviços na mesma máquina, você precisa modificar as duas portas a seguir, cada serviço não pode ser o mesmo para evitar conflitos
Nove, tolerância a falhas de cluster
- Os modos de tolerância a falhas do cluster são os seguintes:
(1) Cluster de Failover: modo padrão; nova tentativa de falha, nova tentativa padrão duas vezes, usar configuração de novas tentativas; quando ocorrer uma falha, relatar um erro e tentar novamente outros servidores duas vezes, geralmente usado para operações de leitura, operações de gravação podem causar gravações devido a atrasos, etc. . Duplicação de dados de entrada
(2) Cluster Failfast: falha rápida; inicie uma chamada, se falhar, um erro será relatado imediatamente sem tentar novamente, geralmente usado para operações de gravação
(3) Cluster Failsafe: Cluster Failsafe: Quando ocorre uma exceção, nenhum erro é relatado, apenas ignorado, e um resultado vazio é retornado
(4) Cluster de failback: recuperação automática da falha; depois que a solicitação falha, o plano de fundo registra a solicitação com falha e a reenvia regularmente
(5) Cluster de bifurcação: chamar vários serviços em paralelo e retornar contanto que um seja bem-sucedido
(6) Cluster de transmissão: Transmita chamadas para todos os provedores, ligue para eles um por um e relate um erro se alguma chamada falhar
- Configuração do consumidor, use o atributo cluster para definir o modo de tolerância a falhas do cluster, o valor padrão é failover
@Reference(cluster = "failover")
X. Degradação do serviço
-
Quando a pressão do servidor é alta, alguns serviços são liberados de acordo com a situação real e apenas os serviços principais são reservados para garantir a operação geral eficiente do serviço
-
Existem duas maneiras de fazer o downgrade do serviço
(1) mock = force: return null: significa que todas as chamadas feitas pelos consumidores para o serviço retornam um valor nulo, que é equivalente a blindar o serviço
(2) mock = fail: return null: indica que a chamada do consumidor para o serviço falha (tentará novamente) e, em seguida, retorna um valor nulo sem relatar um erro
- Configuração do consumidor, use o atributo mock para definir o método de degradação do serviço
@Reference(mock = "force : return null")