Dubbo 服务化最佳实践以及用redis作为注册中心的原理讲解

Dubbo 企业级应⽤

  • 前言
  • 分布式项目开发联调
    • 接口的暴露于引用
    • 自动化构建与协作
    • 接口平滑升级
    • 开发联调
      • 1、基于临时分组联调
      • 2、直连提供者(不推荐)
      • 3、只订阅
  • 控制后台与监控中心
  • redis服务注册机制
    • 注册中心的作用
    • Dubbo所支持的注册中心
    • Redis 注册中心
  • 总结
  • 感谢与参考

前言

hello,小编这周比较忙,一直没有写相应的博客,今天抽空写一下dubbo应用的进阶第一篇,本文参考了dubbo官方文档服务化最佳实践。融入小编自己的理解与自己多年dubbo项目的经验,此篇前半部分多讲的是开发流程的方案,对于dubbo监控小编一笔带过了,后半部分为redis作为注册中心主要的机制,小伙伴或许会问不是都用zookeeper作为注册中心,是的官方也推荐zookeeper,后续小编会继续带来zookeeper作为注册中心的源码阅读以及注册机制讲解,希望不会让大家觉得多此一举。废话不多说咱们开始。

分布式项目开发联调

接口的暴露于引用

在rpc调用的服务中,调⽤⽅是通过接⼝来调⽤服务端,传⼊参数并获得返回结果。那这样服务端的接⼝和模型必须暴露给调⽤⽅项⽬。服务端如何暴露呢,客户端如何引⽤呢?咱们用一张图说明一下
Dubbo 服务化最佳实践以及用redis作为注册中心的原理讲解_第1张图片
暴露接⼝的通常做法是 接⼝与实现分离,服务端将 接⼝、模型、异常 等统⼀放置于⼀个模 块,实现置于另⼀个模块。调⽤⽅通过Maven进⾏引⽤。项目中往往也采用这种做法。

自动化构建与协作

当项⽬越来越多,服务依懒关系越发复杂的时候,为了提⾼协作效率,必须采⽤⾃动化⼯具 完成 接⼝从编写到构建成JAR包,最后到引⽤的整个过程。
Dubbo 服务化最佳实践以及用redis作为注册中心的原理讲解_第2张图片
项目流程
前期的设计包括概设详设数据库设计咱们不表,直接说自动化构建协作是怎样的流程

  1. 服务端开发人员,在上面的api中编写相应的接口,模型以及异常等信息
  2. push远程仓库
  3. Jenkins构建指定的版本
  4. 然后deploy至私服nexus
  5. 消费端开发将jar包拉至本地服务然后开发

这样服务端定义好接口模型数据后,两端分别开发速度快。

接口平滑升级

上面的话是最理想的情况下,只需要定义好接口就行了,那假如项目同时开发,然而调用了相同的接口那,此时有个项目组队这个接口的改变,就会影响到其他项目组的开发进程如下图所示:
Dubbo 服务化最佳实践以及用redis作为注册中心的原理讲解_第3张图片
项⽬B、C都依懒了项⽬A 当中的接⼝1,此时项⽬B业务需要,需要接⼝1多增加⼀个参数,升级完成后。项⽬B能正确 构建上线,项⽬C却不⾏。
此时的解决方案和原则如下:

  • 接⼝要做到向下兼容:接⼝参数尽量以对象形式进⾏封装。Model属性只增不删,如果需要作废,可以添加@Deprecated 标识。
  • 如果出现了不可兼容的变更,则必须通知调⽤⽅整改,并制定上线计划。
  • api新增外部接口,内部可以调用相同方法实现。使用装饰者模式。(因项目而异)

开发联调

对于rpc项目的联调有时候是非常痛苦的,假如公司机器很多,环境很多,甚至到了人手一个环境,那财大气粗,这个可以在自己环境上部署所有的项目然后想怎么玩就怎么玩,但对于大部分公司而言,环境总是有限的,假如我们有A,B,C,D服务,咱们开发新功能时需要修改D服务,然后需要本机联调怎么保证咱们用公共环境的参数却调到本机上来呢。那下面小编来讲几个联调方案

1、基于临时分组联调

  • group 分组 在reference 和server 配置当中采⽤相同的临时组 ,通过group 进⾏设置

说说比较简单,那小编上代码演示
上次小编搭建了一个简单的dubbo和spring-boot 整合的项目,大家可以看下链接如下:
Dubbo快速上手与spring-boot整合以及配置体系
在那篇文章的技术上做修改
application.properties 修改加入server.{application}.group的配置,中间可以替换成你的项目名称
这边无论是服务端还是消费端都要引入

dubbo.application.name=boot-server
dubbo.protocol.name=dubbo
dubbo.protocol.port=-1
dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.provider.timeout=6000
server.member.group = member

在实现的service层注解修改,引用端修改

@DubboService(group = "${server.member.group}")
public class UserServiceImpl implements UserService {
     
}

@DubboReference(group = "${server.member.group}")
private UserService userService;

调用成功
Dubbo 服务化最佳实践以及用redis作为注册中心的原理讲解_第4张图片

让我们启动多台服务
我们copy一份如下图
Dubbo 服务化最佳实践以及用redis作为注册中心的原理讲解_第5张图片
可以在program arguments上加入也可以在vm options上加入 上面配置加-Dserver.member.group即可,效果一样。然后我们调整客户端的配置,修改server.member.group= temp-member再次调用效果
Dubbo 服务化最佳实践以及用redis作为注册中心的原理讲解_第6张图片
无论怎么刷新都是temp_member

2、直连提供者(不推荐)

在reference 中指定提供者的url即可做到直连
xml形式,客户端直接写死url本地的

