Dubbo
单体架构与微服务
单体架构
所有的代码最终打包成一个或多个文件,整个系统的所有功能单元整体部署到同一个进程,这种软件架构的风格,即所谓的"单体架构"
4.png&pos_id=img-FOaeyApt-1706540474228)
单体架构的扩容
一个单体应用在运行时,会部署在一台云服务器上,但是随着用户体量的增长,一台云服务器上运行的一个单体应用,已经无法承载日益增长的请求量,怎么办呢?我们可以对单体应用实现扩容,即使用单体应用集群
通过使用单体应用的集群,可以一定程度上,很好的应对日益增长的用户请求,但是这样就完美了吗? 当然不是
单体架构的优势和弊端
在单体应用的早期,应用程序相对较小,单体架构的好处:
- 应用的开发很简单
- 易于对应用程序进行大规模的更改
- 测试相对直观简单
- 部署简单明了
- 横向扩容不费吹灰之力
但是,随着时间的推移,随着单体应用中包含的功能越来越多,应用的"体积"越来越大,单体应用的弊 端就会逐渐体现出来。
- 代码过度复杂且严重耦合,导致难以维护
- 从代码提交到实际部署的周期很长
- 扩展性受限 开发慢,启动慢,严重影响开发效率
- 交付可靠的单体应用困难
微服务架构
简单理解一个微服务的本质就是一个麻雀虽小但五脏俱全的应用程序,它按照单一职责原则实现了特定的一组功能。
- 因为每个微服务的本质都可以是一个应用程序,这就要求,微服务可以独立部署,独立运行,独立 对外提供服务(运行在一个独立的进程中)
- 每个微服务,根据单一职责原则,实现一组相关功能
在此基础上,什么是微服务架构呢?简单理解,就是把应用程序功能写分解为一组服务的架构风格。实际上,微服务架构是模块化开发的一种形式。
模块化是开发大型,复杂应用程序的基础。当一个单体应用程序的规模太大的时候,是很难作为一个整体开发,也很难让一个人完全理解的。为了让不同的人开发和理解(不同的部分),大型应用需要拆分模块。
- 在单体应用中,模块通常由一组编程语言所提供的的结构(例如Java中的包,或者jar文件)来定义, 但是通过这种方式得到的模块,不同模块的代码还是可以相互引用,导致模块中对象依赖关系的混 乱
而微服务架构,使用微服务作为模块化的单元,要访问服务,只能通过服务对外提供的API,于是服务的API为它自身构筑了一个不可逾越的边界,你无法越过APII去访问服务内部的类。
!
微服务的优势和弊端
使用微服务架构,可以解决庞大的单体应用的痛点,带来很多好处:
- 每个服务都相对较小,容易维护
- 使得大型的应用程序实现快速的持续交付和持续部署
- 应用扩展灵活
- 更好的容错
当然,使用微服务也会带来一些弊端
- 分布式系统可能复杂难以管理
- 分布式部署追踪问题难
- 分布式事务比较难处理
- 服务数量增加,管理复杂性增加
微服务的拆分
微服务的实现
Dubbo框架
基本介绍
Apache Dubbo 是一款微服务开发框架,它提供了 RPC通信 与 微服务治理 两大关键能力。这意味着, 使用 Dubbo 开发的微服务,将具备相互之间的远程发现与通信能力, 同时利用 Dubbo 提供的丰富服 务治理能力,可以实现诸如服务发现、负载均衡等服务治理诉求。同时 Dubbo 是高度可扩展的,用户 几乎可以在任意功能点去定制自己的实现,以改变框架的默认行为来满足自己的业务需求
这里就涉及到了一个RPC(Remote Process Call)通信的概念,维基百科的定义如下:
1. 是一个计算机通信协议。 2. 该协议允许运行于一台计算机的程序调用另一个地址空间(通常为一个开放网络的一台计算机)的子程 序,而程序员就像调用 本地程序一样,无需额外地为这个交互作用 编程(无需关注细节) 3. 如果涉及的软件采用面向对象编程,那么远程过程调用亦可称作远程调用或远程方法调用
Dubbo的基本概念
Dubbo中,在服务调用的过程中定义了两个角色
- 服务消费者: 即调用服务的一方(可能是服务,也可能不是)
- 服务提供者: 被调用的服务
服务调用RPC的原理
class DemoServiceInvoker implements DemoService { // 服务暴露协议 String protocol; // 服务提供者进程所在的主机ip String targetIp; int port; /* 当在代理对象上调用这个方法的时候,就说明,我们想要 调用的是实现DemoService接口的服务的,sayHello方法 */ public String sayHello(String name) throws IOException { // 1. 建立Socket连接 Socket socket = new Socket(targetIp, port); // 2. 发送调用的请求 OutputStream out = socket.getOutputStream(); // 按照dubbo协议的规定,封装请求数据,并发送 // 1. 调用的是实现了哪个接口的服务 // 2. 要调用服务中的哪个方法 // 3. 方法运行所需要的实际参数 // 4. 方法返回值类型 // ...... //out.write(); InputStream in = socket.getInputStream(); //in.read() return null; } }
服务的注册与自动发现
服务注册中心
- 在服务提供者启动的时候,Dubbo会负责将服务提供者实现的接口,所在的主机ip,服务暴露的 协议,及端口号等等信息,告诉注册中心,于是注册中心中就保存了所有的服务相关信息
- 在服务消费者启动时,主动去注册中心进行服务订阅
- 告诉注册中心,它要调用实现了什么接口的服务提供者,并将自己的信息,也注册到注册中 心,这样一来当实现改接口的服务提供者状态,改变的的时候(比如新增,或减少),服务注册 中心会主动通知服务消费者 将注册中心中,实现了自己想要调用的接口的服务提供者列表信息,拉取到本地
Dubbo的服务注册中心
服务注册中心的实现有多种不同的方式,而Dubbo使用的服务注册中心,是基于Zookeeper这个分布式 协调服务器实现。
有了服务注册中心之后,Provider和Consumer的配置也会发生一点改变
Consumer
<!--1. 定义服务消费者的名字--> <dubbo:application name="spring-consumer36"/> <!--2.定义服务的引用对象--> <dubbo:reference id="demoService" interface="com.cskaoyan.api.DemoService"/> <!--3. 注册中心--> <dubbo:registry address="zookeeper://localhost:2181"/>
Provider
<!--1. 定义服务提供者的名字--> <dubbo:application name="spring-provider36"/> <!--2. 将服务接口的实现类对象,放入Spring中--> <bean id="demoService" class="com.cskaoyan.service.DemoServiceImpl"/> <!--3. 定义对外暴露的服务对象--> <dubbo:service interface="com.cskaoyan.api.DemoService" ref="demoService"/> <!--4. 暴露服务 --> <dubbo:protocol name="dubbo" port="20880"/> <!--5. 注册中心--> <dubbo:registry address="zookeeper://localhost:2181"/>
Dubbo与SpringBoot的整合
Dubbo与SpringBoot的整合也需定义服务暴露的接口及服务API,服务提供者和服务消费者。
- api的实现
public interface DemoService { String sayHello(String name); }
- 服务提供者的实现和yml文件的配置,和与Spring的整合稍有不同,在和SpringBoot整合时,可以 使用注解
// 服务接口实现类,同时注意这里的@Service注解是Dubbo的Service注解 @Service public class DemoServiceImpl implements DemoService { @Override public String sayHello(String name) { return "0hello, " + name; } }
yml配置
dubbo: application: name: springboot-provider361 #服务提供者名称 protocol: name: dubbo #服务暴露协议 port: 20880 #服务暴露端口号 registry: address: zookeeper://localhost:2181 #服务注册中心 scan: base-packages: com.cskaoyan.dubbo.service #注解扫描路径
- 服务消费者的实现
@Component public class ThirdService { @Reference(loadbalance = "consistenthash") DemoService demoService; public String sayHello(Person person) { // 远程方法调用 return demoService.sayHello(person); } }
启动类
public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(Consumer36Application.class, args); // 直接实现服务的远程调用 ThirdService service = context.getBean(ThirdService.class); Person person = new Person("长风"); String result = service.sayHello(person); System.out.println(result); // int firstCount = 0; // int thirdCount = 0; // int fourthCount = 0; // for (int i = 0; i < 30; i++) { // // String result = service.sayHello("长风"); // if (result.startsWith("1")) { // firstCount++; // System.out.println("first: " + result); // } else if (result.startsWith("3")) { // thirdCount++; // System.out.println("third: " + result); // } else { // fourthCount++; // System.out.println("fourth: " + result); // } // } // // System.out.println("first: " + firstCount); // System.out.println("third: " + thirdCount); // System.out.println("fourth: " + fourthCount); }
配置文件
dubbo: application: name: springboot-consumer36 #消费者名称 registry: address: zookeeper://localhost:2181 #注册中心
pom文件通用依赖
<!--Dubbo相关依赖--> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>2.7.3</version> </dependency> <!--zookeeper--> <dependency> <groupId>org.apache.zookeeper</groupId> <artifactId>zookeeper</artifactId> <version>3.4.13</version> </dependency> <!--zookeeper 底层依赖curator--> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>2.10.0</version> </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-recipes</artifactId> <version>2.10.0</version> </dependency>
此外,还需要导入依赖的common-api的依赖
服务调用的负载均衡
主要的策略:
直接在调用的@Reference注解上面增加loadbalance 属性即可,但是要注意名称是全小写的字符串
Dubbo的常见问题
有了注册中心之后还会用到点对点模式吗
点对点模式主要还是会用在测试的场景之中,如果一组服务中出现了问题,那么就需要使用点对点模式进行拆分测试
Dubbo与Springcloud的rpc的区别
Dubbo的通信使用的是dubbo协议,所以provider不需要运行在tomcat中,但是Springcloud使用的协议是http协议,这就需要运行在tomcat容器中,否则无法正常的处理请求
主要的策略:
[外链图片转存中…(img-hWfN3HQS-1706540474231)]
直接在调用的@Reference注解上面增加loadbalance 属性即可,但是要注意名称是全小写的字符串
Dubbo的常见问题
有了注册中心之后还会用到点对点模式吗
点对点模式主要还是会用在测试的场景之中,如果一组服务中出现了问题,那么就需要使用点对点模式进行拆分测试
Dubbo与Springcloud的rpc的区别
Dubbo的通信使用的是dubbo协议,所以provider不需要运行在tomcat中,但是Springcloud使用的协议是http协议,这就需要运行在tomcat容器中,否则无法正常的处理请求