前面历史文章中我们有说过关于微服务的注册和发现,并以 etcd 作为简单例子简单阐述了关于服务注册和发现的应用
那么日常工作中,你已经使用了服务注册和发现的哪些模式呢?
服务注册和发现的作用
首先,简单说明一下服务注册和发现的作用
他可以屏蔽和解耦多个服务之间的依赖,还可以让我们对微服务进行动态管理
怎么理解呢?🧐🧐🧐
还记得一开始我们都是在开发单体应用的时候,一个应用包含了多个功能,他们耦合在一起,例如有订单管理,租户管理,账户管理等
演变到微服务的时候,这些专一的功能就单独拎出来,成为一个微服务,有自己独立的数据库,自己的一套系统,这个时候就有订单微服务,租户微服务,账户管理微服务等
那么,以前是一个单体应用,咱们内部干啥都方便,需要啥直接说就好,反正我们都生活在一起
可是,演进到微服务的时候,每一个专一的功能都是一个独立的个体,可能是生活在同一个区域的不同单元楼了
多个服务之间自然需要进行通信,这个时候就需要用到服务的注册和发现,这里存放动态的每一个服务的应用名对应的地址和端口
我们知道,一个服务去与另外一个服务进行通信的时候,需要知道对方的 ip 和 端口 以及沟通好对应的协议
微服务之间通信,我们通常使用 RPC 进行通信,golang 通常用 gRPC 来进行处理
例如有 3 个服务,服务 A,服务 B,服务 C
服务 A 如果将 服务 B 的 ip 地址和端口写到自己服务代码里面
那么有一天,服务 B 的环境发生了变化,那么 服务 A 岂不是依赖服务 B 的功能就不可用了,这也太死了
因此引入服务注册和发现中心之后,服务 A 完全无需关心服务 B 的地址和端口,只需要通过服务名去找服务注册和发现中心获取即可,哪怕服务 B 的地址如何变幻,服务 A 总能请求到正确的服务 B
服务注册和发现的模式,一般有两种
客户端模式
客户端模式,又叫直连模式
见名知意,直连,自然是点到点的直连
服务 A 直接通过 ip 和 port 去请求服务 B,只不过服务 A 需要去一个叫做服务注册和发现中心的地方去获取服务 B 的地址信息,再进行建立连接
例如,我们可以理解为是这样的流程
可以看到,像这种直连的方式
服务 A 需要在代码中去编写代码与服务注册和发现中心交互, 且需要自写算法来进行负载均衡到节点的任意一个服务 B 上(咱们初期一般是对每个服务部署了 3 个应用在环境中)🤣🤣
对于技术栈是一样的团队中,可以将该部分提取抽象出来,做成一个公共库,提供给各个团队使用即可,相当于,对于各个团队来说,直接调用公共库中的方法,传入具体的应用名即可按照算法获取到应用对应的地址,简单高效,项目初期,我们使用的就是客户端模式的服务注册和发现
当然,这种方式,如果切换到别的技术栈,别的编程语言的话,就不适用了,因此从这里我们可以看到,客户端模式是需要修改咱们仓库代码的,也就是说对代码有侵入性,对于跨平台的话不太友好,例如 golang 的公共库,java 没有办法使用,这个应该很容易理解
服务端模式
服务端模式,又叫做代理模式
同理,见名知意,既然是代理,那么自然是要通过代理隐藏某些信息
此处是否会想到正向代理和反向代理呢?如果想了解和确认他们都是啥,可以查看文末的文章链接
对于代理模式来说,还是服务 A 去请求 服务 B 的情况,这个种模式就不需要我们去修改代码了😁😁😁
服务 A 只需要去请求一个统一的域名,自然域名会被 DNS 解析成具体的 ip,请求到代理服务后,代理服务根据我们请求的内容,去进行分发到不同的服务上,如果这个代理服务后面的服务 B 有多个实例的话,那么就可以在代理服务上设置对于每一个实例的权重进行分发,来达到负载均衡的目的
看到这里,有没有看上去好像是在说 nginx 反向代理一样?
没错,此处的代理可以理解成一个反向代理,他是隐藏了关于服务端的细节的(此处 服务 A 属于客户端,服务 B 输出服务端)
此处,我们就可以看到这种模式实际上对于跨平台就非常友好了,不管你的应用是什么语言写的,只要能进行网络通信那么问题不大😀😀😀
但是弊端也是非常明显的,因为我们微服务之间的通信不是直连的,而是通过了一个代理服务,那这个代理服务自然会成为通信过程中影响性能的一环
从主机环境迁移到 k8s 环境中,如何使用服务注册和发现?
上述服务注册和发现的两种模式,你们使用哪种模式更多呢?
以前我们使用的是客户端模式,现在我们直接使用 k8s 自身的能力
我们知道,在 k8s 中,咱们部署一个服务,咱们自然是会给这个服务部署一个 Service,既然是 Service 我们就会给他指定 Port
对于一个 Deploy 咱们部署 多个 pod 的时候,当外部请求到该 Service 的时候,k8s 中自身的负载均衡算法就会将请求转到具体的 endpoint 上,最后流量也就会达到一个具体的 pod 上
那么问题来了?外部是如何请求到服务内部的?
目前简单做法是外部请求一个指定的域名,请求到 k8s 环境之后,通过 ingressRoute 匹配具体的路由,进而转发到对应的 Service,最终请求到具体的 pod
对于 ingressRoute 的用法还有很多,此处就不赘述了
当然,这个是对外提供域名的情况,可以这样做,那么微服务之间内部通信的话,如何进行服务注册和发现呢?
目前的做法还比较 low,部署服务的时候,其中我们会部署一个 ConifgMap,暂时记录叫做 discovery 吧 ,对于服务来说,就是一个配置文件,里面存放的就是每一个服务名和自己的 Service 和端口 的对应关系
那么微服务之间通信的话,直接去读取这个 ConfigMap 就可以能够与服务名对应的 Service 来进行通信了
可以看出这个时候有一个弊端的,如果某个服务的端口发生了变化,没有及时去更新这个 discovery COnfigMap 的话,就会出现功能异常的情况
这一点弊端其实暂时也是可以避免和接受的
其实关于在 k8s 中环境中,对于服务的注册和发现会有更好的选择,例如之后,我们可以将这件事件放到 NACOS 里面处理,当然,关于 NACOS 的内容,就不在这里过多赘述了
感谢阅读,欢迎交流,点个赞,关注一波 再走吧
欢迎点赞,关注,收藏
朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力
好了,本次就到这里
技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。
我是阿兵云原生,欢迎点赞关注收藏,下次见~
文中提到的技术点,感兴趣的可以查看这些文章:
- 服务注册与发现之ETCD
- 简单理解正向代理和反向代理
- 【k8s 系列】k8s 学习二十七 - 6,k8s 自身原理之 Service
- 【k8s 系列】k8s 学习十九,service 2 暴露服务的 3种 方式
- 【k8s 系列】k8s 学习十三,Service 基础
- 【k8s 系列】k8s 学习二十五-2,Deployment 升级应用
- 【k8s 系列】k8s 学习二十五-3,Deployment 升级应用2
可以进入地址进行体验和学习:https://xxetb.xet.tech/s/3lucCI