跨数据中心高可用架构设计

news2024/11/25 2:40:38

前言

随着常年的码代码,做设计,笔者做过基础编码,云计算平台,架构师,见过不少应用设计,系统设计,中间件,了解现有的技术体系发展模式,集中式->分布式;cap与base理论,基本上绝大部分时候可用性都是设计的必要目标,那么可用性在分布式的情况下是如何实现的呢,答案就是副本,即多部署几个资源,理论上部署越多,可用性越高,但是状态这个并不是所有情况都是无状态的,所以取舍在所难免。

常见的设计

常用的各种技术都会有副本的概念,无状态的副本,比如多核CPU,每个核心都是独立运行,都可以执行时间片线程,但是缓存一致性问题依然存在(MESI协议)。同理在分布式环境中,如果无状态服务,那么部署资源越多,可用性越高,因为不用考虑一致性,根据CAP理论,AP可以做到。但是实际情况经常需要一致性,比如数据库事务、会话等。

在现实情况,云计算就有区域、可用区的概念,实际上就是多数据中心,那么高可用架构就是有状态的。常见设计有主备、副本集、分片集群、连接集群。

主备+仲裁

主备设计在很多场景使用,典型的是MySQL MHA,Redis哨兵。以MySQL为例,如果需要自动failover,那么需要MHA等仲裁节点支持

 实际上Redis的哨兵模式也是如此,把主和备分别放在不同的数据中心,当然延迟越小越好,这就涉及跨数据中心的延迟设计,比如AWS,直接用专线(钞能力),也可以让数据中心足够近或者传输数据足够少等方式优化。

此处MHA的server就是仲裁节点,负责failover,主备自动切换,根据心跳探测,实际上mongodb的副本也可以使用1+2模式,原理相同。

同理,因为主备复制的原因,备节点不能提供写入,且需要从主节点复制(全同步、半同步、异步),所以备节点不能过多,存在主节点写入过大无法扩容的问题。

副本集(延展集群)

副本集一般不使用仲裁方式,实际上也是这个思路,但是需要奇数个节点相互仲裁即可,实际上偶数也可以,但是会出现脑裂或者很难仲裁的现象。这种思路都是基于paxos算法,但是Paxos算法太复杂,所以精简一些出现了zab与raft算法。zookeeper基于zab自主选举算法,MongoDB副本集基于raft算法,腾讯仿造mongodb使用MySQL实现tdsql等。

 节点之间两两相连,相互发起投票,投票方式按照一定会出现主的节点设计(奇数个、id等),因为投票的设计,节点越多,选举越困难,所以并不是越多越好,有个平衡点,比如5或者7.

这个图是不是很熟悉,实际上Redis集群、rocketmq集群就是使用这种方式进行failover的,只不过他们跟传统的副本集不一样,使用了分片+raft算法。

那么在设计跨数据中心的HA的时候,就需要2地3中心,把一个节点部署在一个数据中心,可以保证一个数据中心宕机,服务依然可用。

 

分片集群

分片集群设计有两种方式,分片的片是副本集,分片的片是主备。

分片集群

如果分片的片是副本集,那么副本集就提供failover能力,常见的有mongodb分片集群,mongos路由+configserver(副本集)+ 分片,每一个分片又是一个raft副本集(replicaSet)。实际上K8S创建部署计划也是创建RS(replicaSet)。

比如2个分片的分片集群,因为每个分片都是副本集,那么每个分片的副本集节点可以跨数据中心,实现2地3中心。理论上分片可以无限扩增,但是随着扩增越多,路由的查询写入的压力越大,这种架构设计也就是mongodb或者ES(也是分片)能存储很大数据量的原因,比如60亿一张“表”。

 

分片+主备

常见的有Redis集群,rocketmq集群,ES集群等,以Redis为例:

Redis的分片也是数据的分片,但是Redis主备failover由Redis的主节点投票决定,在多数据中心设计中,如果是2个数据中心,那么这个就没办法处理了 ,所以Redis一般是3主3从,5主5从等。奇数的节点就会在2个数据中心出现,其中节点多的一方挂掉,整个集群不可用,需要2地3中心支持。

连接集群

连接集群顾名思义:把2个或者多个集群数据相互复制,达到数据一致性的问题。

多次连接

以rocketmq为例,使用中间复制平台,将2个数据中心的rocketmq集群相互复制

此处仅画了一半,右边也会复制到左边

 通过sdk路由分发,实现双活集群,数据完全同步,如果其中一个数据中心挂了,那么业务没有任何影响,缺点也很明显,带宽占用极高,如果数据中心延迟高或者带宽不够,那么这个方法就行不通。

