【SpringBoot】Dubbo、Zookeeper
文章目录
- 前提知识概要
- 分布式系统
- 单体架构
- 垂直应用架构
- 分布式架构
- 流式架构
- RPC
- Dubbo
- 概念
- Dubbo环境搭建
- Zookeeper
- 测试 Zookeeper
- Window环境下使用Dubbo-admin
- 版本匹配不对
- 服务注册实战
- 内容总结
- 导入相关依赖
- 选择 Zookeeper 版本
- 配置并启用 Zookeeper
- 创建服务接口和实现(DubboService)类,这里是配置`Provider`
- 启动Dubbo的扫描(EnableDubbo)
- 重复上述操作,将需要注册Dubbo的配置下
- 编写Service,这次是消费者,调用提供者所提供的内容
前提知识概要
分布式系统
- “分布式系统是若干独立计算机的集合,这些计算机对于用户来说就像单个相关系统”;
- 其目的是利用更多的机器,处理更多的数据。
- 用小而多,代替大且贵
- 只有当单个节点的处理能力无法满足日益增长的计算、存储任务的时候,且硬件的提升(加内存、加磁盘、使用更好的CPU)高昂到得不偿失的时候,应用程序也不能进一步优化的时候,我们才需要考虑分布式系统;
- 分布式系统要解决的问题本身就是和单机系统一样的,而由于分布式系统多节点、通过网络通信的拓扑结构,会引入很多单机系统没有的问题,为了解决这些问题又会引入更多的机制、协议,带来更多的问题;
- 但是 缺点也在于这里 过分的依赖于 网络通信协议;
单体架构
网络吞吐量小时,使用一个应用(application),将所有的功能都部署在一起,以减少部署的节点和成本。为此简化CRUD的数据访问框架ORM就是关键。
ORM:Mybatis、Hibernate
使用场景:小型网站,将所有功能都部署到一个地方,简单,易用
缺点:
- 性能扩展比较难
- 协同开发问题
- 不利于升级维护
垂直应用架构
数据吞吐量打的时候,单一的应用会增加机器所在压力,将应用的几块拆成互不相干的几个应用以提升效率。这个时候加速前端页面开发的WEB框架又是关键:
WEB框架:MVC,MVVM
通过切分业务 来实现各个模块的独立部署,降低了维护和部署的难度,团队各司其职更易管理,性能拓展也更加的方便,更有针对性。
缺点:
- 公用的模块无法重复利用;
- 多重复写功能导致资源浪费;
分布式架构
当垂直的应用越来越多,应用之间的交互不可避免,就去优化垂直应用架构;
将核心的业务提取,成为独立的服务,逐步形成稳定的服务中心,是前段更好的应用市场。
提高业务服用整合的**分布式框架 **又是关键。
分布式框架:RPC
流式架构
当服务越来越多,容量的评估,小服务资源的浪费等问题逐渐显现,这个时候有需要一个调度中心,能够将有限的资源得到最大的利用, 这时候,用于提高机器利用率的资源调度又成为了重点
提高机器利用率的资源调度和治理中心(SOA)[Service Oriented Architecture]是关键
RPC
RPC【Remote Procedure Call】是指远程过程调用,是一只进程思想,而不是一种规范,类似于我们的。
允许程序调用另一个地址空间。(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。
两台服务器A、B,主要是部署在A服务器上,想要调用B服务器,但是不在一个机器中,不能直接去调用,需要利用网络,通过网络传输将自己想要的数据及想要在B服务站执行的内容 传输过去。
RPC 所实现的内容就是让A服务器调用B服务器 的过程被忽略,在调用函数的时候像调用A自己本身的函数一样;
RPC的两个核心就是:通讯(HTTP、RPC)、序列化(序列化的方式就是方便数据传输);
如何给老婆解释什么是RPC
假设你有一个计算器接口,Calculator,以及它的实现类CalculatorImpl,那么在系统还是单体应用时,你要调用Calculator的add方法来执行一个加运算,直接new一个CalculatorImpl,然后调用add方法就行了,这其实就是非常普通的本地函数调用,因为在同一个地址空间,或者说在同一块内存,所以通过方法栈和参数栈就可以实现。
现在,基于高性能和高可靠等因素的考虑,你决定将系统改造为分布式应用,将很多可以共享的功能都单独拎出来,比如上面说到的计算器,你单独把它放到一个服务里头,让别的服务去调用它。
**问题:**服务A里头并没有CalculatorImpl这个类,那它要怎样调用服务B的CalculatorImpl的add方法呢?
- 可以模仿B/S架构的调用方式呀,在B服务暴露一个Restful接口,然后A服务通过调用这个Restful接口来间接调用CalculatorImpl的add方法。
很好,这已经很接近RPC了,不过如果是这样,那每次调用时,是不是都需要写一串发起http请求的代码呢?比如httpClient.sendRequest…之类的,能不能像本地调用一样,去发起远程调用,让使用者感知不到远程调用的过程呢,像这样:
- 用代理模式呀!而且最好是结合Spring IoC一起使用,通过Spring注入calculator对象,注入时,如果扫描到对象加了@Reference注解,那么就给它生成一个代理对象,将这个代理对象放进容器中。而这个代理对象的内部,就是通过httpClient来实现RPC远程过程调用的。
就是很多RPC框架要解决的问题和解决的思路,比如阿里的Dubbo。
ps:Dubbo以前是阿里的,后来才移交给了Apache
RPC要解决的两个问题:
- 解决分布式系统中,服务之间的调用问题。
- 远程调用时,要能够像本地调用一样方便,让调用者感知不到远程调用的逻辑。
RPC很少用到http(超文本传输协议)协议来进行数据传输,毕竟我只是想传输一下数据而已,何必动用到一个文本传输的应用层协议呢,我为什么不直接使用二进制传输?比如直接用Java的Socket协议进行传输。
以左边的Client端为例,Application就是rpc的调用方,Client Stub就是我们上面说到的代理对象,也就是那个看起来像是Calculator的实现类,其实内部是通过rpc方式来进行远程调用的代理对象,至于Client Run-time Library,则是实现远程调用的工具包,比如jdk的Socket,最后通过底层网络实现实现数据的传输。
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
作者:柳树之
链接:https://www.jianshu.com/p/2accc2840a1b
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
Client将数据进行序列化 传输给Server,Server对数据进行反序列化,读取数据内容,只进行服务调用,程序处理,将处理的内容结果通过在进行序列化 传输到Client,最终实现全局的调用;
Dubbo
类比于SpringCloud,都是使用的分布式架构思想,但是Dubbo
是一个框架,而SpringCloud
是一套整合于Spring的生态;
概念
Apache Dubbo |ˈdʌbəʊ| 是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:
- 面向接口的远程方法调用;
- 智能容错和负载均衡;
- 服务自动注册和发现;
官网:cn.dubbo.apache.org
QuickStart:https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/quick-start/starter/
- 基本概念
**服务提供者(**Provider):暴露服务的服务提供方,服务提供者在启动时,向注册中心注册自己提供的服务。
服务消费者(Consumer):调用远程服务的服务消费方,服务消费者在启动时,向注册中心订阅自己所需的服务,服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
注册中心(Registry):注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者
监控中心(Monitor):服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心
调用关系:
- 服务
Provider
容器Container
负责启动start
,加载,运行服务提供者。 - 服务提供者
Provider
在启动时,向注册中心Registry
注册register
自己提供的服务。 - 服务消费者
Consumer
在启动时,向注册中心Registry
订阅subscribe
自己所需的服务。 - 注册中心
Registry
返回服务提供者Provider
地址列表通知notify
给消费者,如果有变更,注册中心将基于长连接推送invoke
变更数据给消费者。 - 服务消费者
Consumer
,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
Dubbo环境搭建
在最新的3.3.0
版本官网上,可以直接创建你 基于Spring Boot 的微服务应用 ,需要注意
因为是看的狂神的20年的视频,所以先按照他当时的做法思路使用zookeeper
,这个要参照官网
Zookeeper
学习文档:https://cn.dubbo.apache.org/zh-cn/overview/reference/integrations/zookeeper/
Zookeeper: https://zookeeper.apache.org/releases.html
- 下载Zookeeper
下载3.8.4 是稳定版;
官网太慢,去镜像站下载:https://mirrors.aliyun.com/apache/zookeeper
- 解压
apache-zookeeper-3.8.4
,widows
运行"D:\work\apache-zookeeper-3.8.4\bin\zkServer.cmd"
,添加pause
,报错查看错误信息 - 解决
java.lang.ClassNotFoundException
问题
发现调用jar包找不到,我下载的是源码版,重新下载个二进制版,把lib
copy进去,网络不好的情况下不要自己编译。
- 解决
Error processing D:\work\apache-zookeeper-3.8.4\bin\..\conf\zoo.cfg
的问题
目录下没有zoo.cfg
文件,copy sample生成一个,根据上述内容配置,然后启动
- 启动成功
测试 Zookeeper
- run
zkCli.cmd
,显示连接成功; create –e /aaa 123
:创建一个aaa节点,值为123
在 Zookeeper 3.8 版本之后,create -e(表示创建一个带有 ephemeral 选项的节点)已被废弃。现在,如果你想创建一个临时节点(ephemeral node),你应该使用 create 命令时直接指定 -e 参数后面跟路径和数据。
get /aaa
,显示没有创建?检查问题,重新创建使用create /aaa 123
就好了;
Window环境下使用Dubbo-admin
在官网可以看到这段描述,Dubbo-admin可以对整个集群进行查询调用,
官网:
- https://cn.dubbo.apache.org/zh-cn/overview/reference/proposals/admin/
- https://cn.dubbo.apache.org/zh-cn/overview/notices/admin/
文档编辑完 没检查就提交了 哈哈哈
- 下载Dubbo-admin
- https://cn.dubbo.apache.org/zh-cn/overview/reference/setup/install/
- https://cn.dubbo.apache.org/zh-cn/download/
- 下载完解压,使用目前最新的 最稳定版本,解压 ;
- 检查
dubbo-admin-server\src\main\resources\application.properties
的端口号配置; - 打包 cd 到根目录
mvn clean package -Dmaven.test.skip=true
,等待打包完成; - 执行打包好的jar包
java -jar dubbo-admin-0.4.0.jar
, Session 0x0 for server 127.0.0.1/<unresolved>:2181, unexpected error, closing socket connection and attempting reconnect
提示报错,配置host文件 把localhost的地址映射加进去;- 一直启动失败??问题好奇怪
- 访问
http://localhost:7001/
?,默认账号名root
密码root
版本匹配不对
对应的版本不对?
- Dubbo Admin 0.4.0发布于2020年,其设计主要针对JDK8环境
- Zookeeper 3.8.4对JDK17的支持尚不完善,已知存在NIO通道问题
更换完版本后,启动依旧报错,系统提示 java.lang.IllegalStateException
java.lang.IllegalStateException: zookeeper not connected, the address is: zookeeper://127.0.0.1:2181/org.apache.dubbo.config.ConfigCenterConfig?check=true&config-file=dubbo.properties&group=dubbo&highest-priority=false&namespace=dubbo&timeout=30000 at org.apache.dubbo.remoting.zookeeper.curator.CuratorZookeeperClient.<init> (CuratorZookeeperClient.java:118)
Jdk17连接zookeeper报错:127.0.0.1/<unresolved>:2181_java.lang.illegalargumentexception: unable to cano-CSDN博客
使用 Dubbo Admin 0.6.0看看,访问 http://localhost:38080
好了,终于进去了,使用Dubbo Admin 0.6.0
也是报错,之后再去检查pom中的依赖,发现org.apache.zookeeper
的依赖默认版本是zookeeper-3.4.14,于是将他升级为最新版,启动成功。其他问题还在等待校验。
服务注册实战
官方文档: https://cn.dubbo.apache.org/zh-cn/overview/mannual/java-sdk/tasks/service-discovery/zookeeper/
内容总结
- zookeeper :一个jar包 (必须存在)
- dubbo-admin:是一个监控管理后台 (可有可无)
- Dubbo:jar包 (需要用)
- 最新的Dubbo 有好多实现方案,根据具体情况使用,阿里云本身有nacos
导入相关依赖
- SpringBoot
<dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId><version>3.3.0</version>
</dependency>
<!-- 仅当 Zookeeper Server 版本是 3.4.x 及以下时,使用此依赖 -->
<dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-zookeeper-spring-boot-starter</artifactId><version>3.3.0</version>
</dependency>
<!-- 仅当 Zookeeper Server 版本是 3.5.x 及以上时,使用此依赖-->
<dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-zookeeper-curator5-spring-boot-starter</artifactId><version>3.3.0</version>
</dependency>
检查自己 的Zookeeper的版本是 3.8.4
所以使用dubbo-zookeeper-curator5-spring-boot-starter
;
找不着依赖就mvn clean install
- 不使用SpringBoot
<dependencies><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo</artifactId><version>3.3.0</version></dependency><!-- This dependency helps to introduce Curator and Zookeeper dependencies that are necessary for Dubbo to work with zookeeper as transitive dependencies. --><!-- 仅当 Zookeeper Server 版本是 3.4.x 及以下时,使用此依赖 --><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-dependencies-zookeeper</artifactId><version>3.3.0</version><type>pom</type></dependency><!-- 仅当 Zookeeper Server 版本是 3.5.x 及以上时,使用此依赖 --><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-dependencies-zookeeper-curator5</artifactId><version>3.3.0</version><type>pom</type></dependency></dependencies>
选择 Zookeeper 版本
Dubbo 3.3.0 版本开始正式支持 JDK 17,如果您使用 JDK 17,则必须选用 dubbo-dependencies-zookeeper-curator5 或 dubbo-zookeeper-curator5-spring-boot-starter 依赖,对应的 Zookeeper Server 推荐是 3.8.0 版本及以上。
::当前使用的最新稳定版 3.8.4
配置并启用 Zookeeper
配置properties
,注册中心的地址,服务发现名 和 扫描包
# dubbo.properties
dubbo.registry.address=zookeeper://localhost:2181
# 新用户请设置此值,表示启用应用级服务发现,可选值 interface、instance、all,默认值为 all,未来版本将切换默认值为 instance
dubbo.registry.register-mode=instance
address 是启用 zookeeper 注册中心唯一必须指定的属性,而在生产环境下,address 通常被指定为集群地址,如 address=zookeeper://10.20.153.10:2181?backup=10.20.153.11:2181,10.20.153.12:2181
protocol 与 address 分开配置的模式也可以,
如 <dubbo:registry protocol="zookeeper" address="10.20.153.10:2181,10.20.153.11:2181,10.20.153.12:2181" />
创建服务接口和实现(DubboService)类,这里是配置Provider
使用@DubboService
的注解 ,为了将接口暴漏出去,使外部接口可以扫描的到TicketService
package com.demo.service.impl;import com.demo.service.TicketService;
import org.apache.dubbo.config.annotation.DubboService;@DubboService
public class TicketImpl implements TicketService {@Overridepublic String getTicket() {return "Mrs.K sailed ticket";}
}
启动Dubbo的扫描(EnableDubbo)
- 如果没有找到注解
@EnableDubbo
,记得去更新下maven包,看看有没有把依赖导进来,依赖启动器导入的情况下一般就能够发现;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@EnableDubbo
@SpringBootApplication
public class Springboot09DubboserveApplication {public static void main(String[] args) {SpringApplication.run(Springboot09DubboserveApplication.class, args);}}
- 启动项目测试,项目正常启动,
- 服务测试
重复上述操作,将需要注册Dubbo的配置下
- 配置端口,注册地址;
- 启动类开启Dubbo;
编写Service,这次是消费者,调用提供者所提供的内容
在Dubbo中,分提供者Provider
和消费者Consumer
两个概念;
- 提供者实现接口,提供具体的实现内容;
- 消费者负责调用接口,使用提供者所实现的功能;
- 因为不是在一个服务中启动,所以存在RPC的管理,Dubbo的解决方案由此而生;
- 在Dubbo中,消费者所需要使用的是Refer,选择指向的地址
@DubboReference
@Component
public class UserServiceImpl implements UserService {//我们需要去拿去注册中心的服务@DubboReferenceprivate TicketService ticketService;public void buyTicket() {System.out.println("》》User正在买票...");System.out.println("User正在调用ticket服务...");System.out.println(ticketService.getTicket());System.out.println("调用Ticket完成《《");}}
- 这样子代码就会去找
TicketService
接口,但是因为TicketService
是在另一个服务中启用的,所以需要把那个接口在这重现一下
package com.demo.service;public interface TicketService {String getTicket();}
- 在Dubbo-admin中查找,启用成功
- 代码测试,要先关闭Dubbo-admin,还是不行。。。
技术没到家,一直在报端口占用服务冲突的错
package com.demo;import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import com.demo.service.UserService;@SpringBootTest
class Springboot09DubboserveApplicationTests {@AutowiredUserService userService;@Testvoid contextLoads() {userService.buyTicket();}
}
- 写个Controller,在Controller中调用Service之后,启动页面测试
- 优化下 优化内容显示到页面上
项目启动成功:
测试功能