近年来,在金融科技的推动下,互联网金融业务蓬勃发展,金融行业数据处理呈现出新的特征,如数据量大、并发量高、处理性能高、类型繁多等。这就对海量数据的存储、并发访问及实时分析能力提出了新的要求。
另一方面来讲,“事后”分析已经不能满足快速的市场需求和业务变化,需要对海量客户行为数据的实时洞察提高营销精准度,如实时推荐等,并持续监测交易行为提高风险预警能力,如实时风控、反欺诈等。传统技术架构下的数据分析业务,其数据时效性面临着前所未有的挑战。
HTAP(混合事务/分析处理),是Gartner提出的一种新兴的应用框架,旨在打破事务处理和分析之间“壁垒”,在同一个数据库中,提供更高效的“实时业务”决策。
本次最佳实践,我们将为您展开讲解,如何利用巨杉分布式数据库SequoiaDB,实现HTAP混合事务/分析处理,实现OLTP与OLAP及资源平衡。
Gartner最新研究报告显示,操作型数据库(ODBMS),需要同时支持传统事务处理、分布式数据处理、事件/动态数据处理、交易与分析混合处理(增强型事务处理)等多种用例场景。报告中特别提到,将原有的操作和分析融合处理(HTAP)用例更改为增强型事务处理及可编程的HTAP功能,即:在维持高服务等级(SLA)事务处理的同时,嵌入分析处理(包括AI/ML)能力。
为了支撑大规模实时分析应用(如风控,实时推荐,实时数据看板,报表等),需要数据库能够同时具备OLTP和OLAP的混合负载能力。其中OLTP负载能力承载在线业务,而OLAP负载能力则直接对数据进行实时分析,以期大幅缩短决策周期,甚至提供跨业务线的综合实时分析能力。
目前在业内,实现HTAP混合负载,主要有三种技术方案:
• 单一系统同时承载混合负载(如DB2、Oracle、MySQL等)
• 使用不同系统组合+数据同步技术(如ETL、GoldenGate、CDC等)
• 同一存储不同计算引擎(如HBase+Spark等)
这些技术实现HTAP混合负载,无论何种方案,均存在一定的缺陷和短板。
数据共享难题
传统技术使用Oracle、MySQL、DB2、Informix等数据库构建业务,分离部署,数据分散存储。要实现HTAP混合负载,需要构建多套数据库,并基于一系列的数据复制技术,或基于ETL进行数据加工、转换。这样一来,不但架构的复杂性大大增加,数据传输消耗了大量的网络带宽进行数据传输。即便如此,这种跨库实现的混合负载,数据的延迟得不到有效解决。
例如一个关联查询,往往需要在不同机构实现跨库数据查询。甚至,有些数据已经使用磁带落库的方式永久封存,数据远远没有发挥出其应有价值。如何能够打通各个业务系统,把数据盘活,解决复杂的数据复制,让数据能够给业务带来新的增长点,是现在面临比较棘手的问题。
图1 OGG+Kafka实现数据复制
性能不能兼顾
事实上,传统数据库也能够实现混合负载的需求,但往往要在功能或性能上做出牺牲。对于交易场景,关注低延迟、高并发的数据增删改查,同时对ACID功能有严格的要求。这种场景一般需要使用行式存储,牺牲了海量数据访问能力,如Oracle、MySQL等。对于分析场景,主要是是大量数据扫描,甚至做聚合,对并发和延迟要求并不高,但更加关注吞吐量、容量、弹性伸缩能力,更倾向于采用列式存储,因此不得不牺牲实时更新、关联查询能力,如HBase、Oracle In-Memory等。因此,以往的HTAP混合负载技术,很难做到对交易能力和分析能力的兼顾。
扩展性难题
核心系统普遍使用“传统数据库+小型机+集中式存储”架构,扩容难度大,扩容成本也很高。从运维来说,为了保证在线交易数据库的容量,只能不断把旧的生产数据卸载到历史库,甚至封存在磁带库中,日常的数据管理工作给运维人员带来不小负担。对于HTAP业务系统,一次扩容也必然要涉及到源端和目标端,工作量巨大。另一方面,分析业务往往需要横跨在线、历史数据,甚至多业务线的数据,更需要可扩展架构,来满足不断变化的业务迭代,以及不断提升的容量需求和性能要求。
开发接口单一
以往的混合负载技术,其提供的SQL接口比较单一,一般只能提供一种SQL语法。另外,随着业务量的爆发式增长及无纸化的推进,数据库不仅仅需要保存文本数据,更多需要保存音频、影像类大对象数据。目前的技术架构,无法适应目前互联网多样化的应用、开发需求。
综上所述,以往的HTAP混合负载技术,存在明显的短板和不足。在这种条件下,具有支持多节点部署、多引擎、高扩展、高冗余等特性的分布式数据库架构,逐渐成为了HTAP技术的首选。
一个HTAP数据库要实现混合负载,既要能满足上述多种技术要求,也需要能够保证不同业务之间的负载隔离。
巨杉数据库SequoiaDB,采用存算分离架构,通过统一的分布式数据库底座,融合不同的计算引擎,很好地解决了传统技术实现HTAP混合负载的各种难题:
• 轻松地在一个数据库内,提供HTAP支持,无需分库及跨库复制;
• 支持多种计算引擎,如MySQL、PostgreSQL、SparkSQL等;
• 支持跨引擎ACID,兼容标准SQL;
• 支持多种形式的负载隔离;
• 支持弹性扩展、多活容灾。
在SequoiaDB数据库中,用户可以利用复制组的多副本特性,在节点和会话等多个级别设定读写分离策略,使得不同类型的应用(联机交易、联机分析、数据中台等),采用各自的开发接口(例如 MySQL、PostgreSQL、SparkSQL等),进行数据的实时访问,且之间不产生负载干扰。
图2 SequoiaDB三副本实现HTAP
图3 巨杉数据库分布式架构
多副本机制:
• 数据分散存储在不同的数据组中;
• 主副本提供读、写服务,备副本提供只读服务;
数据组内,有多个副本,由数据库内部的一致性算法实现数据同步。
图4 数据一致性同步
在数据组内,设置读写访问优先级策略:
• 将MySQL、PostgreSQL引擎指向读写副本,实现高并发的数据增删查改,来承载联机交易业务;
• 将Spark引擎指向只读副本,实现数据分析、高并发查询,来承载联机分析业务;
• 为了更细化地实现隔离,还可以使SQL引擎连接到具体的某个副本上;
• 各个副本之间,没有任何负载干扰,完全实现了HTAP混合负载下的负载隔离。
图5 HTAP负载隔离
分布式数据库支持多种SQL引擎,常见的有:
1、MySQL引擎
2、PostgreSQL引擎
3、Spark引擎
图6 三种解析器使用特征
各类引擎的特点如下:
SQL引擎 |
描述 |
适用场景 |
MySQL 引擎 |
适合精准查询、业务数据写入、柜面查询等场景 增删查改操作和普通MySQL完全一致 和MySQL语法兼容度达到100% |
OLTP |
PostgreSQL 引擎 |
以复杂SQL语法和强大的SQL编程能力见长 支持增删查改等功能,和普通PostgreSQL使用完全一致 采用外部表的方式将数据存储在分布式数据库中 |
OLTP OLAP |
Spark 引擎 |
可扩展的数据分析组件,集成了原生的内存计算 适合报表分析、大表关联查询等 提供友好、高性能的关联查询 支持标准SQL、支持JDBC访问、支持Python等接口 通过使用 Spark连接组件,来访问分布式数据库存储引擎 |
OLAP |
本文的示例中,我们选择MySQL作为OLTP引擎,SparkSQL作为OLAP分析引擎。
计算引擎可实现集群部署。MySQL和SparkSQL实例均可部署在多台服务器,对连接请求实现均衡的同时,避免了单点故障隐患;
分布式存储引擎。SequoiaDB数据库分布式存储引擎中,数据节点分布在多台服务器上,这样能够充分利用服务器的数据存储和计算能力;
网络隔离。在Spark计算引擎读写繁忙的情况下,会产生较大的网络传输从而侵占MySQL实例在线事务处理的带宽资源,因此,生产环境下建议为Spark和MySQL实例配置独立的网卡。
本次最佳实践案例的实验环境规划如下:
服务器规划:
IP地址 |
主机名 |
192.168.100.201 |
sdb01 |
192.168.100.202 |
sdb02 |
192.168.100.203 |
sdb03 |
组件部署:
节点 |
sdb01 |
sdb02 |
sdb03 |
SQL引擎 |
MySQL实例 |
PostgreSQL实例 |
SparkSQL实例 |
协调节点 |
协调节点 |
协调节点 |
协调节点 |
编目节点 |
编目节点(主) |
编目节点 |
编目节点 |
数据节点 (副本) |
数据组1-主副本 |
数据组1-备副本 |
数据组1-备副本 |
数据组2-主副本 |
数据组2-备副本 |
数据组2-备副本 |
|
数据组3-主副本 |
数据组3-备副本 |
数据组3-备副本 |
注:为了第4章节演示方便,本次将数据的主副本均设置到sdb01服务器。
节点 |
sdb01 |
sdb02 |
sdb03 |
SQL引擎 |
MySQL实例 |
PG实例 |
Spark实例 |
数据节点 首选连接 |
首选主副本 |
首选主副本 |
首选备副本 |
服务器配置:
规格 |
|
服务器数量 |
3台 |
CPU |
8 核 |
内存 |
16GB |
磁盘 |
100GB * 3 |
操作系统 |
Centos 7.4 |
软件版本:
软件 |
版本 |
SequoiaDB |
3.4 |
MySQL |
5.7.25 |
Spark |
2.3.3 |
演示场景:
1、 MySQL、PostgreSQL、SparkSQL跨引擎数据操作及查询
在MySQL中,创建bills.orders表并插入数据,进行数据的增删改查操作;
在PostgreSQL、SparkSQL中查询,并验证数据正确性;
2、 跨引擎Join查询
在MySQL中再创建一张表bills.customers;
在SparkSQL中进行bills.orders、bills.customers的表关联查询;
查看各个数据副本的访问统计,来验证HTAP负载隔离。
1、在MySQL实例中创建表的步骤如下:
登陆MySQL实例
mysql -h 127.0.0.1 -P 3306 -uroot -proot
创建bills数据库
create database bills;
use bills;
创建 bills.orders表
create table bills.orders (
order_id int,
customer_id int,
p_date date,
location varchar(100) ,
primary key (order_id) );
注:在SequoiaDB数据库中, 使用MySQL引擎建表,默认即使用SequoiaDB分布式存储引擎。
2、在PostgreSQL实例中创建表
在PostgreSQL客户端创建外部表bills.orders,并映射到数据库引擎中的orders表。
//登陆PostgreSQL客户端
/opt/sequoiasql/postgresql/bin/psql -p 5432 bills
//加载SequoiaDB连接驱动
create extension sdb_fdw;
//配置与SequoiaDB连接参数
create server sdb_server foreign data wrapper sdb_fdw options(address '192.168.100.202', service '11810', user 'sdbUserName', password 'sdbPassword', preferedinstance '1,M', transaction 'off');
//创建orders表
create foreign table orders (
order_id int,
customer_id int,
p_date date,
location varchar(100)
) server sdb_server options ( collectionspace 'bills', collection 'orders', decimal 'on' );
3.SparkSQL实例中创建表
在SparkSQL客户端创建外部表bills.orders,并映射到数据库引擎中的orders表。
$ 登陆spark beeline客户端
/opt/spark-2.3.3-bin-hadoop2.7/bin/beeline -u 'jdbc:hive2://192.168.100.203:10000'
//创建orders表
create table bills.orders (
order_id int,
customer_id int,
p_date date,
location varchar(100) )
USING com.sequoiadb.spark OPTIONS ( host '192.168.100.203:11810', collectionspace 'bills', collection 'orders',preferredinstance '2,3,S') ;
select * from bills.orders;
说明Spark中orders表创建成功。
Note:
1、Preferedinstance选项:会话读操作优先选择的策略,取值列表:"M"、"S"、"A"、1-255。可以使用数组指定多个取值。"M":可读写实例(主实例) "S":只读实例(备实例) "A":任意实例 1-255:通过 instanceid 指定实例 ID 的实例。
2、Instanceid,是一个数据组内,各个副本的编号,默认是0。设置该参数后,可以SQL实例中建表时,指定其访问的首选副本。
在本文中,将SQL实例的访问策略设置为:MySQL、PostgreSQL优先连接主副本,SparkSQL优先连接备副本,从而实现HTAP负载隔离。因此,还需要对所有数据组的各个副本设置其instanceid。
//本例中将主副本的instanceid设置为1,两个备副本设置为2、3.
//登陆SequoiaDB存储引擎
$ sdb
db = new Sdb( "192.168.100.201", 11810 )
db.updateConf( { instanceid:1 }, { GroupName:"group1", NodeName:"sdb01:11830" } );
db.updateConf( { instanceid:2 }, { GroupName:"group1", NodeName:"sdb02:11830" } );
db.updateConf( { instanceid:3 }, { GroupName:"group1", NodeName:"sdb03:11830" } );
//以group1为例,其他数据组操作类似。
登陆MySQL,向bills.orders表中插入4条测试数据:
insert into bills.orders values(10001,1,"2017-06-01","Beijing");
insert into bills.orders values(10002,2,"2018-06-01","Shanghai");
insert into bills.orders values(10003,3,"2019-06-01","Guangzhou");
insert into bills.orders values(10004,4,"2020-06-01","Shenzhen");
查看数据:
select * from bills.orders;
在MySQL中,更新bills.orders中一条记录,并查询:
update bills.orders set location="Nanjing" where order_id=10001;
select * from bills.orders;
删除bills.orders表中一条记录(order_id=100002),并查询:
delete from bills.orders where order_id=10002;
select * from bills.orders;
登陆PostgreSQL客户端,并查询orders表数据:
/opt/sequoiasql/postgresql/bin/psql -p 5432 bills
//查询orders表数据:
select * from orders;
这说明在MySQL中的数据,在PostgreSQL中是共享的。
登陆SparkSQL客户端,并查询orders表数据:
/opt/spark-2.3.3-bin-hadoop2.7/bin/beeline -u 'jdbc:hive2://192.168.100.203:10000'
//查询orders表数据:
select * from bills.orders;
这说明,MySQL中所操作的数据,在Spark SQL中是共享的。
从数据的增、删、改、查操作可以看出,数据在MySQL和PostgreSQL、SparkSQL中是完全共享的。
1. 创建第二张表bills.customers
MySQL中创建customers表结构:
create table bills.customers (
customer_id int,
customer_name varchar(100) ,
gender char(1),
birth_date date,
primary key (customer_id) );
Spark中创建customers表结构
create table bills.customers (
customer_id int,
customer_name varchar(100) ,
gender char(1),
birth_date date )
USING com.sequoiadb.spark OPTIONS ( host '192.168.100.203:11810', collectionspace 'bills', collection 'customers',preferredinstance '2,3,S') ;
2. 向2个表分别插入测试数据
登陆MySQL实例,向orders、customers表各插入50000条数据
//为便于插入,创建存储过程proc_insert
drop procedure if exists proc_insert;
delimiter ;;
create procedure proc_insert()
begin
declare i bigint default 1;
while i<50001
do
insert into bills.orders values (i*177,i,"2018-05-09",'Beijing');
insert into bills.customers values (i,'Tom','F',"2018-05-09");
set i=i+1;
end while ;
commit;
select i as "Inserted Rows of orders: ", i as " Inserted Rows customers: ";
end;;
//清空现有数据,调用存储过程,插入数据
delete from bills.orders;
call proc_insert();;
//数据查询
select count(*) from bills.orders;
select count(*) from bills.customers;
至此,数据库中已存在2张表,orders表、customer表,分别有50000条数据。
3. 在Spark中进行JOIN查询
select count(*)
from bills.orders o inner join bills.customers c
on o.customer_id=c.customer_id ;
将上章节的JOIN查询连续运行10次,使用SequoiaDB的节点监控工具sdbtop,来观察各个副本的读写次数统计。
(备注:1、以数据组group1:11830为例,其他数据组效果相同;2、为了便于展示,此时重启了数据节点,将统计清零。)
sdb01上的主副本:无任何数据读取。
sdb02上的备副本:产生150472次数据读取。
sdb03上的备副本:产生150569次数据读取。
从结果可以看出:SequoiaDB的HTAP混合负载,已经通过多副本策略,实现了负载隔离效果:
• MySQL对主副本进行写入;
• SparkSQL实例对备副本进行只读查询;
• OLTP、OLAP的负载运行在不同服务器上,互相不产生干扰。
在本文中,我们介绍了巨杉数据库SequoiaDB的HTAP最佳实践,包括HTAP混合事务/分析处理的技术原理、负载隔离策略、操作步骤等。
HTAP混合负载,意味着数据库可以同时承载在线交易业务和统计分析业务。分布式数据库,利用计算-存储分离的架构特点和访问隔离功能,结合了MySQL、PostgreSQL引擎和Spark计算引擎,使复杂的联机分析处理(OLAP)与联机交易(OLTP)处理在一个数据库中得以实现。
分布式数据库提供了多种级别的隔离策略,来实现读写分离,使不同的业务场景访问不同类型的数据副本,使得业务访问性能得到了提升。