服务发现的基本原理
一、什么是服务发现
服务提供者是什么, 简单说就是一个HTTP服务器,提供了API服务,有一个IP端口作为服务地址。 服务消费者是什么?
就是一个简单的进程,想要访问服务提供者提供的服务来做一些事情。 一个HTTP服务器既可以是服务提供者对外提供
服务,也可以是消费者需要别的服务提供者提供的服务,这就是服务依赖。复杂的服务甚至有多个服务依赖
服务发现有三个角色,服务提供者、服务消费者和服务中介。 服务中介是联系服务提供者和服务消费者的桥梁。服务提供者
将自己提供的服务地址注册到服务中介,服务消费者从服务中介那里查找自己想要的服务地址,然后使用这个服务。 服务中介
提供多个服务,每个服务对应多个服务提供者。
服务中介就是一个字典,字典里有很多key-value键值对,key是服务名称,value是服务提供者的地址列表。服务注册就是调用
字典的put方法放东西,服务查找就是调用字典的get方法获取东西
当服务提供者新加入时,要求服务中介能及时告知服务消费者。
二、Redis作为服务中介
Redis里面有丰富的数据结构,用来存储服务字典很合适。 对每一个服务名称,可以用一个set结构存储服务的IP:port字符串
如果服务提供者加入,调用sadd命令加入服务地址,如果服务挂掉,调用srem命令移除服务地址。 对服务消费者使用smembers
指令来获取所有服务地址然后在消费进程里随机调一个,或者使用srandmember命令直接获取随机服务地址。
如果服务提供者进程备暴力杀死了,不能主动调用srem命令怎么处理? 这个时候服务列表中多了一个黑地址指向了不存在的服务
二消费者完全不知道,这个时候服务中介就成了黑中介了。 因此,引入服务保活和检查机制,病更换数据结构。服务提供这需要每隔5秒
左右向服务中介汇报存活, 服务中介将付地址和汇报时间记录在zset数据结构的value和score中。 服务中介需要每隔10秒左右检查zset
数据结果。
那么服务列表变动时如何通知消费者?
第一种方式是轮询,消费者需要每隔几秒查询服务列表是否有改变。 如果服务很多,服务列表很大, 消费者很多,Redis会右一定压力。
这时可以引入服务列表的版本号控制,给每个服务提供一个key/value设置服务的版本号,就是在服务列表发生变动时,递增这个版本号。
消费者只要轮询这个版本号的变动即可直到服务列表是否发生了变化。
第二种方式就是采用pubsub。 及时性明显好于轮询。缺点就是每个pubsub都会占用消费者一个线程和一个额外的Redis连接。 为了减少
对线程和连接的浪费,我们使用单个pubsub广播全局版本号的变动。 所谓全局版本号就是任意服务列表发生了变动,这个版本号都会地藏。
接受到版本变动的消费者再去检查各自的依赖服务列表的版本号是否发生了变动。
Redis的单点问题怎么解决?
现流行的服务发现系统都是使用分布式数据库zookeeper etcd consul等来作为服务中介,他们是分布式的多节点的,挂掉了一个节点没关系
系统仍然可以正常工作。 那如果整个zk集群都挂掉? 其实每个服务消费者在本地内存里都会存一份当前的服务列表,即使服务中介集群挂掉,
也是可以使用当前的服务列表正常工作的。 也可以Redis-sentinel可以在主节点挂掉的时候,自动升级从节点为主节点
三、服务配置重加载
服务发现一般只是用来注册和查找服务列表这样一个比较单纯的功能。不过现代的服务发现系统还会集成服务配置管理功能。这样可以实现服务
配置的实时重加载。 服务中介还会存储一个单独的key/value用来存储这个服务的配置信息。当这个配置项在后台被修改时,服务中介会实时通知
相关服务器变更配置信息。 比如数据库地址变动,业务参数修改等。
四、服务管理后台
为了便于服务管理,一般服务发现还会提供一个服务管理后台,用于管理人员查看服务集群的状态。如果服务注册和汇报时提供冗余的配置信息,服务
管理后台就可以呈现更为详细的服务信息。服务管理后台还可以将所有的服务依赖组织起来,形成完整的依赖。