一、基于zookeeper+dubbo组合的分布式系统
分布式系统中,常用zookeeper+dubbo组合
- zookeeper:一个分布式的、开放源码的分布式应用程序协调服务。提供的功能:配置维护、域名服务、分布式同步、组服务
- dubbo:分布式服务框架,按照分层的方式来架构,使各层解耦。模型简单,分为服务提供方和服务消费方
例子:有两个模块A、B,dubbo负责解决A模块和B模块的远程过程调用(RPC问题),A需要通过注册中心(zookeeper)得到B的地址再进行调用。
dubbo框架工作图如下图:
- dubbo的服务容器Container,启动时启动和加载Provider(服务提供者)
- 服务提供者(Provider)启动时,将自己能提供的服务信息注册到注册中心(Registry)】
- 服务消费者(Consumer)启动时会从注册中心订阅所需要的服务
- 注册中心会把所需服务的地址列表返回给服务消费者(如果服务有变更,注册中心会基于长连接的方式将信息变更给消费者)
- 消费者需要调用时,会从提供者的地址列表中找到某个提供者的位置,调用他的服务,服务失败,会从地址列表中找寻另一个服务器供着并调用服务,直到调用成功
- 监控中心(Monitor)有监控机制,会获得调用次数、调用时间等信息,进行监控
二、配置分布式框架
1、docker安装zookeeper
sudo docker pull zookeeper
2、运行zookeeper,虚拟机的2181映射到容器的2181端口
sudo docker run --name zookeeper01 -p 2181:2181 --restart always -d zookeeper镜像id
镜像包括了三个端口:2181(客户端交互端口)、2888(集群端口)、3888(选举端口),这里只用交互端口
3、添加依赖
dubbo:
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.1.0</version>
</dependency>
zookeeper:(zkclient)
<!--引入zookeeper的客户端工具-->
<!-- https://mvnrepository.com/artifact/com.github.sgroschupf/zkclient -->
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
三、启动提供服务–消费服务功能
1、配置服务项目
步骤:
- 引入dubbo和zkclient相关依赖(按照配置中第3、4步配置)
- 配置dubbo的扫描包和注册中心地址
配置dubbo应用的名称
dubbo要把应用发布到注册中心zookeeper中:添加注册中心地址
配置扫描要发布出去的包的名称
dubbo.application.name=provider-ticket
dubbo.registry.address=zookeeper://192.168.0.104:2181
dubbo.scan.base-packages=com.atguigu.ticket.service
- 服务提供者的服务层,使用@Service发布服务,在需要发布的服务类前添加dubbo的@Service(该类一定要是某一接口的具体实现类,是直接提供服务的类)
import com.alibaba.dubbo.config.annotation.Service;
import org.springframework.stereotype.Component;
@Component
@Service //将服务发布出去
public class TicketServiceImpl implements TicketService {
@Override
public String getTicket() {
return "《厉害了,我的国》";
}
}
- 启动该应用项目的main,dubbo就会根据注册中心的地址,将加了@Service的服务发布出去
2、配置服务消费者
步骤:
- 引入dubbo和zkclient相关依赖(按照第3、4步配置)
- 配置dubbo的注册中心地址
dubbo.application.name=consumer-user
dubbo.registry.address=zookeeper://192.168.0.104:2181
- 消费者的服务层,需要添加@Service注解,引用服务(远程引用、消费服务就用 @Reference注解所调用服务的类名)
import com.alibaba.dubbo.config.annotation.Reference;
import com.atguigu.ticket.service.TicketService;
import org.springframework.stereotype.Service;
@Service
public class UserService{
@Reference
TicketService ticketService;
public void hello(){
String ticket = ticketService.getTicket();
System.out.println("买到票了:"+ticket);
}
}
-------ps-------:消费服务时会需要远程引用提供的服务,所以在需要调用的服务 TicketService 前面要添加@Reference进行远程引用,引用时会按照TicketService的全类名进行匹配,找到哪个服务在注册中心发布了服务。所以服务消费者引用的服务类接口的全类名需要与服务提供者的服务类接口的全类名相同(TicketService接口都需要放在com.atguigu.ticket.service包下),消费者调用接口中的方法ticketService.getTicket()时,会直接调用远程服务提供者的相关功能。
4、测试消费者消费服务的功能
在测试类中注入服务消费者的服务层(@Service),调用消费者功能时,也会远程调用服务者的服务。这里调用了消费者的hello()方法,会远程调用服务提供者的getTicket()方法,得到结果如下图所示:
import com.atguigu.user.service.UserService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@SpringBootTest
public class ConsumerUserApplicationTests {
@Autowired
UserService userService;
@Test
public void contextLoads() {
userService.hello();
}
}
利用Spring Boot配置dubbo总结:
- pom.xml文件中添加dubbo、zookeeper依赖,如果bean文件和提供的服务类需要分开到单独的项目中时,也要在pom中添加该项目的依赖
- application.properties中,服务提供者添加:应用名称、注册中心地址、提供服务的包名;消费者提供:应用名称、注册中心地址
- 服务提供者需要暴露服务,用@Service注解;服务消费者需要消费服务、远程引用服务类方法,用@Reference注解
- 基于接口的远程调用,消费者用@Reference注解的服务全类名需要与服务提供者提供服务的接口的全类名相同,调用时会自动调用接口的具体实现类作为提供的服务。
四、dubbo超时与配置
配置覆盖关系:
- 方法级优先(越精确的优先),接口级次之,全局配置再次之
- 如果级别一样,则消费方优先,提供方次之
(例如提供者timeout为1s,消费者timeout为5s,实际延时为3s,则消费者依然可以调用成功,因为满足在5s延时内)
reference(方法级)>service(方法级)>reference(接口级)>service(接口级)>consume(统一配置服务消费者的规则)>provide(统一配置服务提供者的规则)