前言
去年写了dubbo源码解析系列,但是因为一些不可抗拒的因素(加班),导致通信、编解码部分还没写.同时在和很多朋友交流过程中,其中反馈最多的一个问题是.看源码到底有什么用?究竟是不是真的只是面试时装装逼,装完继续CRUD.
其实之所以有这样的疑问,主要是因为平时遇到的问题都能通过搜索引擎解决.然而,我近两年的做的都是基础平台相关的工作,还是经常遇到一些必须要看源码才能解决的问题.所以我觉得光把自己看源码的经验分享出来还不够,更重要是讲清楚,看源码,究竟解决了什么实际问题.
本篇是为什么要看源码系列
的第三篇.先交代一下背景
由于公司做的是海外业务,为了方便海外同事办公.我们把公司的开发服务器(以下简称sit环境)迁移到了海外.但是这样就产生了一个问题.由于服务器在海外,运维部表示由于政策原因(具体细节不透露),那么我们将无法访问到sit环境.既然无法访问,那么这个sit环境对于我们就形同虚设了.经过协调.运维用Nginx做端口转发.把我们常用的中间件(zookeeper,RocketMQ)、数据库地址做映射.但是这样依然存在一些问题,下面画图分析
类比学习,浅析常见中间件原理
其实我们常见的中间件的原理都大致相同,你了解一种后,通过类比学习.很容易掌握其他的.下面拿RocketMQ举例.演示一下什么叫类比学习法
RocketMQ的官方文档中物理部署结构图如下:
NameSever
你可能不知道是什么.其实这个是RocketMQ3.X版本引入的,之前用的是zookeeper.就是说,3.X版本发现zookeeper功能很强大, 但是人家其实用不到zookeeper这么多功能,基本上只用到了zookeeper的分布式协调,也就是注册中心的功能,就弄了个更轻量的NameSever
.
那么Broker
是什么呢? 这个是数据存储的核心,也是真正的MQ服务器.我们所谓的消息存储,接收,拉取,推送操作都是在这个broker进行的.
简单的说,我们平时在项目中配置的mq地址是NameSever
.然后Broker
把信息注册到NameSever
.在框架的底层,我们访问NameSever
的时候,它通过注册的信息真正发起网络请求去访问注册的Broker
.
类比fastDFS学习
那么接下来我们就类比一下fastDFS
从上面两个图你就可以看出.在fastDFS
中,Tracker Server
就类似NameSever
,Storage Server
就类似Broker
.原理基本是一样的.同样的,平时我们项目中配置的地址其实是Tracker Server
的地址
类比Dubbo学习
Dubbo的原理我这里就不想再多做解释了,之前已经从源码角度各种剖析了.这里给之前没看过我Dubbo源码解析的朋友简单科普一下(真的只是简单讲两句)
两个Dubbo服务之间的调用,绝大多数情况是网络调用(为什么是绝大多数.因为这个涉及到本地暴露和远程暴露的问题).那么网络调用,至少要确定三个参数.就是
url地址
请求参数
响应参数
所以Dubbo最简单的原理就是,生产者把本机的ip地址和暴露的接口信息在zookeeper上创建节点.因为本机的ip地址就可以确定请求的url地址,接口信息可以确定请求和响应的参数.然后消费者调用接口的时候,被动态代理拦截到,然后通过网络请求调用提供者.
同样的,我们在项目中配置的地址是zookeeper的地址.原因同上两个中间件原理一致
你会发现,中间件的简单原理基本是一样的.通过这个类比学习,你以后遇到其他的中间件,哪怕是自己公司自研的中间件,他们的原理你也能迅速上手.
遇到的问题
分析完原理之后,那我们遇到了什么问题呢?比如RocketMQ,我们配置的是NameSever
的地址,那么这个地址我们可以通过Nginx映射出来.这样我们就可以访问到NameSever
.但是Broker
的地址,是Rocket自己注册上去的.我们即使映射了192.168.X.XXX
.但是Broker
注册地址的逻辑代码里面还是会把192.168.Y.YYY
注册上去.那么我们访问的还是192.168.Y.YYY
那么我们映射的这个192.168.X.XXX
就没有作用.
那么我们是不是装个逼秀一波操作,改源码的逻辑,让Broker
注册的地址按照我们映射的192.168.X.XXX
注册上去呢?
我只想说,年轻人,你这个思想很危险啊!
编程讲究的是开闭原则,再说,你确定能驾驭得住的RocketMQ的源码改动吗?我都说了,遇到问题,先不要着急看源码.先看官方文档,再通过搜索引擎,如果都不能解决的.我们再看源码.我百度搜索第一条就是答案的我还看个毛线源码!那么我们来看下官方文档
人家这个说得就很清楚了,默认是注册本地的ip地址上去,但是你可以设置.所以我们把自己的映射的ip地址配置上去就OK了.
Dubbo的问题
RocketMQ的问题我们通过官方文档解决了.但是Dubbo的问题文档没有.搜索了有类似答案,但是依然没有把原理讲清楚.那么我们就直入源码一探究竟(好吧,让我装个逼)
如果你之前就关注肥朝,一直有看过我的dubbo源码解析系列,比如dubbo源码解析-zookeeper创建节点
那么你就能像我这种风一般的男子一样迅速定位到源码中获取ip地址的源码片段.如下
这部分的逻辑是,先调用InetAddress.getLocalHost().getHostAddress()
,如果该方法返回一个合法地址,就直接认为这个地址是本地的ip地址.否则会遍历本地的所有网卡,并返回找到的第一个合法地址
//这部分是jdk的api
host = InetAddress.getLocalHost().getHostAddress();
既然是jdk的api,那么要弄懂原理就好搞很多了.我们直接看文档注释
/**
* Returns the address of the local host. This is achieved by retrieving
* the name of the host from the system, then resolving that name into
* an {@code InetAddress}.
*
* Note: The resolved address may be cached for a short period of time.
*
*
* If there is a security manager, its
* {@code checkConnect} method is called
* with the local host name and {@code -1}
* as its arguments to see if the operation is allowed.
* If the operation is not allowed, an InetAddress representing
* the loopback address is returned.
*
* @return the address of the local host.
*
* @exception UnknownHostException if the local host name could not
* be resolved into an address.
*
* @see SecurityManager#checkConnect
* @see java.net.InetAddress#getByName(java.lang.String)
*/
从文档的大概意思可以看出,他获取的ip地址,和hostName
有关.那么这样我们就有了突破口.
我们通过linux命令(uname -n
)查看机器的hostName,比如
然后编辑host文件
vi /etc/hosts
比如设置
192.168.1.102 testdemo
那么我们启动dubbo服务
当然这样我还是不放心,我们去zookeeper上看看节点
果然和我们看到的是一样的.
写在末尾
感谢大家一路以来的支持.后续的文章会在公众号首发.公众号名为肥朝
.后续还会有更多的套路和奇巧淫技分享.公众号等你来撩.