看了柳大神的《如可给老婆解释什么是rpc》和《如何实现一个简单的RPC》之后,我按这个思路给我们的测试小姐姐解释了什么是RPC,测试小姐姐毕竟是有功底的人,一下子就明白了
测试:“哦!RPC就是让服务的使用方像调用本地接口一样调用远程服务是吧”
me:“完全正确”
测试:“明白了,那zk是干什么的,我们公司用RPC的时候老是提到ZK”
me:“ZK啊,ZK是个注册中心”
测试:“哦?注册中心是什么吖?为什么要用注册中心吖?怎么用注册中心吖?”
me:“你这哲学三问打头,我有点招架不住啊,我理一理思路”
测试:“你说”
me:“上一集讲RPC的时候,我们是把被调用的服务的IP和端口写死的。但是这样并不好,如果有一天我们需要加机器了,我们还要重新修改IP和端口,然后重新发布”
测试:“你之前不是搞了个配置中心么,把ip和端口配到配置中心写成个list,调用的时候从list里面随便挑一个,地址换了改一下配置中心就好了啊”
me:“真机智,其实我觉得这已经算是一个不可靠的注册中心的原型了,能在服务启动的时候进行注册,服务停止的时候删除,然后让服务调用方可以查询服务的注册信息,也就是所谓【服务注册与发现】”
测试:“不可靠?”
me:“你想啊,要是我们有一台提供服务的机器大半夜突然挂掉了。。。”
测试:“是啊,那该怎么办呢,要是能知道哪台机器能用哪台机器不能用就好了,我们只用那些可以用的机器”
me:“赞!这就涉及到注册中心的一个重要特点了,【错误转移】当某个服务提供者异常时,能及时删除注册信息。一般注册中心会定时发送心跳包,来检测服务提供方是否在线,并及时删除下线节点”
测试:“这样啊,那我们直接在调用方这么做不就好了,调用一台机器失败了,就访问下一台,一直到成功为止”
me:“好办法,那如果某一台机器死掉了,那我们每次调用的时候都有几率会失败,这很浪费时间啊。要是我们把死掉机器记录下来不再调用,那如果这台机器过一会重启了,我们也还是不会去请求他,这样会很浪费资源的”
测试:“是哦,可是你的服务重启了,注册中心也不知道啊”
me:“好问题,这又涉及到注册中心的另一个特点,当某个服务启动时,可以重新注册到注册中心上”
测试:“明白了,所以注册中心的作用就是,当服务启动的时候把服务的ip和端口注册上去,服务异常的时候注册中心就把这台机器的注册信息删除掉,然后请求方只需要每次调用的时候去注册中心拿服务的注册信息再调用就可以了,对吧”
me:“差不多是这样了,但是还有个问题,你想想,要是你的服务提供者都是正常的,但是注册中心突然挂了,那怎么办,全公司的服务都没法请求了”
测试:“这个好说,本地缓存一份注册信息,每次从本地缓存来取,然后定时更新缓存”
me:“这也是个办法,不过一般的缓存更新不会采用轮询的方式,而是通过通知的方式,客户端与注册中心建立一个长连接,并注册一个监听器,服务注册信息发生变化的时候通知服务调用方更新注册信息,这样做既能及时更新信息,又能减少频繁访问带来的网络开销”
Tips(注册中心讲解过程中的一些支线交流)
负载均衡
有多台机器提供服务的时候注册中心怎么做LB呢(这是个优秀的测试小姐姐,她自己在公司分享过Nginx)
- 其实负载均衡不是注册中心的事情,这个事情应该交给RPC框架,或者说是RPC的调用方去完成
轮询和心跳
轮询和心跳的区别,简单列一下
- 轮询往往由客户端发起,向服务端请求数据,而心跳则可以由客户端发起,也可由服务端发起
- 轮询每次请求需要重新建立连接,而心跳通常会保持一个TCP连接来完成,所以轮询的开销更大
- 轮询往往希望请求数据,而心跳则仅仅为了保持连接
轮询和监听
为什么使用长连接监听而不是轮询的方式来进行服务注册信息的更新呢
- 数据更新的及时性:及时性取决于轮询的频率,设定多高的频率能保证及时更新呢
- 资源开销:每一次轮询都要新建连接,这回造成很大的开销,特别是为了及时性而提高轮询频率之后