MySQL 是经典的关系型数据库管理系统,以其简单易用的特性在中小型业务系统中广受开发人员的喜爱。但是MySQL的架构也具有一定的局限性,在需要具备"隔离性"的业务,例如 SaaS 系统或微服务架构等对"数据隔离"及"资源隔离"有强需求的场景中,MySQL往往就表现的力不从心。此时,原生具备多租户能力又高度兼容 MySQL 语法的 MatrixOne,就成为开发者的理想选择。
在MySQL中实现多租户通常有两类方式:Shared Application Separate Database或Shared Application Shared Database。
实际生产业务中,这两种模式都存在一定挑战:
独立数据库模式:MySQL本身为单进程数据库,在一台数据库服务器中创建多个数据库实例消耗的资源相对较少,该模式下将每个租户都以独立数据库实例进行支撑,其优势为资源和数据的隔离度非常高,劣势是资源成本和运维难度都较大,当租户数量超过百个时,统一的升级等运维动作将会非常耗费时间。同时,由于使用不同的数据库实例,各实例间的数据共享也会变得不够灵活。
共享数据库模式:所有租户均在一个相同的数据库实例中,通常依靠分库分表、权限设计以及配合应用层代码区分租户逻辑。该模式的优势是仅使用一套数据库集群,资源成本和运维管理难度都较低,升级/扩容/应用改动都仅需要做一次即可完成全局更改,各租户间数据也可以灵活共享。劣势是数据和资源隔离程度较低,尤其容易出现某个租户负载突然大幅增加的时候,抢占其他租户的资源,导致整个系统性能严重下降。MySQL 在 8.0版本引入了用于资源管理的Resource Group特性,可通过资源组的方式修改线程的优先级以及所能使用的资源,来指定不同的线程使用特定的资源,但这个能力只能简单控制CPU资源,开发者需要通过调控线程优先级和绑定CPU核来实现对应线程任务的优先级调度,操作灵活度有限,不足以解决"共享数据库模式"下各租户资源抢占的问题。
而采用"单一集群多租户"方式的 MatrixOne 就可以优雅的解决上述两种模式存在的问题。MatrixOne 在集群级别下可以创建和管理多个数据和用户权限体系完全隔离的租户(Account),在这个设计中,租户是一个逻辑概念,作为资源分配和数据库管理的单位。MatrixOne 的多租户模式能够为不同的租户提供独立的数据库实例,并采用逻辑隔离的方式确保各租户数据的安全性和独立性,有效防止数据泄露和篡改的风险。这种多租户设计既节省了部署和运维多套数据业务系统的成本,又能利用租户间的硬件资源共享最大限度的节约机器成本。
MatrixOne在架构上实现了三个独立的层级,每个层级都有自己的对象单元和分工。不同类型的节点可以自由伸缩,不受到其他层的制约。
这三个层级是:
计算层 :以计算节点 Compute Node(简称 CN)为单位,实现了计算和事务处理的 Serverless 化,具备自己的缓存,可以任意重启和扩缩容。
事务层 :以数据库节点 Transaction Node(简称 TN )和日志节点 Log Service 为单位,提供完整的日志服务和元数据信息,内置 Logtail 用于保存最近的数据。
存储层 :全量数据保存在对象存储中,以 S3 为代表,实现了低成本的无限伸缩存储方式。统一的文件操作服务 File Service 实现了不同节点对底层存储的无感知操作。
基于上图所述的架构,MatrixOne 在分布式集群中采用如下图所示的 Proxy 模块和 CN 资源组技术架构实现了多租户资源隔离:
用户访问MatrixOne 时,连接会先经过 Proxy 模块,Proxy 会根据 CN 的租户标签信息将连接转发到对应 CN 资源组上的某个 CN 上,根据负载均衡的原则选择负载最轻的 CN。在 MatrixOne 集群架构中,CN 是以容器化部署的,因此 CN 之间具有隔离性。一个租户使用的 CN 资源组是一组打上该租户标签的 CN。如果资源不足,需要进行扩展,可以通过水平扩展该 CN 资源组来满足需求,而不会抢占其他 CN 资源组的资源。但上述的实现方式仅适用于MatrixOne K8s集群部署或云原生的MatrixOne Cloud环境,单机部署时由于只有一个CN节点,多租户就仅有"数据隔离"能力,而无法实现"资源隔离"和"弹性扩缩"效果了。
多租户使用示例
在MatrixOne中多租户的使用非常简便,相关语法介绍如下:
创建租户
CREATE ACCOUNT [IF NOT EXISTS] ACCOUNT_NAME ADMIN_NAME [=] 'admin_name' IDENTIFIED BY 'auth_string' [COMMENT 'comment_string'];
-- ADMIN_NAME子句用于指定该租户默认的帐号名和密码
租户操作示例
-- 创建租户account_app1, 租户管理员账号为admin_app1。仅系统租户管理员 root 用户可以执行
create account account_app1 admin_name 'admin_app1' identified by 'app123';
-- 修改租户的密码,集群管理员 root 用户可以修改它所创建的租户的密码,租户本身可以修改自己的密码
alter account account_app1 admin_name 'admin_app1' identified by 'MatrixOne_1234@';
-- 修改租户状态,仅系统租户管理员 root 用户可以执行,租户状态可以为暂停(SUSPEND)、恢复(OPEN)和限制(RESTRICTED),对租户启用了 RESTRICTED 状态以后,该租户只能对数据库进行 SHOW/DELETE/SELECT/USE/SET 操作,其他操作将不可进行
alter account account_app1 suspend;
-- 删除租户,仅系统租户管理员root可以删除租户,删除租户时,会删除租户账号下的所有数据,且无法恢复,务必谨慎操作
drop account account_app1;
租户登陆示例
以使用 mysql client 为例,在访问MatrixOne时,完整的语法为:
mysql -h host -P port -u accountname:username:role -p'password'
其中,accountname即租户名称,当不显式指定时,默认使用"sys"系统租户。username为租户账号,可使用"root"或其他租户创建时指定的"租户管理员"账号,也可使用后期通过管理员创建的其他账号。role用于显式指定所用账号拥有的某一角色,注意当指定角色登录时,租户名不能省略。租户登陆示例:
mysql -h 127.0.0.1 -u account_app1:admin_app1 -P 6001 -p
租户数据共享
除了确保租户之间的数据和负载隔离外,MatrixOne 同样提供了一种允许租户间数据互通的机制,即发布和订阅能力,这一机制可用于解决数据同步和大量数据分发等场景中的互通问题。以开箱即用的MatrixOne Cloud为例,在MatrixOne Cloud中创建的每个实例都是一个独立的租户,假设我们需要将“实例1”中的数据通过“发布订阅模式”共享给“实例2”,操作语句示例如下:
-- 在实例1中创建库表和导入测试数据
create database pub_db;
CREATE TABLE pub_db.customer (
customer_id INT,
customer_name VARCHAR(255)
);
insert into pub_db.customer values(1001,'matrixone');
-- 在实例1中将数据库pub_db发布给指定实例,在MO Cloud中实例名可在“通过第三方工具连接”处获取
create publication pub_moc database pub_db account `62915dd9_d454_4b02_be16_0741d94b62cc`;
-- 在实例2中对源实例发布的数据库执行订阅命令,源实例的实例名仍可在“通过第三方工具连接”处获取
create database sub_db from `0b6d35cc_11ab_4da5_a5c5_c4cc09917c11` publication pub_moc;
-- 在实例2中查看所订阅数据库内的表数据,所订阅数据为只读,且会随着源实例中的数据变化实时变化
select * from sub_db.customer;