type
status
date
slug
summary
tags
category
icon
password

一. 单体架构

单体架构尽管也是模块化的逻辑,但是最终都会打包并部署为单体应用;
主要问题在于:应用本身的复杂性,导致任何一个模块的单独开发者都不可能搞懂;从而导致应用扩展起来十分困难且可靠度较低;最终导致敏捷性开发和部署变得无法实现;
单体应用适合小型项目;在打包成单体应用后,可以快速部署及发布;测试时依赖性也不强(因为它本身就包含了程序的所有)
微服务
微服务是一种SOA(面向服务的架构模式)的最佳实现方式;它提倡服务以业务原型为基础来进行划分服务;每个服务都尽量满足单一职责的原则;
在这样的前提下,可以保证单个服务的代码少,bug少;当然也更易于测试与迭代;
  • - 围绕业务功能构建的,服务关注单一业务,服务间采用轻量级的通信机制,可以全自动独立部署,可以使用不同的编程语言和数据存储技术。微服务架构通过业务拆分实现服务组件化,通过组件组合快速开发系统,业务单一的服务组件又可以独立部署,使得整个系统变得清晰灵活
  • - 原子服务
  • - 独立进程
  • - 隔离部署
  • - 去中心化服务治理
引入微服务后,一个完整的系统往往需要n多个服务来支持;而对于多个服务的管理,编排以及通信等 相对于巨石模型来说是额外的工程量;
微服务的引入,让平台对基建提出了更高的要求;
不足:
  1. 微服务应用是分布式系统,开发者不得不使用RPC或消息传递,来实现进程间通信;同时必须写代码来处理消息传递中速度过慢或服务不可用等局部失效问题
  1. 分区的数据库架构,同时更新多个业务主体的事务是很常见的场景。对于单体应用,仅保证自身的事务一致性即可,但对于分布式应用,提出了分布式事务一致性问题,增加了业务的实现难度,对开发者的技术要求也更高
  1. 测试一个基于微服务架构的应用是一件相对更复杂的任务;测试者必须在一个稳定的服务平台中对应用进行测试,因此测试环境的搭建,以及数据准备等都提出了更高的要求;同时由于服务联动,导致问题跟踪的难度变得更大;
  1. 服务间存在依赖关系,应用的升级可能会波及多个服务模块的修改;
  1. 对运维基础设施的挑战比较大
对于接口定义(服务契约):
发送时要保守,接收时要开放。按照伯斯塔尔法则的思想来设计和实现服务时,发送的数据要更保守,意味着最小化的传送必要的信息,接收时更开放意味着要最大限度的容忍冗余数据,保证兼容性。

二. 微服务设计

=============================================================================

A. API Gateway

拿到巨石架构的时候,历程:
进行微服务拆分:
按照业务垂直划分,所有微服务直接对外网进行服务(暴露一批微服务)
在后续微服务演进升级过程中,由于客户端直接与微服务通信,因此api与客户端强耦合;对于
老版本的api接口一直无法下线(因为无法预测客户端是否已更新到最新版本);这对于整个微服务的演进来说,
是一个比较大的阻碍
需要多次请求,客户端需要聚合大量数据,增加客户端的工作量,同时客户端针对数据的聚合会消耗大量的时间,
影响响应时长(延迟高)
各微服务往往由不同的团队开发,因此协议上是不一定统一的;需要端来进行兼容
面向端的api适配,耦合到内部服务(比如对于不同网络状态下,api的响应数据量可能是不一致的)
多终端兼容复杂:不同端要求的数据可能不完全一致,因此要么各端妥协建立公共api,要么差异化API;在这种情况下,微服务中需要同时包含差异化API以及新老API的兼容;换句话说也就是微服务包含了时间线上的所有API;大大增加了服务的复杂度
统一逻辑无法收敛,比如安全认证、限流:对于面对横切面的逻辑,每个服务都需要独立去实现
--- 提供app-interface-- BFF( backend for fronted)
App-interface位于所有服务上层,它可以通过 dataset join的方式,对个服务的api调用,进行数据聚合,最终提供给客户端
同时提供差异服务的能力:数据裁剪及聚合,针对终端定制化api
动态升级: 原有系统兼容升级,更新服务而非协议
沟通成本降低:客户端开发人员 和 服务开发人员均只需要同BFF成员进行沟通,固定的沟通模式往往能提高效率
BFF是一种适配服务: 将后端各服务api进行聚合,以及协议的精简,提供给客户端需要的数据格式,解耦服务与客户端;
  • - 缺陷: 形成了架构层面的单点服务;
  • -- BFF拆分 (业务场景拆分,重要性拆分)
  • -- 在BFF拆分之后,横切面功能(鉴权,限流等)又会分布到不同的BFF之中,
