微服务概述
-
单体架构
- 尽管在设计上也是模块化的设计逻辑,但是打包还是会打包在一起,其中最主要的问题就是这个应用太复杂,导致应用无法扩展,可靠性低,最终单体敏捷性开发和部署都变的无法完成
-
微服务起源
- 微服务是SOA服务的一种实践
- 小即使美:小的服务代码少,bug少,容易测试,容易维护,也可以更容易不断迭代完善
- 单一职责:一个服务只做好一件事
- 可移植性比效率更重要
- 尽可能早的创建模型
-
微服务定义
围绕业务功能构建,服务关注单一业务,服务间采用轻量级通信机制,可以全自动独立部署,可以使用不同的编程语言和数据存储技术,微服务架构通过业务拆分实现服务组件化,通过组件组合快速开发系统,业务单一的服务组件又可以独立部署,使得整个系统变的灵活
- 原子服务
- 独立进程
- 隔离部署
- 去中心化服务治理
-
微服务的不足
- 微服务应用是分布式系统,由此会带来固有的复杂性,开发者不得不用RPC进行消息传递,实现进程之间的通信
- 分区的数据库结构:在微服务架构应用中,需要更新不同服务所使用的不同的数据库,从而对开发者提出了更高的挑战
- 测试一个机遇微服务架构的应用也是很复杂的任务
- 服务模块之间的依赖
- 对运维要求较高
-
组件服务化
传统实现组件的方式是通过库,库的局部变化意味着整个应用重新部署,通过服务来实现组件,意味着应用拆散为一系列服务运行在不同的进程中
- Kit:一个微服务的基础库
- Service:业务代码 + kit依赖 + 第三方依赖组成的业务微服务
- rpc + message queue : 轻量级通信
-
去中心化
- 数据去中心化
- 治理去中心化
- 技术去中心化
-
基础设施自动化
- CI CD:Gitlab + Gitlab hooks + k8s
- Testing: 测试环境,单元测试,API自动化测试
- 在线运行时:k8s + Prometheus ELK Control Panle
-
可用性 和兼容性设计
- 隔离
- 超时控制
- 负载保护
- 限流
- 降级
- 重试
- 负载均衡
微服务设计
-
API网关设计
增加一个api-interface 用于统一协议出口,在服务内进行大量的dataset join 按照业务场景来设计粗力度的API 为后续服务的进化带来优势
- 轻量交互
- 差异服务
- 动态升级
- 沟通效率的提升
- 业务流程: 移动端-- API 网关 -- BFF -- 微服务
-
微服务划分
- 边界划分
- 业务职能
- 限界上下文
- 边界划分
-
微服务安全
- 对于外网的请求来说,我们通常在 API Gateway 进行统一的认证拦截,一旦认证成功,我们会使用 JWT 方式通过 RPC 元数据传递的方式带到 BFF 层,BFF 校验 Token 完整性后把身份信息注入到应用的 Context 中,BFF 到其他下层的微服务,建议是直接在 RPC Request 中带入用户身份信息(UserID)请求服务。
- Api gateway -- bff - service - biz auth - jwt - request args
- 对于内网服务,一般要区分身份认证和授权
- full trust
- half trust
- zero trus
- 对于外网的请求来说,我们通常在 API Gateway 进行统一的认证拦截,一旦认证成功,我们会使用 JWT 方式通过 RPC 元数据传递的方式带到 BFF 层,BFF 校验 Token 完整性后把身份信息注入到应用的 Context 中,BFF 到其他下层的微服务,建议是直接在 RPC Request 中带入用户身份信息(UserID)请求服务。
-
GRPC
- 特性:
- 多语言
- 轻量级,高性能
- 可插拔
- IDL
- 设计理念
- 移动端:基于HTTP2设计,支持双向流,消息头压缩,单TCP的多路复用,服务端推送等特性
- 服务而非对象,消息而非引用
- 负载无关:不同的服务需要使用不同的消息类型和编码
- 流:streaming api
- 阻塞式和非阻塞式:支持异步和同步处理在客户端和服务端间交互的消息序列。
- 元数据交换
- 标准化状态码
- protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative helloworld/helloworld.proto
- healthCheck
- 主动健康检查 health check,可以在服务提供者服务不稳定时,被消费者所感知,临时从负载均衡中摘除,减少错误请求。当服务提供者重新稳定后,health check 成功,重新加入到消费者的负载均衡,恢复请求。health check,同样也被用于外挂方式的容器健康检测,或者流量检测(k8s liveness & readiness)。
- 特性:
-
服务发现
- 发现类型
- 客户端发现:直连,比服务端服务发现少一次网络跳转,Consumer 需要内置特定的服务发现客户端和发现逻辑。
- 服务端发现:Consumer 无需关注服务发现具体细节,只需知道服务的 DNS 域名即可,支持异构语言开发,需要基础设施支撑,多了一次网络跳转,可能有性能损失。
- 通过 Family(appid) 和 Addr(IP:Port) 定位实例,除此之外还可以附加更多的元数据:权重、染色标签、集群等。
- Provider 注册后定期(30s)心跳一次,注册, 心跳,下线都需要进行同步,注册和下线需要进行长轮询推送。
- Consumer 启动时拉取实例,发起30s长轮询
- Server 定期(60s) 检测失效(90s)的实例,失效则剔除。短时间里丢失了大量的心跳连接(15分钟内心跳低于期望值*85%),开启自我保护,保留过期服务不删除。
- 发现类型
多集群多租户
- 多集群
- 从单一集群考虑,多个节点保证可用性,通常使用N+2的方式来冗余节点
- 从单一集群故障带来的影响面角度考虑冗余多套集群
- 利用 paas 平台,给某个 appid 服务建立多套集群(物理上相当于两套资源,逻辑上维护 cluster 的概念),对于不同集群服务启动后,从环境变量里可以获取当下服务的 cluster,在服务发现注册的时候,带入这些元信息。当然,不同集群可以隔离使用不同的缓存资源等。
- 统一为一套逻辑集群(物理上多套资源池),即 gRPC 客户端默认忽略服务发现中的 cluster 信息,按照全部节点,全部连接。能不能找到一种算法从全集群中选取一批节点(子集),利用划分子集限制连接池大小。
- 多租户
- 在微服务架构中允许许多系统共存是利用微服务稳定性和模块化最有效的方式之一,这种方式一般被称为多租户,租户可以是测试,金丝雀发布,影子系统(shadow systems),甚至服务层或者产品线,使用租户能够保证代码的隔离性并且能够基于流量租户做路由决策。
- 入站请求绑定上下文,in-process使用context传递,跨服务使用metadata传递,在这个架构中每一个基础组件都能够理解租户信息,并且能够给予租户路由隔离流量,同时在平台中允许对运行不同的微服务有更多的控制,比如指标和日志,在微服务架构中典型的基础组件是日志,指标,存储,消息队列,缓存和配置。基于租户信息隔离数据需要分别处理基础组件。
有疑问加站长微信联系(非本文作者)