分布式服务

1.RPC

Remote Procedure Call 进程间通信方式:通过网络从远程计算机程序上请求服务而不需要了解底层网络技术的协议
RPC允许程序调用另一个地址空间的过程或函数,而不用程序显式编码这个远程调用的细节,比如俩台服务器AB,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数或方法,由于不在一个内存空间,不能直接调用,可以应用RPC框架来解决

1.1 Java RMI

是Java语言中的RPC实现方式,remote method invocation,
依赖java.rmi包下工具类,具体流程:集成Remote实现远程接口,开发业务逻辑,创建Server并且注册远程对象,客户端创建Client调用远程方法。
需要在代码直接编码地址,并且不支持服务治理,无法对服务调用进行统计,无法梳理服务依赖情况,无法保证服务上下线时的稳定性

1.2 Dubbo

高性能分布式服务框架,实现服务输入输出,支持服务治理,提供控制台界面,可以独立应用,也可以和Spring框架集成。Dubbo在设计采用微内核架构,基于对Java SPI机制的拓展实现。对分布式服务调用核心功能开放拓展点,包括服务调用的负载均衡策略,序列化协议,传输协议等,使用者可以自定义实现。

1.3 gRPC

使用ProtoBuf来定义服务,ProtoBuf是谷歌开发的一种数据序列化协议,性能高,压缩和传输效率高,语法简单,支持多种语言,能够基于语言自动生成客户端和服务端功能库。

1.4 Thrift

Facebook,解决各系统间大数据量的传输通信以及系统间语言环境不同需要跨平台的问题。支持多次编程语言,应用Thrift,需要再一个语言无关的IDL文件里,定义数据类型和服务接口,然后生成用来构建RPC客户和服务器所需的代码。由于需要定义独立的IDL文件,如果对服务进行修改,当数据结构变化时,必须重新编辑IDL文件,重新编译和生成相关的代码,修改起来比较繁琐。

1.5 Motan

微博,包括服务提供者,调用方,服务注册中心,服务端会向注册中心注册服务,消费端使用服务需要先向注册中心进行订阅,根据注册中心的返回列表与具体服务端建立连接,进行RPC通信。当服务端发生变更时,注册中心也会同步变更,然后同步的通知到消费端,Motan提供服务治理的功能,包括服务发现,服务摘除,高可用和负载均衡。

1.6 技术

  • 建立通信:客户端和服务器之间建立TCP连接,所有交换的数据都在这个连接里传输,建立通信可以使用成熟的网络通信框架,Netty。
  • 网络传输:节点之间数据传输采用什么协议,传输的数据如何反序列化和序列化,Dubbo中,传输协议使用Dubbo协议,序列化选择Hessian,Kryo,Peotobuf等不同方式。
  • 服务注册和发现:
  • 实现服务调用:Java通过代理实现服务调用

2.API网关

网关表示不同网络之间关口,网关是统一入口,承担很多业务,比如内外数据交互,数据安全,监控统计等,微服务架构里,Api网关的作用和开放平台等传统网关又有不同。微服务调用有RPC和Restful API俩种,API网关针对SpringCloud为代表的解决方案
引入网关,高效实现微服务集群的输出,节约后端服务成本,减少线上风险,并为服务熔断,灰度发布,线上测试提供解决方案。

API网关在微服务架构是用来整合各个不同模块的微服务,统一调度服务,封装系统内部架构,为每个客户端提供定制API,与外观模式类似,可以添加身份验证,监控,负载均衡,限流,降级与应用检测等功能。

  • 提供统一入口
  • 做统一切面处理
  • 将异构系统统一整合,比如外部API使用HTTP接口,内部使用性能更高的通信协议,然后在网关进行转换,提供统一外部接口。
  • 实现统一鉴权,提供安全性
  • 实现一个高伸缩性的服务,避免单点失效

2.1 Zuul

网飞开发,提供动态路由,监控,弹性,安全的网关服务

2.2 Gateway

通信框架是Netty,通过服务发现自动转发请求,集成Ribbon做负载均衡,支持Hystrix对网关保护

3.服务注册与发现

快速上下线,让服务水平拓展,保证服务可用性,服务注册与发现保证服务上下线发生变更时,消费者和提供者保持正常通信,

  • 消费者不需要知道具体服务提供者真实物理地址就可以调用,也无需知道具体有多少服务者可用
  • 服务提供者只需要注册到注册中心,就可以对外提供服务

3.1 Zookeeper

应用于Dubbo注册中心实现。Dubbo+Zookeeper方案。zk树形结构目录服务,支持变更推送,服务提供者在启动时在zk注册服务。

  • 注册服务是在zk的/providers节点下创建子节点,并写入自己url,代表该服务提供者
  • 服务消费者启动时候,向zk注册中心订阅服务列表,读取并订阅zk上/providers节点下所有子节点,并解析出来所有提供者的url来作为该服务地址列表。