因此,抽取横切面功能的一层 --- API Gateway
=============================================================================

B. 微服务划分:

拆分方法:
  1. 业务职能
  1. DDD中的限界上下文
  1. CQRS:command and query separation service
gRPC 与服务发现
服务与服务之间的通信 --- RPC / 消息队列
RPC -- 同步 // 消息队列 -- 异步
gRPC -- 高性能,开源,统一的rpc
优势:
  1. 支持多语言
  1. 轻量级,高性能, 支持 protoBuf 和 json
  1. 可插拔: 自定义插件
  1. IDL: 基于文件定义服务,通过proto3工具生成指定语言的数据结构, 服务端接口以及客户端Stub
  1. 移动端的支持: 基于标准的http/2设计,支持双向流,消息头压缩,单TCP的多路复用,服务端推送等特性;这些特性使得gRPC在移动端设备上更省点和节省网络流量
  • -- 去了解 http2
proto示例:
notion image
示例命令:
protoc
  • -go_out=.
  • -go_opt=paths=source_relative
  • -go-grpc_out=.
  • -go-grpc_opt=paths=source_relative
helloworld/helloworld.proto

a. gRPC- HealthCheck

notion image
Consumer 探测 Provider健康状态的意义: 虽然我们服务的生命周期都交给了注册中心管理;但在Consumer拉取服务提供商信息后,Consumer 和 provider的网络却不一定连通,因为注册中心毕竟是第三者,属于间接的管理,需要由服务自身去确认其正确性
Health check 助于平滑升级或上下线
下线:
  1. 标识自身状态
  1. 发起注销请求到注册中心,同时针对自身的所有health check 均返回自身状态;
  1. 监测自身活跃请求数;
  1. 当没有活跃请求数时,优雅下线
  1. Kubernetes 超时强制退出 --(兜底)

C. 服务发现 - 客户端发现

服务端到注册中心去注册, 客户端拉取相关远程服务的注册信息, 客户端请求时,由 客户端自身在本地进行负载均衡,选择服务端实例来发起请求   --- 等价于 客户端 直连 服务端;
注册中心在整个流程中不参与业务, 仅作为服务信息的传递者

D. 服务发现 - 服务端发现

客户端通过负载均衡器向一个可用服务实例发送请求; 而由这个负载均衡器去注册中心查询服务注册表;
会形成集中式的负载均衡; 是不符合去中心化的思想的;
引出 "服务网格" - 类似一层代理,与服务端pod部署在一起,属于进程间通讯;

三. 多集群 及 多租户

从单一集群考虑,多个节点保证可用性,我们通常使用 N+2的方式来冗余节点
从单一集群故障带来的影响面角度考虑冗余多套集群
单个机房内的机房故障导致的问题
多租户本质即是添加自定义标识,根据标识进行流量的定向转发, 以在逻辑层面达到流量隔离的效果;可解决 单服务定向, 全链路定向 以及 灰度发布的问题;
多集群在逻辑层面划分出冗余以保障服务可用性,避免单服务故障影响过多关联服务;多租户实现的一种手段是通过特征值标识身份。多租户有助于灵活虚拟测试环境,且是可以与正式环境中服务交互的测试环境。多租户对于单服务测试、全链路测试、灰度都是有很大贡献的。应用层面可以用多租户解决,数据层面可以通过复制一份(或者一小部分)数据副本达到与模拟线上的效果,如果少读多写,可以新建/启用同 IP 下的另一个 DB 。
 

四. 参考:

 
go语言实践-errorpyqt5-添加logo
Loading...
leiax00
leiax00
让每一天都有意义🍚
最新发布
异地组网-zerotier
2025-4-10
apt/snap常用操作
2025-4-7
ubuntu操作备忘录
2025-4-1
git常用操作
2025-4-1
小智聊天机器人使用记录
2025-3-31
k8s/docker常用操作
2025-3-26
公告