一、高可用的方法论:集群冗余 + 故障自动转移
实现高可用的基本方法论是:集群冗余 + 故障自动转移。
集群冗余(Redundancy):这意味着系统中的关键组件或服务不只部署一份,而是有多份副本同时运行。当其中一份出现故障时,其他副本可以立即接管工作,避免单点故障。这通常通过部署多个服务实例、多个数据库副本等方式实现。
故障自动转移(Automatic Failover):当某个组件或服务发生故障时,系统能够自动检测到故障,并将流量或请求自动切换到健康的冗余副本上,无需人工干预。这是确保服务连续性的核心机制。
二、高可用细节:端到端的故障转移
在微服务架构中,高可用性需要贯穿整个请求链路,从用户端到最底层的数据库,每个环节都需要考虑故障转移机制。以下是各个关键环节的故障转移细节:
1. “端”到“反向代理”
这是用户请求进入系统的第一道关卡。这里的“端”可以是用户浏览器、移动App或IoT设备。
DNS解析:通过DNS解析将域名解析到多个反向代理服务器的IP地址。当某个反向代理服务器故障时,DNS可以配置健康检查,将故障IP从解析结果中移除,或客户端通过重试连接到其他IP。
客户端重试/负载均衡:移动App或桌面应用可以在本地内置多个反向代理的IP列表,当一个连接失败时,自动尝试连接列表中的下一个。
Anycast网络:对于全球部署的系统,可以使用Anycast技术,将用户请求路由到地理位置最近且可用的反向代理节点。
2. “反向代理”到“站点应用”
反向代理(如Nginx、HAProxy)负责将外部请求转发到后端实际处理业务逻辑的“站点应用”(通常是Web层或API网关)。
健康检查:反向代理会定期对后端站点应用进行健康检查(如HTTP心跳检测)。如果某个站点应用实例不健康,反向代理会将其从可用列表中移除,不再转发请求给它。
负载均衡算法:反向代理使用各种负载均衡算法(如轮询、最少连接、IP哈希等)将请求分发到健康的站点应用实例。
会话保持(Session Persistence):对于需要会话保持的应用,反向代理通常会通过Cookie或IP哈希等方式,确保同一用户的请求始终被转发到同一个后端实例,避免会话丢失。
3. “站点应用”到“微服务”
站点应用(或API网关)作为客户端,需要调用后端的各种微服务来完成业务逻辑。
服务注册与发现:微服务实例启动时,会向服务注册中心(如Eureka、Consul、Zookeeper、Nacos)注册自己的地址和状态。站点应用(或通过客户端负载均衡器)从注册中心获取可用的微服务实例列表。
客户端负载均衡:站点应用(或其内置的SDK)会根据从注册中心获取的列表,选择一个健康的微服务实例进行调用,并实现重试机制。
熔断与降级:当被调用的微服务出现故障或响应缓慢时,调用方(站点应用)会触发熔断机制,停止对该服务的调用,快速失败或返回默认值,防止故障扩散。同时,可以实施降级策略,在服务不可用时提供有限功能。
超时与重试:设置合理的调用超时时间,并在超时或失败时进行有限次数的重试。
4. “微服务”到“缓存”
微服务通常会依赖缓存(如Redis、Memcached)来提升性能和减轻数据库压力。
缓存集群:缓存系统本身通常是集群部署的,例如Redis Sentinel/Cluster,Memcached分布式集群。
客户端智能路由:缓存客户端SDK通常内置了对缓存集群的感知能力,能够自动发现节点、路由请求到正确的节点,并在节点故障时进行自动重试和切换。
多级缓存:结合本地缓存、分布式缓存,当分布式缓存不可用时,可以提供降级方案。
缓存穿透、击穿、雪崩防护:通过布隆过滤器、互斥锁、设置不同过期时间等策略,防止缓存失效时对后端数据库造成冲击。
5. “微服务”到“读库”
微服务进行数据查询时,通常会访问读数据库(从库)。
读写分离:读库通常是主库的从库,通过主从复制实现数据冗余。
读库集群:部署多个读库实例,形成读库集群。
数据库中间件/代理:通过数据库中间件(如MyCAT、ShardingSphere)或客户端SDK,实现读请求的负载均衡和故障转移。当某个读库故障时,请求会自动转发到其他健康的读库。
数据同步监控:监控主从复制的延迟,确保读库数据的新鲜度。
6. “微服务”到“写库”
微服务进行数据写入时,通常会访问写数据库(主库)。
主备切换/主从高可用:写库通常是单点,但会配置高可用方案,例如:
主备模式:一个主库负责写,一个或多个备库实时同步数据。当主库故障时,备库可以被提升为新的主库(自动或手动)。
数据库集群:如MySQL Group Replication、PostgreSQL BDR、MongoDB Replica Set等,原生支持高可用和故障转移。
数据持久化:确保写操作的数据能够可靠地持久化,即使在故障发生时也能恢复。
分布式事务:对于涉及多个微服务或多个数据库的写操作,需要通过分布式事务(如基于消息队列的最终一致性、TCC)来保证数据的一致性。

