传统的客户端和服务端的交互模式
- 服务端1 2 3 分别提供了一个服务的「ip」和「端口号」
- 这里的客户端不是咱们狭义理解的客户端app或者前端,客户端也可以是一个服务端,比如你在一个golang项目中需要不同的服务等,那么你这个golang项目就是上图中的客户端,这一点尤其要注意。
- 如果说的准确一点,这里的客户端应该叫做「服务消费者」,服务端应该叫做「服务提供者」
上面这种传统的交互模式看着没什么问题,但是其实可用性并没那么好,首先比如你的服务端2挂了,但是客户端还是不知道的,依然会继续请求,这样可用性当然是大大的下降的,所以接下来就引发出了我们接下来要讲的「服务发现」模式
服务发现模式
大概流程
其实所谓的服务发现,就是服务消费者在调用服务提供者提供的服务的时候,多了一层「服务中介」。服务中介中有很多key/value键值对,key是「服务名称」,value是「服务提供者的地址列表」。「当你新增一个服务提供者的时候,就往服务中介中写入kv数据,这个过程叫做服务注册」 「当你请求一个服务的时候,直接拿着key去服务中介中取对应的value,也就是服务提供者的地址列表,然后去请求就可以了。」
当服务提供者节点挂掉时,要求服务能够及时取消注册,比便及时通知消费者重新获取服务地址。
当服务提供者新加入时,要求服务中介能及时告知服务消费者,你要不要尝试一下新的服务。
基本过程如下图
- 步骤1:每次新增加一个服务提供者,需要先去服务注册中心注册一个key/value(服务名称/服务提供者的地址列表)
- 步骤2:服务调用者不直接调用服务提供者,而是拿着标志(也就是上面注册的key(服务名称))去服务注册中心查找对应的value(服务提供者的地址列表)
- 步骤3:服务注册中心会告诉服务调用者对应的key(服务名称)是否有value(服务提供者的地址列表),有的话会把对应的value(服务提供者的地址列表)返回给服务调用者
- 步骤4:服务调用者会拿着返回的value(服务提供者的地址列表)去请求对应的服务
服务发现是否太过简单?
上面的过程看起来好像是有点太简单了,而且看起来也没解决什么问题呀,而且好像还徒增了复杂度。其实并不是这样的。
服务提供者进程如果被kill -9暴力杀死,服务消费者不知道怎么办?
这个不用担心,服务发现中引入「服务保活和检查机制」,并更换数据结构。服务提供者需要每隔5秒左右向服务发现汇报存活,服务发现将服务地址和汇报时间记录在kv中。服务中介需要每隔10秒左右检查kv数据结构,踢掉汇报时间严重落后的服务地址项。这样就可以准实时地保证服务列表中服务地址的有效性。这也就是我们说的「服务健康检查」
服务列表变动时如何通知消费者?
第一种方法是「轮询」,消费者需要每隔几秒查询服务列表是否有改变。如果服务很多,服务列表很大,消费者很多,那么服务发现也会有一定的压力 第二种方法是「订阅消费模式」,服务消费者订阅一个消息,服务提供者有变动直接往消息中发送对应变化就行。
常见的服务发现方案
- - DNS
- - mDNS
- - Zookeeper
- - Etcd
- - Consul
具体方案大概了解一下就行,后面我们会详细介绍一下「Consul」,那么我们下期再见吧。如果这篇文章有帮助到你,