探索分布式框架dubbo

最近在研究阿里开源的分布式 RPC 框架 dubbo

快速开始

等等,在开始之前,先来读两篇短文,看看别人是怎么讲故事的,学习学习

1、那些年,我们追过的RPC


2、从SOA到微服务的演化 (原创:老刘 码农翻身 2017-05-22)

小明毕业后为了户口,进入了一家大型国企的信息部门工作, 这个国企不差钱, 几十年来随着IT系统的发展, 也与时俱进地兴建了多个信息系统,只不过自家开发的极少, 从外边购买的极多, 虽然信息部也有开发能力, 但是当甲方的感觉是最妙的, 何况出了问题还可以把责任推出去。

在这些系统当中, 小一点儿的有自动化办公系统(OA) , 休假系统,车辆管理系统, 薪水支付系统, 大点儿的有客户关系管理系统, ERP系统 ..... 等等, 可以说是琳琅满目,让人目不暇接,几十年来IT发展的技术,几乎都能在公司的IT环境中找到。

小明的工作之一就是维护现在的IT系统博物馆, 博物馆中大部分都是遗留系统, 能工作,但是非常的老旧。硬件平台, 软件环境,开发语言各部相同,都是异构的。

就说那个休假系统吧,还是用上个世纪流行的Delphi 写的。 还有那个OA系统, 也是上个世纪的ASP,运行在IIS上。 虽然界面丑陋,勉强能用。

也有一点新东西,比如上周上线的那个维修系统不就用了最新的前端技术嘛, 小明也着实激动了一阵,看了两天的React。

有一天有个著名外企的销售来到了小明的公司,请信息部门的老大吃了饭,K了歌。。。好像还搞了些小明这些小兵不知道的秘密活动。

第二天老大给国企老总做了汇报, 过了一段时间, 公司发文了:

为了提升IT效率,打破各个信息孤岛,实现各个信息系统之间的互联互通, 让业务和IT进行对齐, 达到业务敏捷性, 公司经慎重研究决定,邀请xxx公司作为咨询顾问, 从即日起开始实施SOA战略。

小明看了一遍,愣住了,上面的字全都认识, 但连起来就不知道是什么意思, 虚头巴脑的, 唯一确定的是,咨询顾问要来了,要开始什么SOA了。

顾问果然来了, 先给小明他们的信息部门洗了一次脑, 小明的脑海中被各种新式的名词所充斥: SOA, ESB, SCA, BEPL.... 下了课, 小明和同事们讨论了很久, 模模糊糊的明白了要做什么事情。

好像是把这些遗留的异构系统包装成粗粒度的服务, 还是 Web 服务,可以通过Http来访问, 然后呢, 让大家互相调用, 甚至可以把这些服务进行编排,形成一个大的业务流程, 完成更高层次的业务, 听起来挺有意思的。

外企的销售非常精明, 趁势卖了一大批硬件和软件, 他们的技术团队还确实帮着做了一个小的验证系统, 实现了一个业务场景,展示给公司老总看, 老总非常满意: 不错, 我们公司又一次站到了IT技术的前沿!

然后就没有下文了, 领导们似乎忘记了, SOA似乎没有发生过,互联互通呢? 业务敏捷呢?

小明很困惑,周末约着同学张大胖去吃饭。

张大胖在一个互联网公司工作, 主要是做网上约车系统, 用的都是最前沿的技术, 他说: 听起来你们要把这些遗留的异构系统做数据/信息的集成啊, 只是没有做下去而已, 国企嘛可以理解。 你知道我们公司在干什么事儿吗?

小明说:“不会和我们一样吧?”

“完全不同! 我们公司才成立几年啊, 最重要的就是这个约车系统, 当然我们现在发展的很快,这三年以来系统已经快变成一个巨无霸了, 代码已经达到百万行级别, 没人能搞明白了, 代码库非常难于管理, 冲突不断。 系统部署也非常困难, 一点点小改动都需要巨无霸式的整体部署, 你能想象得到吗, 我们系统重启一次得15分钟!”

“卧槽, 这么慢? 不可思议,我用过你们的打车软件, 用起来还可以啊?”