<dubbo:reference url="dubbo://127.0.0.1:20880" id="demoService"  timeout="2000"  interface="com.tuling.teach.service.DemoService" check="false"/

代码写死配置上先写 application.url =dubbo://127.0.0.1:20880

@DubboReference(url = "${application.url}")
 private UserService userService;

小编这边不做演示

3、只订阅

⼀个项⽬有可能即是服务提供者⼜是消费者,在测试时需要调⽤某⼀服务同时⼜不希望正在开发的服务影响到其它订阅者如何实现? 通过修改 register=false 即可实现

控制后台与监控中心

dubbo有个管理后台和监控中心的搭建这边小编不做赘述,大家可以看这篇博客写得很详细
Dubbo管理控制台与监控中心的搭建
注:dubbo-admin 的版本并没有统⼀的管理,没有稳定分⽀,⽬前试了只有master-0.2.0 比较稳定实用。

redis服务注册机制

注册中心的作用

为了到达服务集群动态扩容的⽬的,注册中⼼存储了服务的地址信息与可⽤状态信息,并实时推送给订阅了相关服务的客户端。
Dubbo 服务化最佳实践以及用redis作为注册中心的原理讲解_第7张图片
一个完整的注册中心需要实现以下功能:

  1. 接收服务端的注册与客户端的引用,即将引用与消费建立关联,并支持多对多。
  2. 当服务正常关闭时能即时清除其状态
  3. 当注册中心重启时,能自动恢复注册数据,以及订阅请求

Dubbo所支持的注册中心

  1. Multicast 注册中心
    a. 基于组网广播播技术,只能用在局域网内,一般用于简单的测试服务
  2. Zookeeper 注册中心(推荐)
    a. Zookeeper 是 Apacahe Hadoop 的子项目,是一个树型的目录服务,支持变更推送,适合作为 Dubbo服务的注册中心,工业强度较高,可用于生产环境,并推荐使用
  3. Redis 注册中心
    a. 基于Redis的注册中心
  4. Simple 注册中心
    a. 基于本身的Dubbo服务实现(SimpleRegistryService),不支持集群可作为自定义注册中心的参考,但不适合直接用于生产环境。

Redis 注册中心

关于Redis注册中心我们需要了解两点:

  1. 数据结构:如何存储服务的注册与订阅关系
  2. 状态更新:是当服务状态改变时如何即时更新

数据结构:
redis 注册中心存储了服务发布、订阅信息。他们以redis中的map字段进行存储,数据结构如下:
服务发布

/dubbo/{服务名}/providers (key)
{提供者url1}: {有效期} (value 仍然是map形式)
{提供者url2}: {有效期}

服务订阅

/dubbo/{服务名}/consumers
{订阅者url1}: {有效期}
{订阅者url2}: {有效期}

小编以redis客户端来看一下上面的数据结构
Dubbo 服务化最佳实践以及用redis作为注册中心的原理讲解_第8张图片
⼀个注册中⼼存储了多个服务、每个服务对应多个提供者和订阅者。每个服务的提供者的URL 作为接⼝map中的⼀个Key,与之对应的value 就是该提供者的有效期。有效期通常只有60 秒,dubbo通过⼀个维护线程,每隔30更新该时间。
这个源代码在org.apache.dubbo.registry.redis.RedisRegistry#deferExpired
大家有兴趣可以看一下啊,这里小编理解为心跳机制不断的报活。

发布与订阅流程
Dubbo使用Redis的发布订阅特性实现
提供者与消费者之前数据实时同步其原理如下:
Redis 发布订阅(pub/sub)是一种消息通信模式:
发送者(pub)发送消息,订阅者(sub)接收消息。
Redis 客户端可以订阅任意数量的频道。
下图展示了频道channel1,以及订阅这个频道的三个客户端 -client2 、client5 和client1之间的关系:
Dubbo 服务化最佳实践以及用redis作为注册中心的原理讲解_第9张图片

#进入redis 客户端
telnet 127.0.0.1 6379
#创建一个 channel
set name Bob
#订阅该channel,此时客户端处于阻塞状态,等待接收消息
subscribe name
#开启一个新的客户端
telnet 127.0.0.1 6379 9
#为该 channel 发布消息
publish name “luban uncle”

dubbo使用redis注册中心的流程
在提供者和消费者上线上时,分别会进行发布与订阅事件,
其主体流程如下:

  1. 消费端
    a. 启动:注册消费者信息
    b. 启动:启动一个阻塞线程,订阅(subscribe)该接口事件
    c. 停止:删除接⼝消费信息
    d. 停止:停止订阅线程

  2. 提供端
    a. 启动:注册提供者信息
    b. 启动:推送(publish) 接口注册事件
    c. 停止:删除接口提供者信息
    d. 停止:推送(publish) 接口注销事件

相关源代码如下
org.apache.dubbo.registry.redis.RedisRegistry#doSubscribe// 订阅 org.apache.dubbo.registry.redis.RedisRegistry.Notifier#run// 订阅线程,阻塞读取 org.apache.dubbo.registry.redis.RedisRegistry.NotifySub#onMessage// 变更通知 org.apache.dubbo.registry.redis.RedisRegistry#doRegister // 注册 org.apache.dubbo.registry.redis.RedisRegistry#destroy // 消费

总结

今天小编主要讲了dubbo作为项目rpc调用框架的主要使用和一些方案,重点主要为redis作为注册中心的原理,后续小编会对其源码做解读,并且继续讲解当注册中心为zookeeper的时候是怎样的流程。谢谢

感谢与参考

感谢源码阅读网鲁班大叔讲解
参考了dubbo官方文档以及监控时大佬的相关博客

你可能感兴趣的:(分布式架构,#,Dubbo篇,分布式,dubbo,redis)