rpc框架dubbo学习入门及环境搭建(spring boot+Kotlin)
学习之前,确保有以下知识基础:
- java网络编程
- socket传输数据
- io流
rpc简介及实现
rpc是remote procedure call的简写,意思为远程过程调用。
rpc应用较多的情景是分布式开发,那什么是分布式开发呢?
原本我也是想自己解释的,奈何网上大佬解释得很清楚了,这里就不献丑了,建议阅读完下面推荐的几篇再继续往下
刚开始的时候,服务和调用都是在同一机器,这叫本地过程调用
之后,由于客户量增长,一个服务器并不能满足要求,之后便是把调用和服务分开,分别部署在不同的机器,负责调用服务方法的称之为客户机,负责提供服务方法的称为服务机
上图的原理可能步骤有点多,但是只要记住一点,客户机是把数据通过socket或者是其他协议传递到了服务机,让服务机进行处理,从而以相同的协议方式把数据传递回来
如何实现一个简单的rpc一文中,大佬已经实现了一个简洁的rpc框架,然后对于这个rpc框架,并提出来的一些可以优化的点:
1. 缺乏通用性
我通过给calculator接口写了一个calculatorremoteimpl,来实现计算器的远程调用,下一次要是有别的接口需要远程调用,是不是又得再写对应的远程调用实现类?这肯定是很不方便的。
2、集成spring
在实现了代理对象通用化之后,下一步就可以考虑集成spring的ioc功能了,通过spring来创建代理对象,这一点就需要对spring的bean初始化有一定掌握了。
3、长连接or短连接
总不能每次要调用rpc接口时都去开启一个socket建立连接吧?是不是可以保持若干个长连接,然后每次有rpc请求时,把请求放到任务队列中,然后由线程池去消费执行?只是一个思路,后续可以参考一下dubbo是如何实现的。
4、 服务端线程池
我们现在的server端,是单线程的,每次都要等一个请求处理完,才能去accept另一个socket的连接,这样性能肯定很差,是不是可以通过一个线程池,来实现同时处理多个rpc请求?同样只是一个思路。
5、服务注册中心
正如之前提到的,要调用服务,首先你需要一个服务注册中心,告诉你对方服务都有哪些实例。dubbo的服务注册中心是可以配置的,官方推荐使用zookeeper。如果使用zookeeper的话,要怎样往上面注册实例,又要怎样获取实例,这些都是要实现的。
6、负载均衡
如何从多个实例里挑选一个出来,进行调用,这就要用到负载均衡了。负载均衡的策略肯定不只一种,要怎样把策略做成可配置的?又要如何实现这些策略?同样可以参考dubbo,dubbo - 负载均衡
7、结果缓存
每次调用查询接口时都要真的去server端查询吗?是不是要考虑一下支持缓存?
8、多版本控制
服务端接口修改了,旧的接口怎么办?
9、异步调用
客户端调用完接口之后,不想等待服务端返回,想去干点别的事,可以支持不?
10、优雅停机
服务端要停机了,还没处理完的请求,怎么办?
ps:使用rpc的时候,需要考虑到网络问题,需要采用重试机制
由上述的这些问题,之后便是出现了一些优秀的rpc框架,如dubbo、spring cloud等
dubbo简介
dubbo是阿里巴巴开源的基于 java 的高性能 rpc(远程过程调用) 分布式服务框架(soa),致力于提供高性能和透明化的rpc远程服务调用方案,以及soa服务治理方案,其内部使用了 netty、zookeeper,保证了高性能高可用性。
dubbo结构图:
节点 | 角色说明 |
---|---|
provider | 暴露服务的服务提供方 |
consumer | 调用远程服务的服务消费方 |
registry | 服务注册与发现的注册中心 |
monitor | 统计服务的调用次数和调用时间的监控中心 |
container | 服务运行容器 |
其中,注册中心registry
和监控中心monitor
都是可选的,所以,我们下文先简单实现dubbo(点对点传输数据)
<dependency> <groupid>com.starsone</groupid> <artifactid>dubbo-api</artifactid> <version>0.0.1</version> </dependency>
dubbo简单实现
项目说明:
项目基于spring boot,分为三个部分,api
,consumer
和provider
- api主要是用来声明一些服务的接口(maven项目)
- provider则是对服务接口的具体实现(spring boot项目,通过maven依赖api项目)
- consumer则是远程调用provider提供的服务接口(spring boot项目,通过maven依赖api),
本质上consumer相当于客户机,而provider相当于客户机
1.新建项目
使用idea,建立一个空白的项目,之后新建module
之后idea会弹出一个新建module的窗口
依次新建api、provider、cousmer三个module
api选择maven项目,之后填写相关的包名信息直接新建即可(不需要选择具体的maven结构),而另外两个则是spring boot项目,选择spring initializr新建即可,同样,不要勾选其他的依赖,填写好包名相关信息新建即可
2.api项目声明服务接口
在api项目中,我们新建一个calculatorservice接口,里面定义一个add的方法
public interface calculatorservice { int add(int a,int b); }
3.配置api项目的依赖
原本,之后的provider和consumer项目都是需要引用dubbo-spring-boot-starter这个依赖,dubbo-spring-boot-starter依赖中已经包含了dubbo依赖,这样就可以不需要写dubbo的依赖了
由于之后我们的provider和consumer项目都是需要引用api这个项目,所以,我们可以把provider和consumer所需要的依赖dubbo-spring-boot-starter
添加到api这个项目中
之后的provider和consumer项目也就是依赖了api项目,也成功依赖了dubbo-spring-boot-starter
<dependency> <groupid>org.apache.dubbo</groupid> <artifactid>dubbo-spring-boot-starter</artifactid> <version>2.7.5</version> </dependency>
4.provider和consumer项目引用api项目依赖
由于之前我们创建的api项目是maven项目,所以添加依赖就很简单,在provider和consumer各自的pom.xml添加依赖即可
5.provider实现api中的服务接口
我们在provider项目中新建一个类calculatorserviceimpl
,去实现calculatorservice
接口
@service(interfacename = "calculatorservice") class calculatorserviceimpl:calculatorservice { override fun add(a: int, b: int): int { val result = a+b println("$a+$b=$result") return result } }
注意,这里的service注解是dubbo包里面的注解,而不是spring中的service,定义接口名interfacename
为calculatorservice
,方便之后容器进行查找
6.配置provider项目
我们需要修改spring boot的配置文件,这里我使用yml的形式进行配置,阅读比较舒适
spring: application: name: dubbo-provider-application dubbo: scan: #扫描指定包是否包含有dubbo中service注解的类 base-packages: com.starsone.provider.service protocol: name: dubbo #协议,默认为dubbo(其他协议webserovice、thrift、hessain、http) port: 12345 #端口,默认为20880 registry: address: n/a #不需要注册中心
ps:如果不想在配置文件制定扫描包含有service注解的类,可以在provider项目中的application类中添加开启dubbo自动扫描的注解@enabledubbo
provider项目结构图:
7.运行provider
由于我们没有引入注册中心,所以得先运行provider,获得ip地址
之后consumer项目中,才能让springr容器去根据ip地址+端口号去找到对应的实例并自动装载
由输出日志,我们可以看到ip地址
8.consumer获得service对象
@component class myrunner:applicationrunner { @reference(url ="dubbo://192.168.52.1:12345",interfacename = "calculatorservice" ) private lateinit var calculatorservice: calculatorservice override fun run(args: applicationarguments?) { println(calculatorservice.add(5,14)) } }
这里,由于是为了简单考虑,没有使用web依赖,所以,使用了applicationrunner这个接口进行测试,spring容器在加载完成会自动回调此接口
reference注解是dubbo中的注解,consumer项目运行之后,consumer中的dubbo就会根据此url和一些其他的信息进行数据的传递,远程调用provider中的服务,之后,provider接收数据并进行处理,返回数据给consumer,是不是有了rpc的感觉?
9.配置consumer及测试
配置的话,只配置了应用的名称
之后,我们运行consumer的application,可以看到结果
同样,在provider项目,也是打印出了consumer项目传递过来的参数
引入注册中心
前面的实现,是没有注册中心的,属于一种直连的方式,但是,实际上,分布式开发,具有多台服务机
客户机应该是向注册中心请求,由注册中心查询当前空闲的服务机,并根据某种策略,选择其中一台服务机,将其ip地址返回给客户机,之后客户机通过ip地址,与该服务机进行连接,进行rpc操作
dubbo框架中,推荐使用zookeeper作为注册中心
zookeeper是一个分布式的,开放源码的分布式应用程序协调服务,是google的chubby一个开源的实现,是hadoop和hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。
1.下载zookeeper
注意,这里下载的版本最好与项目中的依赖版本一致
2.导入zookeeper依赖
我们需要修改api项目中的依赖,这样provider和consumer两个项目的依赖也是得以修改
<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> <exclusion> <groupid>log4j</groupid> <artifactid>log4j</artifactid> </exclusion> <exclusion> <groupid>io.netty</groupid> <artifactid>netty</artifactid> </exclusion> </exclusions> </dependency> <!-- zookeeper客户端 --> <dependency> <groupid>org.apache.curator</groupid> <artifactid>curator-recipes</artifactid> <version>4.2.0</version> </dependency>
3.配置provider和consumer的注册中心
provider:
consumer:
4.取消consumer指定url
由于我们使用的是注册中心,所以,不需要指定url了,把reference注解中的url删掉
5.运行zookeeper
解压下载的zookeeper压缩包,进入到conf目录,把zoo_sample.cfg
文件改为zoo.cfg
进入bin目录,点击zkserver.cmd
文件,运行zookeeper
6.运行provider和consumer
先运行provider,之后运行consumer,可以看到结果
本篇文章也是折腾了几天,参考了十几篇文章,一步步测试才弄成功,有些知识点并没有太深入,像dubbo控制台、监控中心等如何搭建,后期学习的时候再进行补充说明吧
参考
上一篇: 荐 数据仓库系列:数据仓库的发展历程
下一篇: 我现实中的抄底