“唉, 金玉其外,败絮其中, 你不知道我们每次发布有多痛苦, 但是竞争激烈, 我们还得频繁发布。 所以我们做的事情和你们相反, 不是集成, 而是拆分! 把一个巨无霸变成一些小的组件, 让这些小组件能完全独立的开发, 测试和部署。”

“那你们的开发团队怎么办?” 小明问。

“我们的组织结构也要随着这些小组件来重构啊,你看我们分成了“乘客管理”,“司机管理”,“旅程管理”,“支付管理”等好多组, 每个组只负责他们特定的一块儿功能, 并且每个组里边都有设计,开发,测试,部署等人员,一应俱全, 他们从头到尾全程负责。”

“有意思啊,这些小组件都是独立的,每个组件实例都是一个进程吧, 那这些小组件怎么交互? 难道也是通过我们公司所用的Web service ?”

“不不, 我们不用那重量级的Web service , 什么WSDL, 什么SOAP, 我们统统不用, 我们只用最轻量级的、基于Http 的Restful 来对外提供接口”

小明突然想到一个问题:“你们每个部门负责一个特定功能,那数据怎么办?还用统一的数据库吗?”

“这是个老大难问题,我们得做数据库的拆分啊,唉, 一言难尽。”

小明说 :“可以理解,不过这样以来确实是更加敏捷了。”

大胖说:“这还不是最厉害的,最厉害的是我们能快速的自动化的部署这些小组件,并且能为他们创建很多实例来运行,有一个挂掉了也没关系,别人可以调用那些还在运行的。”

“所以关键点就是这些小组件对外提供的服务是无状态的,对吧?”

“没错”  大胖说, “这一点和你们的SOA是一样的, 对了, 告诉你一个小秘密,我们在生产环境会做一些‘猴子测试’,通过写脚本随机的停掉一些实例,看看我们的系统运行的怎么样”

小明说:“厉害啊,你们都玩的可都是心跳啊。”

“木有办法,只有在生产环境才能发现真正的问题啊”

“难道你们的这种方式没有缺点吗?”

“当然有了, 就拿数据库来说吧, 数据做了分区, 一致性怎么保证啊? 选择分布式事务非常麻烦, 有时候不得不选择最终一致性来妥协; 还有服务多了, 客户调用起来非常的麻烦, 所以经常得把多个接口API封装,对外提供一个简单的接口 ; 当然这种基于HTTP的调用远没有原来的在一个进程内的方式效率高。 还有一个要命的问题就是监控,你想想这么多运行的实例, 互相之间有调用关系,一个地方出错了, 怎么追踪啊,很麻烦。”

“不管如何, 你们这种把系统拆分,让一个独立的组织负责独立的部分还是很敏捷啊, 对了,你说的小组件,难道没有一个像SOA这样的高大上名称吗?”

“当然有了, 业界把这种方式叫做微服务! 虽然这个词不能完整的表达我们做的事情。 我现在很期望Martin Flower 给它起个更贴切的名称,就像Dependency Injection 那样, 比之前的IoC强多了。 ”

吃过饭回去的路上,小明心想:天下大势,真是分久必合,合久必分啊, 我们在零散系统的集成, 大胖他们又在搞巨无霸应用的拆分。

相比而言,小明还是羡慕大胖,羡慕他们公司的朝气蓬勃。 他虽然明白自己所在国企的信息系统和大胖做的不一样, 但是暮气沉沉的感觉让人看不到希望, 再这么混下去, 热爱的技术可就真的废了。

过了年,小明已经在国企服务了3年了,顺利的拿到了帝都的户口, 然后毫不迟疑的跳槽到了大胖的公司,去搞微服务去了。


直接上 GitHub 找到 dubbo 项目 Apache Dubbo (incubating) Project

git clone https://github.com/apache/incubator-dubbo.git

进入 dubbo-demo 模块,如下


dubbo-demo.PNG

demo下面的几个模块的后缀就是表示其配置(注解配置,api配置,xml配置)
interface只是一个接口模块

