您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息

看这一篇文章就够了,全面解析微服务架构组件

2022/10/28 12:01:38发布53次查看
1. 如何发布和引用服务
服务描述:服务调用首先解决的问题就是服务如何对外描述。 常用的服务描述方式包括 restful api、xml 配置以及 idl 文件三种。
restful api
主要被用作 http 或者 https 协议的接口定义,即使在非微服务架构体系下,也被广泛采用
优势:http 协议本身是一个公开的协议,对于服务消费者来说几乎没有学习成本,所以比较适合用作跨业务平台之间的服务协议。劣势:性能相对比较低
xml 配置
一般是私有 rpc 框架会选择 xml 配置这种方式来描述接口,因为私有 rpc 协议的性能比 http 协议高,所以在对性能要求比较高的场景下,采用 xml 配置比较合适。这种方式的服务发布和引用主要分三个步骤:
服务提供者定义接口,并实现接口服务提供者进程启动时,通过加载 server.xml 配置文件将接口暴露出去。服务消费者进程启动时,通过加载 client.xml 配置文件引入要调用的接口。
优势:
私有 rpc 协议的性能比 http 协议高,所以在对性能要求比较高的场景下,采用 xml 配置方式比较合适 劣势:对业务代码侵入性比较高xml 配置有变更的时候,服务消费者和服务提供者都要更新(建议:公司内部联系比较紧密的业务之间采用)
idl 文件
idl 就是接口描述语言(interface description language)的缩写,通过一种中立的方式来描接口,使得在不同的平台上运行的对象和不同语言编写的程序可以相互通信交流。常用的 idl:一个是 facebook 开源的 thrift 协议,另一个是 google 开源的 grpc 协议。无论是 thrift 协议还是 grpc 协议,他们的工作原来都是类似的。
优势:用作跨语言平台的服务之间的调用
劣势:在描述接口定义时,idl 文件需要对接口返回值进行详细定义。如果接口返回值的字段比较多,并且经常变化时,采用 idl 文件方式的接口定义就不太合适了。
一方面会造成 idl 文件过大难以维护另一方面只要 idl 文件中定义的接口返回值有变更,都需要同步所有的服务消费者都更新,管理成本太高了。
总结
具体采用哪种服务描述方式是根据实际情况决定,通常情况下, 如果只是企业内部之间的服务调用,并且都是 java 语言的话,选择 xml 配置方式是最简单的。如果企业内部存在多个服务,并且服务采用的是不同语言平台,建议使用 idl 文件方式进行描述服务。如果还存在对外开放服务调用的情形的话,使用 restful api 方式则更加通用。
2. 如何注册和发现服务
注册中心原理
在微服务架构下, 主要有三种角色:服务提供者(rpc server)、服务消费者(rpc client)和服务注册中心(registry),三者的交互关系如图
rpc server 提供服务,在启动时,根据服务发布文件 server.xml 中配置的信息,向 registry 订阅服务,把 registry 返回的服务节点列表缓存在本地内存中,并于 rpc server 建立连接。rpc client 调用服务,在启动时,根据服务引用文件 client.xml 中配置的信息,向 registry 订阅服务,把 registry 返回的服务节点列表缓存在本地内存中,并于 rpc client 建立连接。当 rpc server 节点发生变更时,registry 会同步变更,rpc client 感知后会刷新本地内存中缓存的服务节点列表。rpc client 从本地缓存的服务节点列表中,基于负载均衡算法选择一台 rpc server 发起调用。
注册中心实现方式
注册中心api
服务注册接口:服务提供者通过调用注册接口来完成服务注册服务反注册接口:服务提供者通过调用服务反注册接口来完成服务注销心跳汇报接口:服务提供者通过调用心跳汇报接口完成节点存货状态上报服务订阅接口:服务消费者调用服务订阅接口完成服务订阅,获取可用的服务提供者节点列表服务变更查询接口:服务消费者通过调用服务变更查询接口,获取最新的可用服务节点列表服务查询接口:查询注册中心当前住了哪些服务信息服务修改接口:修改注册中心某一服务的信息
集群部署
注册中心一般都是采用集群部署来保证高可用性,并通过分布式一致性协议来确保集群中不同节点之间的数据保持一致。
zookeeper 的工作原理:每个 server 在内存中存储了一份数据,client 的读请求可以请求任意一个 serverzookeeper 启动时,将从实例中选举一个 leader(paxos 协议)leader 负责处理数据更新等操作(zab 协议)一个更新操作方式,zookeeper 保证了高可用性以及数据一致性
目录存储
zookeeper作为注册中心存储服务信息一般采用层次化的目录结构:每个目录在 zookeeper 中叫作 znode,并且其有一个唯一的路径标识znode 可以包含数据和子 znode。znode 中的数据可以有多个版本,比如某一个 znode 下存有多个数据版本,那么查询这个路径下的数据需带上版本信息。
服务健康状态检测
注册中心除了要支持最基本的服务注册和服务订阅功能以外,还必须具备对服务提供者节点的健康状态检测功能,这样才能保证注册中心里保存的服务节点都是可用的。基于 zookeeper 客户端和服务端的长连接和会话超时控制机制,来实现服务健康状态检测的。在 zookeeper 中,客户端和服务端建立连接后,会话也也随之建立,并生成一个全局唯一的 session id。服务端和客户端维持的是一个长连接,在 session_timeout 周期内,服务端会检测与客户端的链路是否正常,具体方式是通过客户端定时向服务端发送心跳消息(ping 消息),服务器重置下次 session_timeout 时间。如果超过 session 就已经结束了,zookeeper 就会认为这个 session 就已经结束了,zookeeper 就会认为这个服务节点已经不可用,将会从注册中心中删除其信息。
服务状态变更通知
一旦注册中心探测到有服务器提供者节点新加入或者被剔除,就必须立刻通知所有订阅该服务的服务消费者,刷新本地缓存的服务节点信息,确保服务调用不会请求不可用的服务提供者节点。基于 zookeeper 的 watcher 机制,来实现服务状态变更通知给服务消费者的。服务消费者在调用 zookeeper 的 getdata 方式订阅服务时,还可以通过监听器 watcher 的 process 方法获取服务的变更,然后调用 getdata 方法来获取变更后的数据,刷新本地混存的服务节点信息。
白名单机制
注册中心可以提供一个白名单机制,只有添加到注册中心白名单内的 rpc server,才能够调用注册中心的注册接口,这样的话可以避免测试环境中的节点意外跑到线上环境中去。
总结
注册中心可以说是实现服务话的关键,因为服务话之后,服务提供者和服务消费者不在同一个进程中运行,实现了解耦,这就需要一个纽带去连接服务提供者和服务消费者,而注册中心就正好承担了这一角色。此外,服务提供者可以任意伸缩即增加节点或者减少节点,通过服务健康状态检测,注册中心可以保持最新的服务节点信息,并将变化通知给订阅服务的服务消费者。
注册中心一般采用分布式集群部署,来保证高可用性,并且为了实现异地多活,有的注册中心还采用多 idc 部署,这就对数据一致性产生了很高的要求,这些都是注册中心在实现时必须要解决的问题。
3. 如何实现rpc远程服务调用
客户端和服务端如何建立网络连接
http 通信
http 通信是基于应用层http 协议的,而 http 协议又是基于传输层 tcp 协议的。一次 http 通信过程就是发起一次 http 调用,而一次 http 调用就会建立一个 tcp 连接,经历一次下图所示的 “三次握手”的过程来建立连接。
完成请求后,再经历一次“四次挥手”的过程来断开连接。
socket 通信
socket 通信是基于 tcp/ip 协议的封装,建立一次socket 连接至少需要一对套接字,其中一个运行于客户端,称为 clientsocket ;另一个运行于服务器端,称为 serversocket 。
服务器监听:serversocket 通过点用 bind() 函数绑定某个具体端口,然后调用 listen() 函数实时监控网络状态,等待客户端的连接请求。客户端请求:clientsocket 调用 connect() 函数向 serversocket 绑定的地址和端口发起连接请求。服务端连接确认:当 serversocket 监听都或者接收到 clientsocket 的连接请求时,调用 accept() 函数响应 clientsocket 的请求,同客户端建立连接。数据传输:当 clientsocket 和 serversocket 建立连接后,clientsocket 调用 send() 函数,serversocket 调用 receive() 函数,serversocket 处理完请求后,调用 send() 函数,clientsocket 调用 receive() 函数,就可以得到返回结果。
当客户端和服务端建立网络连接后,就可以起发起请求了。但网络不一定总是可靠的,经常会遇到网络闪断、连接超时、服务端宕机等各种异常,通常的处理手段有两种:
链路存活检测:客户端需要定时地发送心跳检测小心(一般通过 ping 请求) 给服务端,如果服务端连续 n 次心跳检测或者超过规定的时间没有回复消息,则认为此时链路已经失效,这个时候客户端就需要重新与服务端建立连接。断连重试:通常有多种情况会导致连接断开,比如客户端主动关闭、服务端宕机或者网络故障等。这个时候客户端就需要与服务端重新建立连接,但一般不能立刻完成重连,而是要等待固定的间隔后再发起重连,避免服务端的连接回收不及时,而客户端瞬间重连的请求太多而把服务端的连接数占满。
服务端如何处理请求
同步阻塞方式(bio)
客户端每发一次请求,服务端就生成一个线程去处理。当客户端同时发起的请求很多事,服务端需要创建很多的线程去处理每一个请求,如果达到了系统最大的线程数瓶颈,新来的请求就没法处理了。bio 适用于连接数比较小的业务场景,这样的话不至于系统中没有可用线程去处理请求。这种方式写的程序也比较简单直观,易于理解。
同步非阻塞(nio)
客户端每发一次请求,服务端并不是每次都创建一个新线程来处理,而是通过 i/o 多路复用技术进行处理。就是把国歌 i/o 的阻塞复用到听一个 select 的阻塞上,从而使系统在单线程的情况下可以同时处理多个客户端请求。这种方式的优势是开销小,不用为每个请求创建一个线程,可以节省系统开销。nio 适用于连接数比较多并且请求消耗比较轻的业务场景,比如聊天服务器。这种方式相比 bio,相对来说编程比较复杂。
异步非阻塞(aio)
客户端只需要发起一个 i/o 操作然后立即返回,等 i/o 操作真正完成以后,客户端会得到 i/o 操作完成的通知,此时客户端只需要对数据进行处理就好了,不需要进行实际的 i/o 读写操作,因为真正的 i/o 读取或者写入操作已经由内核完成了。这种方式的优势是客户端无需等待,不存在阻塞等待问题。aio 适用于连接数比较多而且请求消耗比较重的业务场景,比如涉及 i/o 操作的相册服务器。这种方式相比另外两种,编程难难度最大,程序也不易于理解。
建议
最为稳妥的方式是使用成熟的开源方案,比如 netty、mina 等,它们都是经过业界大规模应用后,被充分论证是很可靠的方案。
数据传输采用什么协议
无论是开放的还是私有的协议,都必须定义一个“契约”,以便服务消费和服务提供者之间能够达成共识。服务消费者按照契约,对传输的数据进行编码,然后通过网络传输过去;服务提供者从网络上接收到数据后,按照契约,对传输的数据进行解码,然后处理请求,再把处理后的结果进行编码,通过网络传输返回给服务消费者;服务消费者再对返回的结果进行解码,最终得到服务提供者处理后的返回值。
http 协议
消息头server 代表是服务端服务器类型content-length 代表返回数据的长度content-type 代表返回数据的类型消息体具体的返回结果
数据该如何序列化和反序列化
一般数据在网络中进行传输,都要先在发送方一段对数据进行编码,经过网络传输到达另一段后,再对数据进行解码,这个过程就是序列化和反序列化
常用的序列化方式分为两类:文本类如 xml/json 等,二进制类如 pb/thrift 等,而具体采用哪种序列化方式,主要取决于三个方面的因素。
支持数据结构类型的丰富度。数据结构种类支持的越多越好,这样的话对于使用者来说在编程时更加友好,有些序列化框架如 hessian 2.0 还支持复杂的数据结构比如 map、list等。跨语言支持。性能。主要看两点,一个是序列化后的压缩比,一个是序列化的速度。以常用的 pb 序列化和 json 序列化协议为例来对比分析,pb 序列化的压缩比和速度都要比 json 序列化高很多,所以对性能和存储空间要求比较高的系统选用 pb 序列化更合;而 json 序列化虽然性能要差一些,但可读性更好,所以对性能和存储空间要求比较高的系统选用 pb 序列化更合适对外部提供服务。
总结
通信框架:它主要解决客户端和服务端如何建立连接、管理连接以及服务端如何处理请求的问题。通信协议:它主要解决客户端和服务端采用哪些数据传输协议的问题。序列化和反序列化:它主要解决客户端和服务端采用哪种数据编码的问题。
这三部分就组成了一个完成的rpc 调用框架,通信框架提供了基础的通信能力,通信协议描述了通信契约,而序列化和反序列化则用于数据的编/解码。一个通信框架可以适配多种通信协议,也可以采用多种序列�...
该用户其它信息

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录 Product