业务之前采用了单体应用的架构 不同功能模块的代 码耦合在一起,编译打包部署也都在一起。
有的人忘记提交代码、有的人忘记打包、有的人忘记修改工程依赖到最新版本。一次上 线过程需要反复确认,耗费了大量精力,严重影响了整体的开发和部署效率。
最后选定了服务化的解决方案 对原有的单体应用架构进行改造,把功能相对独立的模块拆分出去,部署为微服务
当前移动互联网时代最先进的业务架 构解决方案,能更好地迎合移动互联网业务快速迭代的要求。
单体应用的痛(总结:部署 发布 协同 效率低 可用性差)
然而随着业务规模的不断扩大,团队开发人员的不断扩张,单体应用架构就会开始出现问 题。
部署效率低下
应用编译打包、部署测试一次,甚至需要 10 分钟以上
团队协作开发成本高
超过 5 人修改代码,然后一起打包部署,测试阶段只要有一块功能有问题,就得重 新编译打包部署,然后重新预览测试,所有相关的开发人员又都得参与其中,效率低下, 开发成本极高。
系统高可用性差
某段代码不断在内存中创建大对象,并且没 有回收,部署到线上运行一段时间后,就会造成 JVM 内存泄露,异常退出,那么部署在 同一个 JVM 进程中的所有服务都不可用,后果十分严重。
线上发布变慢
特别是对于 Java 应用来说,一旦代码膨胀,服务启动的时间就会变长, 有些甚至超过 10 分钟以上,如果机器规模超过 100 台以上,假设每次发布的步长为 10%,单次发布需要就需要 100 分钟之久。因此,急需一种方法能够将应用的不同模块 的解耦,降低开发和部署成本。
想要解决上面这些问题,服务化的思想也就应运而生。
什么是服务化?(总结:本地方法调用,改造成通过 RPC 接口产生的远程方法调用)
服务化就是把 传统的单机应用中通过 JAR 包依赖产生的本地方法调用,改造成通过 RPC 接口产生的远程方法调用
举个例子
以微博系统为例,微博既包含了内容模块,也包含 了消息模块和用户模块等。 其中消息模块依赖内容模块,消息模块和内容模块又都依赖用户 模块。 当这三个模块的代码耦合在一起,应用启动时,需要同时去加载每个模块的代码并连 接对应的资源。一旦任何模块的代码出现 bug,或者依赖的资源出现问题,整个单体应用 都会受到影响。
首先可以把用户模块从单体应用中拆分出来,独立成一个服务部署,以 RPC 接口的 形式对外提供服务.
什么是微服务(服务拆封更细 独立部署 独立维护 有统一治理平台)
那么微服务相比于服务化又有什么不同呢?
服务拆分粒度更细。
微服务可以说是更细维度的服务化,小到一个子模块,只要该模块依 赖的资源与其他模块都没有关系,那么就可以拆分为一个微服务。
服务独立部署
每个微服务都严格遵循独立打包部署的准则,互不影响。比如一台物理机 上可以部署多个 Docker 实例,每个 Docker 实例可以部署一个微服务的代码。
服务独立维护。
每个微服务都可以交由一个小团队甚至个人来开发、测试、发布和运维, 并对整个生命周期负责。
服务治理能力要求高
因为拆分为微服务之后,服务的数量变多,因此需要有统一的服务 治理平台,来对各个服务进行管理。
什么时候应该拆分单体应用?拆分单体应用有哪些标准可依呢(总结:互相影响就开始拆了 单体应用开发超过10人 根据功能是否独立 公共的也要分出去)
什么时候进行服务化拆分?
一个收费视频用户量访问过大导致内存泄露 因为免费视频和收费视频耦合在一起 最后导致免费视频无法观看
一旦单体应用同时进行开发的人员超过 10 人,就会遇到上面的问 题,这个时候就该考虑进行服务化拆分了。
服务化拆分的两种姿势
1是纵向拆分 :是将不同的功能模块 服务化,独立 部署和运维
标准是按照业务的关联程度来决定,关联比较密切的业务适合拆分为一个微服务,而功能相对比较独立的业务适合单独拆分 为一个微服务。
2是纵向拆分 :是从公共且独立功能维度拆分。
标准是按照是否有公 共的被多个其他服务调用,且依赖的资源独立不与其他业务耦合。
服务化拆分的前置条件(总结 :服务接口协议定义要事先定义好, 发布订阅用的注册中心 监控方案,服务治理方案 比如熔断 故障定位)
单体应用迁移到微服务架构时必将面临也必须解决的。
服务如何定义
每个服务都运行在各自的进程之中,应该以何 种形式向外界传达自己的信息呢
答案就是接口,无论采用哪种通讯协议,是 HTTP 还 是 RPC,服务之间的调用都通过接口描述来约定,约定内容包括接口名、接口参数以及 接口返回值。
服务如何发布和订阅
拆分为微服务独立部署后,服务提供者该如何对外暴露自己的地址,服务调 用者该如何查询所需要调用的服务的地址呢
注册中心
服务如何监控
需要一种 通用的监控方案,能够覆盖业务埋点、数据收集、数据处理,最后到数据展示的全链路功 能。
来关注我们最关心的是 QPS(调用量)、AvgTime(平均 耗时)以及 P999(99.9% 的请求性能在多少毫秒以内)这些指标
服务如何治理
服务的数量变多了,依赖关系也变复杂 了。比如一个服务的性能有问题时,依赖的服务都势必会受到影响。可以设定一个调用性 能阈值,如果一段时间内一直超过这个值,那么依赖服务的调用可以直接返回,这就是熔 断,也是服务治理最常用的手段之一。
故障如何定位
需要有一种解决方案能够将一次用 户请求进行标记,并在多个依赖的服务系统中继续传递,以便串联所有路径,从而进行故 障定位。
起走进微服务架构,来看看 它的各个组成部分
1.向注册中心注册服务 告诉我能提供什么服务和那个服务的地址
2.来服务消费者 ,查询所需要调用服务的地址 拿到地址发请求 拿到结果解析
3.服务的请求耗时、调用量以及成功率都被记录下来用监控 而调用经过的链路信息会被记录下来,用于故障定位和问题追踪
4.如果期间调用失败 可以通过重试等服务治理手段来保证成功率
总结一下,微服务架构下,服务调用主要依赖下面几个基本组件:
服务描述
注册中心
服务框架
服务监控
服务追踪
服务治理
服务描述
首先要解决的问题就是服务如何对外描述。的服务名叫什么?调用这个服务需要提供哪些信息?调用这个服务返回的结果是什么 格式的?该如何解析?
这些都是服务描述组件解决的 一般包括 RESTful API、XML 配置以及 IDL 文件
RESTful API 方式通常用于 HTTP 协议的服务描述,并且常用 Wiki 或者Swagger来 进行管理
IDL 文件方式通常用作 Thrift 和 gRPC 这类跨语言服务调用框架中,比如 gRPC 就是通过 Protobuf 文件来定义服务的接口名、参数以及返回值的数据结构,示例如下
注册中心
下一步要解决的问题就是服务的发布和订阅
提供者一启用 就向注册中心注册自己服务(会根据 服务发布文件的发布信息)
消费者在启动时 就向注册中心订阅自己服务(消费者配置文件 中 配置的服务信息)
再然后注册中心返回服务提供者地址列表给服务消费者
当服务提供者发生变化 ,注册中心将变更通知给服务消费者。
服务框架
在发起调用之前你还需要解决以下几个问题
服务通信采用什么协议? TCP、UDP 协议,还是采用七层 HTTP 协议,还是采用其他协议?
数据传输采用什么方式? 就是说服务提供者和服务消费者之间的数据传输采用哪种方式, 是同步还是异步,是在单连接上传输,还是多路复用。
数据压缩采用什么格式?比如常见的 JSON 序列化
服务监控
一旦服务消费者与服务提供者之间能够正常发起服务调用,你就需要对调用情况进行监控, 以了解服务是否正常。通常来讲,服务监控主要包括三个流程。
指标收集。就是要把每一次服务调用的请求耗时以及成功与否收集起来,并上传到集中的 数据处理中心。
数据处理。每次调用的请求耗时以及成功与否等信息,就可以计算每秒服务请求量、 平均耗时以及成功率等指标。
数据展示。数据收集起来,经过处理之后,还需要以友好的方式对外展示,才能发挥价 值。通常都是将数据展示在 Dashboard 面板上,并且每隔 10s 等间隔自动刷新,用作 业务监控和报警等。
服务追踪
原理:
服务消费者发起调用前,会在本地按照一定的规则生成一个 requestid,发起调用时,将 requestid 当作请求参数的一部分,传递给服务提供者。
服务提供者接收到请求后,记录下这次请求的 requestid,然后处理请求。如果服务提供 者继续请求其他服务,会在本地再生成一个自己的 requestid,然后把这两个 requestid 都当作请求参数继续往下传递。
服务治理
服务监控能够发现问题,服务追踪能够定位问题所在,而解决问题就得靠服务治理了。服务 治理就是通过一系列的手段来保证在各种意外情况下,服务调用仍然能够正常进行
单 IDC 故障。你应该经常听说某某 App,因为施工挖断光缆导致大批量用户无法使用的 严重故障。而服务治理可以通过自动切换故障 IDC 的流量到其他正常 IDC,可以避免因为单 IDC 故障引起的大批量业务受影响。
依赖服务不可用。比如你的服务依赖依赖了另一个服务,当另一个服务出现问题时,会拖 慢甚至拖垮你的服务。而服务治理可以通过熔断,在依赖服务异常的情况下,一段时期内 停止发起调用而直接返回。这样一方面保证了服务消费者能够不被拖垮,另一方面也给服 务提供者减少压力,使其能够尽快恢复。
04 | 如何发布和引用服务?
05 | 如何注册和发现服务?
注册中心原理
读取各自的xml配置文件 向注册中心注册自己的服务
服务的发心跳信息 client向注册中心订阅 并于RPC 建立连接
节点别更时 会刷新本地换从去新的地址调用
注册中心实现方式
涉及几个问题 1.需要提供哪些接口 2.如何部署 3.如何存储服务信息 4.如何监控服务提供者节点的存活5.节点变化如何通知消费者
注册中心 API
集群部署
注册中心一般采用集群 为了高可用 并通过分布式一致性协议保证数据一致性 就比如注册中心开源项目 zookeeper
目录存储
服务健康状态检测
是基于 ZooKeeper 客户端和服务端的长连接和会话超时控制
客户端和服务端建立连接后 就建立会话 生成sessionid 在一定时间内会不断发心跳信息 SESSION_TIMEOUT 没再收到ping的消息 则任务结束会话 ZooKeeper 就会认为这个服务节点已经不可用,将会从注册中心中删除其 信息
服务状态变更通知
白名单机制
例如 错误的把测试环境下的节点注册到线上注册中心集群,这样的话线上流量调用到测试机的RPC 所以后果可能很严重
所以提供一个白名单 只有添加到注册中心白名单的RPC 才能去注册接口
06 | 如何实现RPC远程服务调用?
客户端和服务端如何建立网络连接?
断开处理1.链路存活检测 (总结 客户端不断发心跳 当客户端发现次数和时间达到一定程度后没有回复 那么就要和服务器重新建立链接了)
断连重试2.(总结 要过一会儿再连 不然还没等到计算机回收连接 就又有连接进来 导致资源瞬间被占满)
服务端如何处理请求?
服务端如何处理请求1-同步阻塞方式(BIO-适用于连接数比较小的业务场景)
一个线程处理一个请求 线程池满的时候 其他请求无法进来
服务端如何处理请求2-同步非阻塞方式 (NIO-适用于连接数比较多并且请求消耗比较轻的业务场景)
服务端如何处理请求3-异步非阻塞方式(AIO-连接数比较多而且请求消耗比较重的
)
发起调用会立马收到结果 完成后收到I/O结果 不需要实际IO读写操作 真正IO 在内存处理了
数据传输采用什么协议
数据该如何序列化和反序列化?
07 | 如何监控微服务调用?
监控对象
监控对象分4层 从上往下 用户端监控 借口监控 资源监控 基础监控
用户端监控:业务直接对用户提供的功能的监控 比如微信发送消息
接口监控: 对rpc接口的监控 比如 比如好友列表功能的监控
资源监控:接口依赖的资源监控 比如资源再redis 对redis的监控
监控指标
监控维度
全局 从整体角度监控对象的请求量 平均耗时 错误率 全局唯独的监控一般是为了让你有个大概的了解
分机房维度 一个机房一个机房的监控
单机
时间 一周前 一月前 三月前
核心 把核心的与非核心的分开监控
对于一个微服务来说,你必须明确要监控哪些对象、哪些指标,并且 还要从不同的维度进行监控,才能掌握微服务的调用情况。
监控系统原理(总结四大环节)
数据收集
通常有两种数据收集方式:代理收集:把调用信息加入到日志文件中 分析系统进行分析
数据传输
udp 和 kafka(发送指定topic 让数据处理单元订阅对应的topic)
数据处理
对收集来的原始数据进行聚合并村粗
接口维度聚合 这个维度是把所有实时收集来的数据接口名维度聚合在一起 可以统计每个接口的实时请求量 平均耗时
机器维度聚合 把调用节点维度聚合在一起 (可以判断每个节点的实时请求量和平均耗时 )
存储 两种
一种是索引数据库 比如es 查询按索引
一种是实讯数据库 比如openTSDB 查询按时讯 1min,5min来进行查询
数据展示
2.饼状图 (监控占比)
3.格子图 (细粒度的监控)
如果没有强大的监控能力 改造微服务就不能掌握各个服务的情况 如果不能快速定位 是一场灾难
08 | 如何追踪微服务调用?
在微服务里 有各个的服务 一次请求设计到多个服务 由于一次请求设计到 异地 语言不同 机器不同 ,那么请求失败查看具体原因是件多么复杂的事
那么有这么一套服务追踪系统 可以跟踪发起了哪些调用 经过了哪些服务 并且记录了每一次调用所设计到的详情信息 如果调用失败了 你就可以通过这个服务追踪系统 你就可以快速定位在哪个环节出现了问题
服务追踪的作用
除了快速 定位 我在这里列出了4点 可以帮你在微服务改造过程解决不少问题
第一 优化系统瓶颈
通过记录调用经过的每一条链路上的耗时 我们能快速定位系统瓶颈点所在 是网络慢呢 还是网关系统异常
可以从全局视角去观察 对某个瓶颈点作出优化
第二,优化链路调用
判断服务经过的链路是否合理 比如一个服务下游依赖了多少个服务 经过这个链路分析 可以判断每个依赖是否合理是否都是必要的 是否可以通过业务来优化
比如跨中心服务调用了 比如一个服务a调用了 另外一个服务中心的服务b 而没有调用自身的服务中心b 那么通过链路调用
第三,网络拓扑
第四,透明传输数据
服务追踪系统原理
节点上的同一次请求串联起来,从而还原原有的调用关系,可以追踪系统问题、分析调用数据并统计各种系统指标。
traceid 用于标记用户请求的唯一ID 在第一层生成 随着rpc调用不断往后传递 这样就可以把调用路径串联起来
spanid 用于标识一次 RPC 调用在分布式请求中的位置
annotation,用于业务自定义埋点数据,可以是业务感兴趣的想上传到后端的数据,比 如一次请求的用户 UID。
服务追踪系统实现
数据采集层
作用是在各个模块之间进行埋点 上报给数据处理层进行处理
SS(Server Send)阶段 : 服务端返回请求,这个阶段会将服务端上下文数据上报,下面 这张图可以说明上报的数据有:traceId=123456,spanId=0.1,appKey=B, method=B.method,start=103,duration=38。
CR(Client Recieve)阶段 : 客户端接收返回结果,这个阶段会将客户端上下文数据上 报,上报的数据有:traceid=123456,spanId=0.1,appKey=A, method=B.method,start=103,duration=38。
2数据处理
针对实时数据处理,一般采用 Storm 或者 Spark Streaming 来对链路数据进行实时聚合加 工,存储一般使用 OLTP 数据仓库,比如 HBase,使用 traceId 作为 RowKey,能天然地 把一整条调用链聚合在一起,提高查询效率。
离线数据处理
针对离线数据处理,一般通过运行 MapReduce 或者 Spark 批处理程序来对链路数据进行 离线计算,存储一般使用 Hive。
3. 数据展示层
服务整体情况:服务总耗时、服务调用的网络深度、每一层经过的系统,以及多少次调用。 下图展示的一次调用,总共耗时 209.323ms,经过了 5 个不同的系统模块,调用深度为 7 层,共发生了 24 次系统调用。
每一层发生了几次调用,以及每一层调用的耗时。
调用拓扑图
下面是一张 Pinpoint 的调用拓扑图,通过这张图可以看出系统内都包含哪些应用,它们之 间是什么关系,以及依赖调用的 QPS、平均耗时情况。
调用拓扑图是一种全局视野图,在实际项目中,主要用作全局监控,用于发现系统中异常的 点,从而快速做出决策。比如,某一个服务突然出现异常,那么在调用链路拓扑图中可以看 出对这个服务的调用耗时都变高了,可以用红色的图样标出来,用作监控报警。
09 | 微服务治理的手段有哪些?
可见,一次服务调用,服务提供者、注册中心、网络这三者都可能会有问题,此时服务消费 者应该如何处理才能确保调用成功呢?这就是服务治理要解决的问题。
节点管理
服务消费者出现问题 或者网络不通
无论哪种都有节点管理的两种管理手段
1.注册中心主动摘除
服务提供者主动回报心跳 如果超时 那么就把这个节点给摘除了 并把最近的可用节点推送给服务消费者
2.服务消费者摘除机制
虽然1方案可以解决服务提供者节点异常,那么要是服务注册中心网络到提供者网络不通呢 就会把接所有服务提供者全部摘除
所以存活探测机制在服务消费者这段更加合理 如果发现到服务提供者节点失败那么就在内存中删除
负载均衡
由于采购机子批次不同 新采购的机子性能要好于旧的批次 对于服务消费者而言 在从服务列表中选择可用节点 希望让配置高一些的机器承担多一点流量那么就需要用到负载均衡的算法
1.随机算法
每个节点得到调用量是差不多的
2.轮询算法
就是按照固定权重 对可用节点轮询 可以对某些好的配置节点调高他的权重 那么请求量就会多一些
3.最少活跃调用算法
在服务消费者那一端维护一个连接数 选择连接数较少的的节点发起调用
4.一致性hash算法
指相同参数的请求总是发到同一服务节点。当某一个服务节点出现故障时,原本发往该节点 的请求,基于虚拟节点机制,平摊到其他节点上,不会引起剧烈变动。
配置差不多 选择1和2 算法最合适 配置明显差异选择3最合适
服务路由
选择哪个节点发起调用不仅是负载均衡算法决定 还是有服务路由规则确定 为什么要有这个规则
1.原因是因为业务存在灰度发布的需求
2.多机房就近访问原则
如何配置路由规则呢
静态配置(放在消费端 要想更换调用配置 需要修改 并重新上线)
和
动态配置 (这种方式下 路由规则是存在注册中心的 定期去请求服务器来保持同步 修改注册中心即可 下一次请求 会请求注册中心来更新配置 从而实现动态变更)
服务容错
对于服务调用失败的情况,需要有手段自动恢复,来保证调用成功。failouver
FailBack
失败通知 调用失败后不再重试 而是返回的结果来决定后续的操作 比如像上面幂等 调用失败了不只是执行重试 而是查询服务端的状态 看调用是否生效 已经生效不再重试
FailCahce
失败缓存 调用失败不立即发起调用 而是过一段时间后重启发起调用
Failfast
快速失败 调用失败不重试 采用于非核心的调用 记录失败日志后就返回了
你可以看出它们的使用场景是不同的,一般情况下对于 幂等的调用,可以选择 FailOver 或者 FailCache,
非幂等的调用可以选择 FailBack
或者 FailFast。
上面我讲的服务治理的手段是最常用的手段,它们从不同角度来确保服务调用的成功率。节 点管理是从服务节点健康状态角度来考虑,负载均衡和服务路由是从服务节点访问优先级角 度来考虑,而服务容错是从调用的健康状态角度来考虑,可谓是殊途同归。
在实际的微服务架构实践中,上面这些服务治理手段一般都会在服务框架中默认集成了,比 如阿里开源的服务框架 Dubbo、微博开源的服务框架 Motan 等,不需要业务代码去实 现。如果想自己实现服务治理的手段,可以参考这些开源服务框架的实现。