正准备跃跃欲试,结果发现好像少了点什么,咋没有可视化界面dubbo-admin,看看文档发现,admin 已经被单独分离出来了

下载运行dubbo-admin

git clone https://github.com/apache/incubator-dubbo-admin
# 直接在 dubbo-admin-server\src\main\java\org\apache\dubbo\admin启动DubboAdminApplication也可以
mvn --projects dubbo-admin-server spring-boot:run

cd dubbo-admin-ui
npm install
npm run dev
dubbo-admin.PNG

admin准备好了,但在demo里面发现默认注册中心用的都是多播:multicast://224.5.6.7:1234
这里dubbo推荐使用 zookeeper

安装 zookeeper

下载地址:http://www.apache.org/dyn/closer.cgi/zookeeper/
zookeeper 分为单机模式和集群模式,因为这里只是为了运行dubbo,这里只介绍Windows下装单机版(集群版,讲道理这种分布式的东西应该在Linux下折腾嘛)

解压后进入conf目录,修改zoo_sample.cfg文件名为:zoo.cfg,这是因为zookeeper启动时默认加载zoo.cfg配置文件。修改zoo.cfg文件内容如下:

# The number of milliseconds of each tick  
# tickTime:这个时间是作为 Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个 tickTime 时间就会发送一个心跳。  
# 默认情况下最小的会话超时时间为两倍的tickTime  
tickTime=2000  
# The number of ticks that the initial   
# synchronization phase can take  
# zookeeper集群中的包含多台server, 其中一台为leader, 集群中其余的server为follower. initLimit参数配置初始化连接时,   
# follower和leader之间的最长心跳时间. 此时该参数设置为5, 说明时间限制为5倍tickTime, 即5*2000=10000ms=10s.  
initLimit=5  
# The number of ticks that can pass between   
# sending a request and getting an acknowledgement  
# 该参数配置leader和follower之间发送消息, 请求和应答的最大时间长度. 此时该参数设置为2, 说明时间限制为2倍tickTime, 即4000ms.  
syncLimit=2  
# the directory where the snapshot is stored.  
# do not use /tmp for storage, /tmp here is just   
# example sakes.  
# dataDir:顾名思义就是 Zookeeper 保存数据的目录,默认情况下,Zookeeper 将写数据的日志文件也保存在这个目录里。  
dataDir=D:\\zookeeper-3.4.8\\data  
# dataLogDir:顾名思义就是 Zookeeper 保存日志文件的目录  
dataLogDir=D:\\zookeeper-3.4.8\\log  
# the port at which the clients will connect  
# clientPort:这个端口就是客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求。  
clientPort=2181  
# the maximum number of client connections.  
# increase this if you need to handle more clients  
# maxClientCnxns:限制连接到 ZooKeeper 的客户端的数量  
# maxClientCnxns=60  
#  
# Be sure to read the maintenance section of the   
# administrator guide before turning on autopurge.  
#  
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance  
#  
# The number of snapshots to retain in dataDir  
# autopurge.snapRetainCount=3  
# Purge task interval in hours  
# Set to "0" to disable auto purge feature  
# autopurge.purgeInterval=1  

需要在zookeeper-x.x.x文件夹下新建data和log文件夹

启动 zookeeper

cmd命令进入 zookeeper-3.4.8\bin 目录,启动 zkServer.cmd
或者直接双击zkServer.cmd启动,双击后窗口不会关闭,如果关闭了表示未启动成功
如果jdk环境变量设置了,但是提示JAVA_HOME找不到,则需要修改该目录下的 zkEnv.cmd 关于 JAVA_HOME 的一部分

zookeeper.PNG

启动 zookeeper 成功,下一步修改demo里面的注册中心的addresszookeeper://127.0.0.1:2181

demo-api-consumer:

public static void main(String[] args) {
        ReferenceConfig reference = new ReferenceConfig<>();
        reference.setApplication(new ApplicationConfig("dubbo-demo-api-consumer"));
        //reference.setRegistry(new RegistryConfig("multicast://224.5.6.7:1234"));
        reference.setRegistry(new RegistryConfig("zookeeper://127.0.0.1:2181"));
        reference.setInterface(DemoService.class);
        DemoService service = reference.get();
        String message = service.sayHello("dubbo");
        System.out.println(message);
    }

