[肥朝]从一次解决开发环境问题聊聊为什么要看源码

1,334 阅读7分钟

前言

去年写了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}.
 *
 * <P>Note: The resolved address may be cached for a short period of time.
 * </P>
 *
 * <p>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上看看节点

果然和我们看到的是一样的.

写在末尾

肥朝 是一个专注于 原理、源码、开发技巧的技术公众号,号内原创专题式源码解析、真实场景源码原理实战(重点)。扫描下面二维码关注肥朝,让本该造火箭的你,不再拧螺丝!