3.2 Eureka

各个节点平等,几个节点挂掉不影响

3.3 Nacos

服务注册和发现功能,方便集成SpringCloud

  • CP:保证一致性,导致注册中心可用性降低
  • AP:保证可用性,可能会服务错误
    注册中心一般通过集群方式对外服务,比如zk集群。实现CP一致性,zk获取服务列表时,如果zk正在选主或者zk集群半数以上机器不可用时,将无法获得数据。
    对于服务注册和发现场景,可用性比数据一致性更加重要,针对同一个服务,即使注册中心的不同节点保存的服务提供者信息不相同,会出现部分提供者地址不存在,不会导致严重服务不可用,对于消费者说,能消费是最重要的

4.负载均衡

4.系统监控

4.1 分布式调用跟踪

系统拆分后,缺乏一个自上而下全局调用ID。分布式调用跟踪技术就是通过调用链的方式,把一次请求调用过程完整的串联起来,实现了对请求调用路径的监控,分布式调用链就是将一次分布式还原成调用链路,显式的在后端查看一次分布式请求的调用情况,比如各个节点的耗时,请求具体打到那台机器上,每个服务节点的请求状态等。

4.2 场景

  • 故障快速定位:通过链跟踪,一次请求的逻辑轨迹可以完整清晰展示出来,在开发的过程中,可以在业务日志添加调用链ID,可以通过调用链结合业务日志快速定位错误信息。
  • 各个调用环节的性能分析:在调用链的各个环节分别添加调用时延并分析系统的性能瓶颈,进行针对性优化。
  • 各个调用环节的可用性,持久层依赖等:通过分析各个环节的平均时延,QPS等信息,可以找到系统的薄弱环节,对一些模块做调整,比如数据冗余等
  • 数据分析:调用链是一条完整的业务日志,可以得到用户的行为路径,并汇总分析。

4.3 原理

参考Dapper论文,分布式调用跟踪是一种全链路日志,主要的设计基于span日志格式,Dapper用span来表示一个服务调用开始和结束时间,也就是时间区间,并记录span的名称以及每个span的id和父id,如果一个span没有父id,则成为root span。
日志采集和存储有很多许多开源可以选择,一般会使用离线+实时的方式储存日志,主要是分布式日志采集的方式,典型解决方案为Flume结合Kafka等MQ,日志存储到HBase等

4.4 实现

  • Google的Drapper
  • Twitter的zipkin:聚集来自各个异构系统的试试监控数据,用来追踪微服务架构下的系统延时问题
  • EagleEye鹰眼系统:前端请求到服务器,应用容器在执行实际业务前会先执行EagleEye的埋点逻辑。其为前端请求分配一个全局唯一的调用链ID,即TraceId,埋点逻辑吧TraceID放在一个调用上下文对象里面,而调用上下文对象会储存在ThreadLocal里面。调用上下文里还有个Rpcid,用于区分同一个调用链多个网络调用发生顺序的嵌套层次关系。当这个前端执行业务处理需要发起RPC调用时,RPC调用客户端首先会从当前线程ThreadLocal上面获取之前EagelEye设置的调用上下文,然后吧Rpcid递增一个序号,之后调用上下文会作为附件随这次请求一起发送到下游服务器。
  • 实际业务中,链路跟踪会有一个采样率配置,不会监控全部链路,作为非业务组件,尽可能少侵入其他非业务系统,并且尽量少占用系统资源。

5.分布式配置管理

5.1 应用场景

分布式场景下的限流和降级配置,通过配置管理来打开关闭

5.2 实现

本质是推送订阅模式
配置的应用方是订阅者,配置管理服务是推动方

  • 客户端发布数据到配置中心
  • 配置中心吧配置数据推送到订阅者
  • 配置管理服务封装一个客户端
  • 应用方基于该客户端与配置管理服务进行交互

5.2.1 实现步骤

提取配置信息,放入公共的地方存储,比如文件系统,数据库,Redis。使用发布订阅模式,让子系统订阅这些配置信息。对外开放可视化的配置管理中心,对配置信息进行操作维护。

特性要求

  • 高可用:服务器集群应该无单点故障,只要集群还有节点,就能提供服务
  • 容错性:在配置平台不可用时,也不影响客户端正常运行
  • 高性能:尽可能低的性能开销,不能因为获取配置给应用带来不可接受的性能损耗
  • 可靠存储:数据的备份容灾,一致性等,尽可能保证不丢失配置数据
  • 实时生效:对于配置的变更,客户端应用能够及时感知