demp-api-provider:

public static void main(String[] args) throws Exception {
        ServiceConfig service = new ServiceConfig<>();
        service.setApplication(new ApplicationConfig("dubbo-demo-api-provider"));      
        //service.setRegistry(new RegistryConfig("multicast://224.5.6.7:1234"));
        service.setRegistry(new RegistryConfig("zookeeper://127.0.0.1:2181"));
        System.out.println("provider启动了");
        service.setInterface(DemoService.class);
        service.setRef(new DemoServiceImpl());
        service.export();
        System.in.read();
    }

万事俱备,首先启动 provider

[21/05/19 17:15:36:347 CST] main  INFO logger.LoggerFactory: using logger: org.apache.dubbo.common.logger.log4j.Log4jLoggerAdapter
provider启动了
[21/05/19 17:15:42:375 CST] main  INFO utils.Compatibility: Running in ZooKeeper 3.4.x compatibility mode
[21/05/19 17:15:43:093 CST] main  INFO imps.CuratorFrameworkImpl: Starting

zookeeper 命令行

2019-05-21 17:15:52,601 [myid:] - INFO  [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxnFactory@222] - Accepted socket connection from /127.0.0.1:55960
2019-05-21 17:15:52,601 [myid:] - INFO  [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:ZooKeeperServer@949] - Client attempting to establish new session at /127.0.0.1:55960
2019-05-21 17:15:52,632 [myid:] - INFO  [SyncThread:0:ZooKeeperServer@694] - Established session 0x10001863bea0003 with negotiated timeout 40000 for client /127.0.0.1:55960

admin-ui 显示

provider.PNG

启动 consumer

[21/05/19 17:38:20:068 CST] main  INFO config.AbstractConfig:  [DUBBO] Refer dubbo service org.apache.dubbo.demo.DemoService from url zookeeper://127.0.0.1:2181/org.apache.dubbo.registry.RegistryService?anyhost=true&application=dubbo-demo-api-consumer&check=false&default.deprecated=false&default.dynamic=true&default.lazy=false&default.register=true&default.sticky=false&deprecated=false&dubbo=2.0.2&dynamic=true&generic=false&interface=org.apache.dubbo.demo.DemoService&lazy=false&methods=sayHello&pid=13352®ister=true®ister.ip=192.168.10.1&remote.application=dubbo-demo-api-provider&remote.timestamp=1558430153116&side=consumer&sticky=false×tamp=1558431487233, dubbo version: , current host: 192.168.10.1
Hello dubbo, response from provider: 192.168.10.1:20880
[21/05/19 17:38:20:967 CST] DubboShutdownHook  INFO config.DubboShutdownHook:  [DUBBO] Run shutdown hook now., dubbo version: , current host: 192.168.10.1

zookeeper 命令行:

2019-05-21 17:38:17,489 [myid:] - INFO  [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxnFactory@222] - Accepted socket connection from /127.0.0.1:56156
2019-05-21 17:38:17,493 [myid:] - INFO  [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:ZooKeeperServer@949] - Client attempting to establish new session at /127.0.0.1:56156
2019-05-21 17:38:17,528 [myid:] - INFO  [SyncThread:0:ZooKeeperServer@694] - Established session 0x10001863bea0004 with negotiated timeout 40000 for client /127.0.0.1:56156
2019-05-21 17:38:21,045 [myid:] - INFO  [ProcessThread(sid:0 cport:2181)::PrepRequestProcessor@487] - Processed session termination for sessionid: 0x10001863bea0004
2019-05-21 17:38:21,077 [myid:] - INFO  [NIOServerCxn.Factory:0.0.0.0/0.0.0.0:2181:NIOServerCnxn@1056] - Closed socket connection for client /127.0.0.1:56156 which had sessionid 0x10001863bea0004

可以看到输出成功
dubbo 的目的,即做到调用远程接口方法和调用本地接口方法一样透明简单,从这个demo中就可以看出来。

你可能感兴趣的:(探索分布式框架dubbo)