分布式+Dubbo+Zookeeper
架构发展
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uVJBvnEF-1620458493178)(https://dubbo.apache.org/imgs/user/dubbo-architecture-roadmap.jpg)]
单一应用架构
当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。此时,用于简化增删改查工作量的数据访问框架(ORM)是关键。
垂直应用架构
当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,提升效率的方法之一是将应用拆成互不相干的几个应用,以提升效率。此时,用于加速前端页面开发的Web框架(MVC)是关键。
分布式服务架构
当垂直应用越来越多,应用之间交互不可避免,将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提高业务复用及整合的分布式服务框架(RPC)是关键。
流动计算架构(云)
当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增加一个调度中心基于访问压力实时管理集群容量,提高集群利用率。此时,用于提高机器利用率的资源调度和治理中心(SOA)是关键。
RPC
remote produce call 远程调用
Http协议是负责通信的,RPC也是负责通信的。
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/fbc81950f177df66c80eed5ebfb860ba.png)
RPC两个核心模块
通讯 & 序列化
序列化:方便数据在网络中的传输。
Dubbo就是做这些事情的。
Dubbo [ˈdʌbl]
官网:https://dubbo.apache.org/zh/docs/v2.7/user/quick-start/
github下载:https://github.com/apache/dubbo-admin/tree/master
Apache Dubbo 是一款高性、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用;智能容错和负载均衡;以及服务自动注册和发现。
![dubbo-architucture](https://i-blog.csdnimg.cn/blog_migrate/02b28cb2c3f1851d99a60219fe4ad614.jpeg)
async 异步
sync 同步
monitor 监控
节点角色说明
节点 | 角色说明 |
---|---|
Provider | 暴露服务的服务提供方 |
Consumer | 调用远程服务的服务消费方 |
Registry | 服务注册与发现的注册中心 |
Monitor | 统计服务的调用次数和调用时间的监控中心 |
Container | 服务运行容器 |
调用关系说明
- 服务容器负责启动,加载,运行服务提供者。
- 服务提供者在启动时,向注册中心注册自己提供的服务。
- 服务消费者在启动时,向注册中心订阅自己所需的服务。
- 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
- 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
- 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
安装Dubbo
github地址:https://github.com/apache/dubbo-admin/tree/master
在cmd打成jar包 :
mvn clean package -Dmaven.test.skip=true
也可以用idea打开dubbo项目,点击maven的package打包!
打包完成后每个目录下的target中会有jar包!
dubbo-admin
是一个监控管理后台
打开dubbo-admin
目录下的jar包
D:\Environment\dubbo-admin-master\dubbo-admin\target>java -jar dubbo-admin-0.0.1-SNAPSHOT.jar
访问本地默认端口:7001
默认账号:root root
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/cc35c14b11e796492a2d091ab2c98a7f.png)
Zookeeper
ZooKeeper 是一个开源的分布式协调服务,它的设计目标是将那些复杂且容易出错的分布式一致性服务封装起来,构成一个高效可靠的原语集,并以一系列简单易用的接口提供给用户使用。是Dubbo推荐的一种注册中心
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/02af8c73424439e4019f2c835931ec35.png)
服务端:zkServer.cmd
客户端:zkCLi.cmd
启动服务端,在客户端操作
[zk: localhost:2181(CONNECTED) 0] ls / # 查目录
[zookeeper]
[zk: localhost:2181(CONNECTED) 1] create -e /kuangshen 123 # 创建结点 kuangshen , 值是123
Created /kuangshen
[zk: localhost:2181(CONNECTED) 2] ls /
[kuangshen, zookeeper]
[zk: localhost:2181(CONNECTED) 3] get /kuangshen # 获取结点信息
123
cZxid = 0x4
ctime = Sun Feb 07 10:08:54 CST 2021
mZxid = 0x4
mtime = Sun Feb 07 10:08:54 CST 2021
pZxid = 0x4
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x1777a3d9d820000
dataLength = 3
numChildren = 0
[zk: localhost:2181(CONNECTED) 4]
代码实现
新建springboot项目,添加两个module,一个provider,一个consumer
提供者
1.导入依赖
<!--导入依赖-->
<!-- https://mvnrepository.com/artifact/org.apache.dubbo/dubbo-spring-boot-starter -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.3</version>
</dependency>
<!--zkclient-->
<!-- https://mvnrepository.com/artifact/com.github.sgroschupf/zkclient -->
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
</dependency>
<!--日志会冲突-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.12.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.12.0</version>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.14</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
2.实现类
package com.zhu.service;
import org.apache.dubbo.config.annotation.Service;
import org.springframework.stereotype.Component;
@Service // dubbo的注解,可以被扫描注册到注册中心
@Component // spring的注解,加入到spring容器中
public class TicketServiceImpl implements TicketService{
@Override
public String getTicket() {
return "狂神说Java";
}
}
3.配置
# 端口
server.port=8001
# 服务应用名字
dubbo.application.name=provider-ticket-server
# 注册中心地址
dubbo.registry.address=zookeeper://127.0.0.1:2181
# 要注册的服务
dubbo.scan.base-packages=com.zhu.service
4.启动zookeeper
zkServer.cmd
5.程序启动
6.查看dubbo监控后台
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/f85b2aa94bab6c3fa898df7c05e79029.png)
消费者
- 依赖
- 实现类
package com.zhu.service;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.stereotype.Component;
@Component
public class UserService {
// 想要拿到provider-server提供的类,要去注册中心拿到服务
@Reference // 引用外部的类,正常开发是引用pom的坐标,练习中可以定义路径相同的接口名
TicketService ticketService;
public void butTicket(){
String ticket = ticketService.getTicket();
System.out.println("在注册中心拿到票:"+ticket);
}
}
- 配置
server.port=8002
# 消费者去注册中心拿服务需要暴露自身name
dubbo.application.name=consumer-server
# 注册中心的地址
dubbo.registry.address=zookeeper://127.0.0.1:2181
- 编写测试类
@SpringBootTest
class ConsumerServerApplicationTests {
@Autowired
UserService userService;
@Test
void contextLoads() {
userService.butTicket();
}
}
在注册中心拿到票:狂神说Java
@Reference注解做了什么
问:被@Reference 注解的 bean,通常是一个接口,怎么可以被实例化呢?
答: @Reference修饰的域是通过动态代理实现的。也就是生成了一个动态的接口实现类。
如果provider有两个实现相同接口的类,那么会看Dubbo的@Service注解,哪个实现类有这个注解,调的就是这个类的方法。如果两个类都有这个注解,默认调第一个。
推测:Dubbo会查找容器中所有被注册的bean,看哪个bean有Dubbo的@Service注解,就通过动态代理,生成接口的实现类。消费者调用的就是这个方法。