需求起源
SelectDB 设计多计算集群架构初衷主要源于两类典型的使用场景:
- 写入与读取隔离:传统数仓架构中,数据的写入和读取在同一个计算集群,当遇到业务写入高峰期或突增的写入压力时,容易因资源相互抢占影响查询服务的性能和稳定性。如果能引入多个计算集群,通过独立的计算集群分别进行写入、读取操作,即使在写入压力非常高时,也可放心执行计算任务,无需担心影响到服务的稳定性。
- 在线业务和离线业务隔离:大量数据分析场景会使用相同的数据支撑多个业务,比如某业务使用一份数据支持面向 C 端用户的数据查询,另一个业务需要使用相同数据支持企业内部用户的运营分析等,这两个业务对于服务的延时、可用性要求完全不同。传统架构通常会把数据冗余存储到不同系统中,用于满足不同业务的需求,但这会带来冗余数据的存储成本和多套系统的维护成本。如果支持多计算集群架构,可基于同一份数据拷贝,并使用独立隔离的计算资源分别满足在线和离线业务需求,便能为用户带来可观的成本节省和简单的运维体验。
SelectDB Cloud 是基于 Apache Doris 研发的全托管实时数据仓库服务,采用全新的云原生存算分离架构。当计算层与存储层进行了分离设计后,计算层由于没有了数据状态,可支持极其灵活快速的弹性伸缩;而存储层由于和计算解耦,可以极为方便的供多个计算资源进行共享访问。因此,我们在 SelectDB 中引入多计算集群能力,通过数据仓库架构上的创新来更好地满足用户需求。
初识 SelectDB 多集群
在 SelectDB 的架构设计中,一个仓库实例可包含多个集群,类似分布式系统中的计算队列和计算组。数据持久化在底层的共享存储中,多个集群均可共享访问。每个集群本身即为一套分布式系统,包含一个或多个 BE 节点。由于存算分离架构中远程存储访问速度较慢,我们在计算节点本地引入了缓存,以加速数据访问。
例如下面架构图中,仓库 1 中包含集群 1、集群 2、集群 3,它们均可访问存储在共享存储中的数据。
对于多集群的使用方式,用户连接 SelectDB 仓库实例后,可通过命令切换使用不同的计算集群。一个使用多计算集群进行读写分离的样例如下:
通过 MySQL Client 连接 SelectDB,使用集群 cluster_1 进行数据库、表的建立。
# 切换使用计算集群 cluster_1 USE @cluster_1; # 创建 database、table CREATE DATABASE test_db; USE test_db; CREATE TABLE test_table ( k1 TINYINT, k2 DECIMAL(10, 2) DEFAULT "10.05", k3 CHAR(10) COMMENT "string column", k4 INT NOT NULL DEFAULT "1" COMMENT "int column" ) COMMENT "my first table" DISTRIBUTED BY HASH(k1) BUCKETS 16;
通过 Stream Load 方式,使用集群 cluster_2 写入样例数据。
curl --location-trusted -u admin:admin_123 -H "cloud_cluster:cluster_2" -H "label:123" -H "column_separator:," -T data.csv http://host:port/api/test_db/test_table/_stream_load
其中 data.csv 中的样例数据如下:
1,0.14,a1,20 2,1.04,b2,21 3,3.14,c3,22 4,4.35,d4,23
通过 MySQL Client 连接 SelectDB,使用集群 cluster_3 进行数据查询:
# 切换使用计算集群 cluster_3 USE @cluster_3; # 进行查询访问 SELECT * FROM test_table;
多集群的核心设计
在云原生存算分离架构下,多计算集群的实现从技术方案上看似乎并不存在过多难题。但从产品的角度而言,具备成熟易用的多计算集群能力且能运用于用户实际业务场景中,还有较多核心要点需要深度设计。 下面,我们对其中部分关键点进行介绍。
如何保证强一致的数据共享?
存算分离后,数据存储在共享存储中,可以供多个集群访问。在一个集群写入完成后,另一个集群是否能够立即访问到数据? 如果不能,将会存在一定的数据延迟,对很多实时性要求高的业务场景来说,这种方案难以接受。
为了达到数据的强一致访问,SelectDB 不仅实现了数据的共享化,也进行了深度重构,实现元数据的共享化:当数据通过其中一个集群写入共享存储后,会先更新共享的元数据,再返回数据写入结果。当其他集群进行数据访问时,可通过访问共享的元数据中心获取最新的数据信息,从而做到强一致的数据共享。这意味着通过任一个集群写入 SelectDB 中的数据,一旦写入成功,其他集群立即可见。
如何实现数据的多写多读?
基于共享存储,数据的多读是比较容易实现的,但写入是否只能由其中一个集群进行?如果只能通过其中一个集群写入,那该集群是事先人工确定、出问题时人工变更所有写入作业,还是引入分布式锁在多集群之间进行协调、以决定哪个集群来负责写入?
更麻烦的是,当原写入集群处于假死状态,可能出现多个集群尝试去写入的冲突情况,解决这些问题会导致数据仓库的架构复杂度大幅增加。因此关系型数据库在探索了很多年后,大量系统仍采用一写多读的架构。
SelectDB 结合数仓场景的特点,进行了深度思考设计,可实现数据的多写多读,以简化用户的运维过程、降低系统复杂度。具体而言,数仓场景通过采用小批量、多并发的写入方式,来达到写入的高吞吐,数据延迟达到秒级即可满足大多数用户的需求,可以看到数仓的写入事务并发不高,并无关系型数据库每秒数十万的事务并发需求。因此 SelectDB 可以基于数据的 MVCC 多版本机制,借助共享的元数据中心进行事务协调,数据先提交多个集群进行转化处理,然后在更新元数据阶段(生效数据过程)进行分布式协调,先获取到锁的集群写入成功,其他集群则进行重试。由于数据写入的开销主要在转化处理过程,基于这样的分布式协调机制和乐观锁设计,实现多读多写能力的同时,也可利用多集群进一步提升并发写入吞吐。
如何实现灵活可控的缓存能力?
存算分离架构通常采用对象存储或 HDFS 类系统作为远端共享存储,其单次 IO 请求的访问性能较差,相比本地存储性能下降数十倍。如何保障存算分离架构中计算集群的查询性能?进一步的,当采用多集群支持读写分离、在离线隔离场景时,如何保证多集群的查询性能呢?
SelectDB 通过提供精心设计的缓存管理机制,可自动化保障存算分离架构的查询性能,也可按需满足用户灵活多变的调优需求:
- 对于单个计算集群,SelectDB 默认会根据 LRU 策略进行数据缓存,当缓存大小足够存储全部热数据时,即可保障存算分离类系统的性能追平存算一体类系统,由于本地缓存的单副本设计、远端存储的低廉价格,存算分离架构的存储成本要大幅低于存储一体架构。SelectDB 同时提供了手动的缓存控制策略,可通过手动策略保证某些表的数据优先存储于缓存中。此外,当集群进行弹性伸缩时,SelectDB 会自动基于统计信息,提前进行缓存的预热或迁移,以保障变更过程中查询服务平稳。
- 对于多个计算集群,SelectDB 提供了提供了跨集群的缓存同步能力,可同步已有集群的缓存数据到其他集群,从而加速查询性能,并且支持分区粒度的缓存同步控制能力。每个计算集群的缓存是独立的,用户可根据需要按需控制缓存大小。
如何进行权限控制与资源隔离?
一个仓库中的多个计算集群之间,由于计算资源互相独立,因此计算集群间完全隔离。然而,当仓库下有多个计算集群可用时,如何避免用户误用集群,导致业务间的互相干扰?另外,由于存储资源共享,其带宽和 QPS 能力有限,如何保障一个集群对共享存储的访问不干扰其他的集群?
SelectDB 提供完整的权限控制与资源隔离的方案,来保障多计算集群架构有条不紊的运行:
- 对于计算集群的使用,SelectDB 提供一套简单易用的权限机制,集群支持类似库表的权限分配机制,只有给用户分配了某集群的权限,用户才可以使用该集群,从而避免集群误用情况。
- 对于存储资源的访问,SelectDB 支持按照集群规格,进行存储带宽和 IOPS 的限流控制,当超过限速后存储访问请求将进行排队,以避免多个集群之间互相干扰。
解锁更多使用场景
多计算集群架构的最初设计目标主要是为了满足读写隔离、在离线业务隔离等场景应用。SelectDB 的多计算集群方案上线后,有近半用户使用过多计算集群,我们意外发现多计算集群的应用潜力正在持续延伸:
- 弹性临时集群:在实际使用过程中,考虑业务隔离性,用户经常需要一个集群用于临时性业务,例如管理员保留一个隔离的测试集群用于日常访问、新功能正式发布前建立完全仿真的集群进行测试验证、月底或临时性的数据处理任务通过独立的集群进行等。为更好的满足此类需求,SelectDB 也提供了一系列配套能力,如同一个仓库同时支持包月和按量集群的混合计费模式、按量集群支持通过停止闲置计算资源来降低成本等。
- 跨可用区容灾:当前部署架构中,元数据中心、共享存储已支持跨可用区容灾,用户完全可以通过把多集群放置在不同可用区中,来完成全链路的跨可用区容灾。由于请求的处理过程主要在一个集群内部完成,跨可用区的访问仅在少量元数据获取过程,这种方案对查询性能也基本无影响。当某个可用区出现故障时,可通过一条命令,快速把业务切换到其他可用区。
- 集群切换式变更:当用户需要对集群进行某些变更操作时,可通过双集群切换方式进行平滑变更。比如对集群缓存资源进行缩容场景,由于目前集群弹性功能不支持缓存缩容,用户可通过新建低缓存容量的集群替换老集群。另外,后续我们可支持双集群切换来进行 SelectDB 大版本的平滑升级,当升级过程中发现问题时可随时安全回滚,保障大版本升级的稳定性,这也是一个极为重要的应用场景。
设计自省
在线上运营过程中,我们也在持续收集用户使用反馈、观察用户使用卡点,其中有两点设计引起了我们的反思,并正在进行设计上的优化重构:
- 集群命名设计:对于大量云上用户,已经建立实例和集群的专有概念,集群是用户购买在云控制台上购买的最小单元,在 MongoDB、Elasticsearch 等产品中,集群通常等价于实例。而在 SelectDB 的架构设计中,仓库或实例是购买的最小单元,集群是仓库内部的一组计算资源。这里概念设计上的不一致,给不少用户带来了理解上的麻烦。SelectDB 目前正在逐步调整系统架构中的概念,逐步把“计算集群”引导为“计算队列”、“计算组”等更贴切的概念。
- 默认权限策略:为避免集群误用导致多集群之间互相干扰,SelectDB 提供了多集群的权限控制能力,默认普通用户没有集群使用权限,需分配权限后方可使用。此类设计给新用户快速上手带来了较大门槛,不少用户在刚开始使用时会发现无法查询,也增加了仅仅使用单集群时的使用成本。SelectDB 目前正在思考重新设计集群权限部分,默认情况下用户拥有所有集群的使用权限,而把多集群的权限控制作为高阶功能,交给用户按需开启使用。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。