设计应用,也需要考虑,例如MQ消费的幂等去重等,避免出现多次消费;发送可以根据数据区的标记发送一边即可,当然消费亦可以,根据实际情况处理,是真正意义的双活设计。如果出现某个数据中心故障,切换发送和消费的标记,那么实现无缝迁移业务,甚至根据监控数据实现自动切换。

因为是连接集群,那么存储的时候需要考虑写入数据的id(唯一性)冲突的问题,建议数据打标写入。

  

数据存储文件复制

上面的设计可以进一步优化,比如使用中间件的特性,比如MySQL binlog,kafka的commit log index log等。通过中间件自身属性实现文件或者数据流的复制。

本质一样,实现区别而已。

 

分片大集群-数据允许丢失

如果对数据要求不高,允许丢失,比如缓存数据,可以使用分片大集群模式

数据完全分片,数据源可以同步,并定时写入redis,如果redis集群因为一边数据中心挂了,那么会丢失数据,等待写入,但是对业务无影响,至于sdk路由怎么设计,这个就要根据具体情况了,路由规则罢了。如果是注册中心这样的有本地缓存,且定时检查心跳,那么自动注册,即可无需复制

 数据没有复制,但是是分片集群,其中一个数据中心宕机,那么sdk会自动向另一个数据中心注册,且每个sdk有本地缓存,实现了无需切换的代价,且整个数据中心宕机,应用也挂了,亦不存在任何问题。

当然也可以不实现跨数据中心自动注册,丢掉一部分APP提供能力,等恢复后应用又可以自动恢复能力。

 

总结

笔者仅仅简单的介绍了跨数据中心的做法,方案等;实际上设计更加复杂,各种实际问题非常棘手,尤其是还有各种状态考虑,复制的稳定性,带宽等综合考虑就更复杂了。简单的sdk就会有多种设计,路由去重幂等等实现。具体还是需要根据实际场景设计。

开发逻辑向平台迁移

随着这些年docker等容器的兴起,开发逻辑向平台倾斜,以前开发是FATJar模式,变为agent,变为sidecar,变为serverless,实际上就是平台承担所有与业务无关的能力,专注业务,核心是定框子,在框子干活保证质量与效率。对于开发人员,很难接触系统实现逻辑了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/616641.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

阿里8年,肝到P7只剩这份笔记了,已助朋友拿到15个Offer....

时光飞逝,转眼间在阿里工作了8年,工作压力大,节奏快,但是从技术上确实得到了成长,尤其是当你维护与大促相关的系统的时候,熬到P7也费了不少心思 我的职业生涯开始和大多数测试人一样,刚开始接触…

Redis进阶:分布式锁问题

分布式锁问题 1. 分布式锁问题1.1 问题介绍1.2 解决方案1.2.1 分布式锁主流的实现方案1.2.2 使用Redis实现分布式锁1.2.3 分布式锁需要满足的四个条件 1.3 实现分布式锁 1. 分布式锁问题 1.1 问题介绍 单机单体中的锁机制在分布式集群系统中失效;单纯的Java API并…

Linux快速安装MySQL

文章目录 Linux上安装MySQL1. 安装MySQL1)上传MySQL安装包以及MySQL驱动jar包2)解压MySQL安装包3)卸载系统自带的mariadb4)安装MySQL依赖5)安装mysql-client6)安装mysql-server7)启动MySQL8&…

案例27:基于Java宠物领养系统开题报告设计

博主介绍:✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专…

性能测试之Docker监控

相信很多程序员在进行性能测试时常常会遇到一些问题,比如如何监控Docker容器的运行状态。这时候,Docker监控工具就派上了用场。 我曾经也遇到过这样的问题,不知道如何获取Docker容器的性能数据,直到我发现了Docker监控工具。使用…

干货分享 | TSMaster小功能之实时注释在图形中的使用技巧

今天给大家介绍TSMaster功能之实时注释在图形中的使用技巧,主要通过手动注释、自动化注释、实时注释在记录与回放中的运用等三方面来进行介绍。 一、实时注释的作用 在了解实时注释的使用技巧之前,我们先了解一下实时注释是什么以及它的作用。 实时注释…

算法修炼之筑基篇——筑基二层初期(解决最长回文子串问题,马拉车(manacher)算法模板)

✨博主:命运之光 🦄专栏:算法修炼之练气篇 🍓专栏:算法修炼之筑基篇 ✨博主的其他文章:点击进入博主的主页 前言:学习了算法修炼之练气篇想必各位蒟蒻们的基础已经非常的扎实了,下来…

