定义(底层视角)
单一功能
- 避免单个服务的代码量过大(代码量对于业务迭代、维护的影响较大)
- 各服务间定义清晰的边界(解耦合),易于任务的拆解
服务自治
- 各服务可以搭建在异构体系之上
- 各服务允许使用不同的技术栈
- 定义明确、合理的API,服务内部调整不应该影响上下游
优势
- 技术栈多样化,容易吸收技术,技术更新成本较小
- 健壮性更佳,可以降低单个问题服务对整体的影响,服务可降级
- 扩展性更佳
- 易于部署,降低故障概率,提升部署效率
- 服务组件化,可复用
- 业务迭代更快,不容易出现“不可维护代码”
设计模式
共享数据模式
不同的业务模块(或)可以看到所有的数据,并允许其对数据进行编辑
优势:
- 简单,易于新业务快速集成
劣势
- 如果某一业务希望对表结构进行更改,需要非常小心,因为别的业务可能也在使用同一张表
- 绑定数据库选型,不易更改
- 共享的是“数据”,而非“行为”,同一行为可以出现在不同的业务上,造成“行为”冗余
步与异步调用模式
名称 | 详细 | 方式 | 优势 |
---|---|---|---|
同步调用 | 上游服务等待下游服务返回请求结果 | request/response | 1、简单,方便问题排查; 2、最快速的获取到请求结果; |
异步调用 | 上游服务发起请求后不等待游服务返回请求结果,而是通过别的方式获取到请求结果,或者不需要获取请求结果 | 1、上游系统不定时询问下游系统是否处理完成; 2、下游系统完成处理后给上游系统一次回调; | 1、适合长时间运行的job,适合在手机移动网络环境使用; 2、不会阻塞住上游系统,提升上游系统的并行度; |
请求/响应与事件驱动模式
名称 | 详细 | 调用模式 | 适用场景 |
---|---|---|---|
请求/响应模式 | 上游服务发起一次请求,同时获取到下游返回的请求结果 | 1、同步调用 2、异步调用 | 1、上游系统关注下游系统的处理结果; 2、实时性较强; |
事件驱动模式 | 上游系统推送一次事件,下游系统拉取事件后进行处理 | 异步调用 | 1、动态添加下游系统; 2、下游系统服务问题对上游系统无影响; 3、能保证事件被处理,对峰值流量可以做到平滑处理; |
rpc vs http
名称 | 优势 | 适用场景 |
---|---|---|
rpc | 1、参数返回值简单明了(类似与本地函数调用); 2、通常性能更佳(tcp, udp),可以实现长链接; 3、通常可以做到向前兼容; | 1、中、后台; 2、对性能要求很高的服务; |
http | 1、多语言集成进标准库,无需外部依赖; 2、对防火墙、代理、负载均衡等服务友好; | 1、面向前端或外部团队的服务; |
缓存
客户端缓存
- 能极大的降低网络调用量;
- 服务端下发请求结果时,注明有效期,在有效期内客户端不用访问服务端,直接只用之前获取到的结果;
- 陈旧数据的通知机制比较负责;
- 服务端下发请求时,为返回内容打上一个标签,客户端下次请求时带上该标签,当这段时间结果不变时不会重发,否则更新请求结果和标签;
代理缓存
- 最简单的搭建缓存的方式,服务端和客户端无感知;
服务端缓存
- 更容易分析结果,也更容易对调试缓存机制,提升缓存的命中率;
- 如果有多种客户端存在,在服务端加缓存也比在客户端更快;
提供客户端
优势
- 方便使用,同时支持多语言
- 屏蔽内部的通讯协议,允许更新通讯协议并对上游服务无感知
- 基础功能只需要开发一次,如服务发现、故障节点处理、重试处理、本地缓存和日志管理等,不需要每个下游服务重复开发
注意点
- 鉴于服务端和客户端代码均由同一团队开发,需要注意业务逻辑由服务端向客户端转移,轻量级的客户端有利于业务的正常迭代、升级与运维
- 考虑到业务迭代需要保证客户端的扩展性,同时允许多个版本的客户端同时存在
UI交互模式
web用户,web控制台,native app(android和ios),h5
1、不同业务的微服务暴露接口供UI直接使用;
2、提供统一的API网关
3、按照前端对象或功能提供多个API网关,如可以针对web端、native app和h5提供三个API网关;
分析
- 第一种模式实现最简单,但UI和各微服务接口强耦合,后两种模式通过增加API层可以将二者解耦;
- 第一种模式会出现同一展示业务多次调用后端服务的情况,增加了客户端的逻辑,同时对于mobile应用不友好;
- API层可以承担业务展示逻辑,从而保证各后台服务的“独立性”,后台服务与业务迭代解耦;
- 第二种模式会导致所有业务迭代均需要API层修改,API层成为业务开发的瓶颈;
- 第三种模式会导致部分逻辑重复,如按照前端对象划分会造成同一组合业务逻辑重复,按照功能划分会导致用户鉴权等基础功能重复;
服务发现
客户端发现
客户端负责确定可用服务实例的网络位置和请求负载均衡。 客户端查询服务注册中心(service registry),它是可用服务实例的数据库。之后, 客户端利用负载均衡算法选择一个可用的服务实例并发出请求。
优点
-
结构简单,除了服务注册中心,没有其他移动部件
- 方便业务实现特定于应用程序的负载均衡决策
缺点
-
客户端与服务注册中心耦合在一起,而服务注册中心通常使用特定的协议(如zk),每种语言都需要开发
服务端发现
客户端通过负载均衡器向服务发出请求。负载均衡器查询服务注册中心并将每个请求 路由到可用的服务实例。
优点
-
把发现的细节从客户端抽 象出来。客户端只需向负载均衡器发出请求
-
一些部署环境免费提供此功能,如k8s
缺点
-
除非负载均衡器由部署环境提供,否则您需要引入这个高可用系统组件,并进行设置和管理
DNS
流程
1、请求发送到dns server(层级),获取到域名对应的ip list;
2、本地缓存ip list,若下一次查询在ttl时间内,则直接使用上次查询的结果;
3、round robin轮询选出一个ip;
优点
1、linux集成,集成简单;
2、无中间层服务,性能优异;
缺点
1、由于存在ttl,更新的配置存在到达延迟;
2、不能感知不同ip的负载能力,也不能感知不同ip的异常;
3、不支持动态注册;
NGINX
优点
- 热备:如果你有2台服务器,当一台服务器发生事故时,才启用第二台服务器给提供服务;
- 加权轮询:跟据配置的权重的大小而分发给不同服务器不同数量的请求;
- ip_hash:nginx会让相同的客户端ip请求相同的服务器;
- 下游感知可配置(免费版本的只支持被动感知,付费版本支持主动探活)