5.2.2 选型

  • 携程Apollo
    集中化管理应用不同环境不同集群的配置
    配置修改后能够实时推送到应用端,并且具备规范的权限,流程治理等特性,适用于微服务配置管理等场景。
    Appllo服务端基于SpringBoot开发。支持多种语言的客户端。
    适合大型业务系统
  • 淘宝Diamond
    运行时,客户端定时检查配置是否发生变化,每次检查时,客户端将MD5传给服务器。服务器进行比较。
    相同:数据没有变,返回信息
    不相同:数据变化,返回变化数据给客户端,重新请求更新后的配置文件
    适合小型业务系统的配置管理。
    配置信息持久化到MYSQL数据库和本地磁盘中,通过数据库加本地进行容灾,客户端和服务端通过Http来交互,通过比较数据MD5值来感知数据变化
  • 百度Disconf
    应用安装依赖Zookeeper,配置动态更新借助Zookeeper的watch机制实现。初始化流程中对配置文件watch,当配置文件更新时,Zookeeper通知客户端,然后客户端从Discon服务端获取最新的配置并更新到本地
  • Zookeeper也用于分布式配置管理,依赖发布订阅功能,基于watch机制实现

6.容器化

容器技术是更加轻量级的操作系统隔离方案,可以将应用程序及其运行依赖环境打包到镜像中,通过容器引擎进行调度,并且提供进程隔离和资源限制的运行环境。

6.1 虚拟化技术

通过Hypevisor实现虚拟机与底层硬件的解耦,虚拟机实现依赖Hypevisor层,Hypevisor是整个虚拟机核心所在。
Hypevisor可以叫做虚拟机监视器VMM,是一种运行在基础物理服务器和操作系统之间的中间软件层,可以允许多个操作系统和应用共享硬件。Hypevisor虚拟机可以模拟机器硬件资源协调虚拟机对硬件资源访问同时在各个虚拟机之间进行隔离

6.2 容器化技术-Docker

是开源的应用容器引擎,可以打包应用以及依赖包到一个可移植的容器中,然后发布到服务器上,Docker基于镜像运行,可部署在物理机或虚拟机上,通过容器引擎和容器编排调度平台实现容器化应用的生命周期管理。
优势:Docker只包含应用程序和依赖库,处于一个隔离环境中,更加轻量高效

6.3 比较

虚拟机是运行在宿主机之上的完整操作系统,运行会占用较多的CPU,内存,硬盘资源等。
虚拟化技术为用户提供完整的虚拟机,包括操作系统,有更好的隔离性和安全性,但更新升级困难
容器化为应用程序提供隔离的运行空间,容器之间共享同一个上层操作系统内核,具有快速扩展,灵活性和易用性等优势,但隔离性较差,安全性较低。
实际部署结合俩种技术,一个虚拟机运行多个容器

6.4 容器化原理

核心是如何实现容器内资源限制,以及不同容器之间的隔离
-

6.4.1 Namespace : 通过抽象方法使得Namespace中的进程看起来拥有他们自己的隔离的全局系统资源实例

Linux内核实现六种Namespace

  • Mount namespaces 隔离文件系统
  • UTS namespaces 定义hostname和domainame
  • IPC namespaces 特定的进程间通信资源
  • PID namespaces 独立进程ID结构
  • Network namespaces 独立网络设备
  • User namespaces 用户和组ID空间

6.4.2 Cgroups

Control Group 功能是限制记录,隔离进程所使用的物理资源
比如CPU Mermory IO Network 等
CGroups在接受到调用时,会给指定的进程挂上钩子,这个钩子在资源被使用时触发,触发时根据资源类别,然后使用对应方法进行限制。
有个术语叫Subsystem子系统,是一个资源调度控制器。CPU Subsystem 负责CPU时间分配,Memory Subsystem负责Mermoey使用量等。Docker启动一个容器后,会在cgroup目录下生成带有此容器ID的文件夹。

6.5 微服务适配容器化

微服务结合Docker,更加方便对微服务架构运维部署落地
以Java服务为例,容器资源限制通过CGroup实现,而容器内部进程如果不感知CGroup的限制,就进行内存,CPU分配,可能会导致资源冲突的问题。
Java8之前版本无法很好配合Docker,JVM通过容器获取可用内存和CPU数量并不是Docker允许使用的可用内存和CPU数量,在1.8之前在容器内获取的是上层物理机或者虚拟机的CPU核心数

Runtime.getRuntime().availableProcessors()

另一个影响体现在GC中,JVM垃圾对象回收对Java程序执行性能有一定影响,默认JVM使用公式来计算并行GC的线程数。如果JVM应用错误CPU核心数,会导致JVM启动过多的GC线程,导致GC性能下降,Java服务的延时增加