SpringCloud服务注册中心

SpringCloud 服务注册中心 1.Eureka基础知识 什么是服务治理? Spring Cloud 封装了 Netflix 公司开发的 Eureka 模块来实现服务治理 在传统的rpc远程调用框架中,管理每个服务与服务之间依赖关系比较复杂,管理比较复杂,所以需要使用服务治理,管理服务与服务之间的依赖关系,…

数据库的增删改查(三)

1、查询 1.1、聚合查询 1.1.1、聚合函数 数据库提供了很多函数,其中就包括聚合函数,常见的聚合函数如下表 函数说明COUNT([IDDINCT] expr)返回查询到的数据的数量SUM([DISTINCT] expr)返回查询到的数据的总和,不是数字没有意义AVG([IDSTI…

一篇长文教你进行全方位的使用appium

随着移动应用的日益普及,移动应用的测试成为了软件开发的重要组成部分。Python,作为一种易于学习,功能强大的编程语言,特别适合进行这种测试。本文将详细介绍如何使用Python进行APP测试,并附带一个实例。 Python 和 Ap…

CVE漏洞复现-CVE-2021-2109 Weblogic Server远程代码执行

CVE-2021-2109 Weblogic Server远程代码执行 漏洞背景 2021年1月20日,Oracle官方发布了漏洞补丁,修了包括 CVE-2021-2109 Weblogic Server远程代码执行漏洞在内的多个高危严重漏洞。CVE-2021-2109 中,攻击者可构造恶意请求,造成J…

多媒体库SDL以及实时音视频库WebRTC中的多线程问题实战详解

目录 1、概述 2、开源跨平台多媒体库SDL介绍 3、开源音视频实时通信库WebRTC介绍 4、在国产化Linux桌面系统中遇到的SDL多线程问题 5、在给WebRTC新增外部音频插件库时遇到的多线程问题 6、最后 VC常用功能开发汇总(专栏文章列表,欢迎订阅&#xf…

【云原生】创建容器的方法

1)基于现有镜像的创建 先使用现有镜像创建容器 docker run 再进入容器进行内容更新 docker exec 最后提交成新的镜像 docker commit 2)基于模板创建 可以从本地容器导出模板文件 docker export 或者从网上下载现成的模板文件 http://openvz…

C++继承相关内容(二)

目录 一.拷贝构造函数 第一种情况:基类没有拷贝构造函数,派生类也没有拷贝构造函数 结果: 原因: 第二种情况:基类没有拷贝构造函数,派生类有拷贝构造函数 结果: 原因: 第三种情况…

【文生图系列】 Stable Diffusion v2复现教程

文章目录 xformersbug 记录 txt2imgdiffusers参考 基础环境承接Stable Diffusion v1, 详情请见我的博文【文生图系列】 Stable Diffusion v1复现教程。然后更新pytorch和torchvision的版本,因为要使用GPU和xformers,需要下载gpu版本的pytorch。再下载ope…

学习笔记之微服务(一)

一、了解微服务 1、服务架构演变 **单体架构:**所有业务功能都集中在一个项目中开发,打成一个包部署。 优点:架构简单、部署成本低 缺点:耦合度高 分布式架构:根据业务拆分系统功能,每个业务模块独立项…

微信小程序map 之个性化地图(日出日落主题)

微信小程序map 之个性化地图(日出日落主题) 个性化地图之根据日出日落时间动态变换地图主题个性化前的准备进入腾讯地址服务官网小程序开发html 代码. layer-style 编号为样式名称js代码. 注意的是,layer-style只能定义一次,所以值…

Yarn【常用命令】

1、yarn application 查看Application运行情况 1.1、列出所有Application yarn application -list 可以通过Web UI端来查看: 1.2、根据Application状态过滤: yarn application -list -appStates (所有状态: ALL 、 NEW 、 NEW…

Spring Cloud Alibaba 同时兼容dubbo与openfeign

一、前言 dubbo与springcloud都可以单独作为微服务治理框架在生产中进行使用,但使用过springcloud的同学大概了解到,springcloud生态的相关组件这些年已经逐步停更,这就导致在服务架构演进过程中的迭代断层,以至于一些新的技术组…

聚合/组合

谨慎使用继承的方式来进行扩展,优先使用聚合/组合的方式来实现。 Father类里有两个方法A和方法B,并且A调用了B。子类Son重写了方法B,这时候如果子类调用继承来的方法A,那么方法A调用的就不再是Father.B(),而是子类中的…