// ncpus是JVM发现系统CPU个数
ParallerlGCThreads = (ncpus <= 8)? ncpus:3 + ((ncpus* 5)/8)

7.ServiceMesh

微服务部署架构有一个边车模式,基于边车模式,拓展处理Sercive Mesh服务网格的概念

7.1 边车模式

是一种分布式服务架构的设计模式。在系统设计时,边车模式通过给应用程序添加边车的方式来拓展应用程序现有的功能,分离通用的业务逻辑,比如日志记录,流量控制,服务注册和发现,限流熔断等,通过添加边车实现,微服务只需要专注实现业务逻辑。
边车实际就是Agent,微服务通信可以通过Agent代理完成
在部署时,需要启动Agent,会处理服务注册,服务发现,日志和服务监控等逻辑,应用边车模式解耦了服务治理和对外的业务逻辑。边车模式控制的粒度更细,可以直接接管服务实例,合理拓展边车功能能够实现服务的横向管理,提升开发效率。

7.2 服务网格

边车模式实现的功能进一步标准化,会变得更加通用就可以抽象出一个通用的服务治理组件。
微服务领域有CNCF组织,云原生基金会,致力于微服务开源技术的推广,Service Mesh是CNCF推广的新一代微服务架构,致力于解决服务间通讯。

ServiceMesh可以认为是边车模式的进一步拓展,可以管理服务注册和发现,提供限流和降级功能,前置的负载均衡,服务熔断功能,日志和服务运行状态监控。管理微服务和上层容器通信。
使用Sidecar或ServiceMesh都可以认为是在原有系统上抽象一层新的设计来实现。服务网格就是抽象出专门一层,提供服务治理领域所需的服务注册发现,负载均衡,熔断降级,监控等功能,如何更好的基于各类云服务部署系统,是云原生要解决的问题,ServiceMesh可以统一管理微服务与上层通信的部分,接管各种网络通信,访问控制等。

7.2.1 ServiceMesh和API网关区别

服务网格实现的功能和API网关类似,都以一个切面的形式,进行一些横向功能实现。比如流量控制,访问控制,日志和监控等。服务网格和API网关主要区别是部署方式不同,在整体系统架构中位置不一样

  • API网关:独立部署,通过单独的系统提供服务,为了实现高可用,会通过集群方式管理。
  • 服务网格:集成在应用容器内,服务网格应用本身更近,相比如API网关,和应用交互链路更短

7.2.2 Istio

开源服务网关组件,Istio提供负载均衡,服务间身份验证,监控等方式,Istio实现通过Sidecar,通过添加一个Sidcar代理,在环境中为服务添加Istio的支持,代理会拦截不同服务之间通信,然后进行统一配置和管理。
特性:

  • 为HTTP,gRPC,websocket,tcp流量自动负载均衡
  • 对流量行为进行细粒度控制,包括丰富路由规则,重试,故障转移和故障注入
  • 可插拔的策略层和配置API,支持访问控制,速率限制和配额
  • 管理集群内所有流量的自动化度量,日志记录和追踪
  • 实现安全服务间通信,支持基于身份验证和授权的集群

7.2.3 Linkerd

最早由Twitter贡献,运营大型系统发现,最复制问题来源服务之间通讯,为解决服务之间通信问题,通过添加Linkerd代理,实现一个专用的基础设施层,为提供服务发现,路由,错误处理以及服务可见性等功能,而无须侵入应用内部实现

8.微服务

8.1 Dubbo

支持高性能远程服务调用,并且进行相关服务治理,功能上对标gRPC,Thrift典型的RPC框架

  • 基于SPI拓展:Service Provider Interface 是JDK内置的一种服务提供发现机制,要获取一个类的拓展必须加载所有实现类,得到指定的实现类需要遍历,Dubbo增强原生SPI实现,可以通过指定的拓展类来找到具体实现
  • 灵活服务调用:Dubbo支持多种服务调用方式,针对服务端和消费端的线程池,集群调用模式,异步和同步调用等都可以进行灵活配置
  • 责任链和插件模式:使用者可以在服务调用的责任链上,对各个环节进行自定义实现,也可以通过该方式解决Dubbo自带策略有限问题,Dubbo实现一个类似微内核加插件的设计,整体的可拓展性和灵活性都比较高
  • 高级特性支持:Dubbo对远程服务调用提供非常细粒度功能支持,比如服务发布支持XML,注解等多种方式,调用可以选择泛化调用,Mock调用

8.2 SpringCloud

  • 配置中心:Config
  • 服务发现:Eruka,Consul
  • API网关:Zuul,Kong
  • 负载均衡:Ribbon,Feign
  • 限流降级:Hystrix,sentinel
posted @ 2023-10-28 20:46  lwx_R  阅读(13)  评论(0编辑  收藏  举报