数据仓库架构(一)数仓产品ADB与DWS

【摘要】

业务使用数据仓库产品:阿里云ADB后转为华为云DWS,这两种产品都是数据仓库,有什么区别,迁移该注意什么。

【背景】

某公司主从事汽车行业信息化综合服务,有ERP运营管理软件、BI智能分析、移动互联网APP和微信应用服务、云服务平台和数据服务等。从阿里云迁移至华为云,云上使用服务包括ECS,CCE,RDS,MQ,Redis,LTS,DWS,CSS等。

主要关注其中数据仓库产品DWS的迁移过程,使用DWS的是一个基于大数据的业务,该公司是典型的“大中台+小前台”模式,调用集团中台的BI报表。报表工具用一个组件叫做“哪吒“(财税财务报表自动生成工具),在此基础上做了二开,该工具接入阿里的ADB数仓及大数据Hive数据库。ADB是一个分布式、高可用的数仓产品,对应的数仓产品为华为云DWS。

【问题描述】

  1. 是否可以不做改动直接切换?阿里云ADB和华为云DWS的区别
  2. 如果不用数仓,高性能云数据库是否可以替代?数仓和云数据库的区别
  3. 业务侧工具哪吒开源版本适配多个数据库,但是存在二开改造,改造后只支持mysql数据库和hive数据库,联系不到原开发团队,也就无法确定二开做了哪些改动,是否可以再改回去;
  4. SQL语法可能有兼容问题;

【过程与结果】

【核心问题】

ADB和DWS都是基于国外的结构化数据库研发出来的,但是ADB为Mysql内核,DWS为pg内核

【数据仓库和数据库的关系】

Mysql和postgresql都是常见的结构化数据库,大多数企业软件都是用数据库或数据库集群,随着云计算的推广,可能会选择云数据库,不再本地安装和运维;近几年XC的风头正劲,所以云上的国产化数据库也使用越来越多,但是不管是在哪里安装的,区别只在于接入和适配,对于实际使用没有太大的影响,因为结构化数据库是类似的,一般是行存储,适合做事务处理,数据高度标准化,连续写入。

数据仓库是专为了大数据量复杂分析而设计的,数据仓库相当于一个集成化数据管理的平台,从多个数据源抽取有价值的数据,在仓库内转换和流动,并提供给BI等分析工具来输出干货。数仓不适合连续写入的场景,往往是一次写入多次读取,所以是批处理写入;数仓使用列存储,有的数仓设计支持行列混合存储,但还是以列存储为主,这是为了集群式分布式并行计算的优化,便于实现告诉查询和低开销访问。

其实可以这么理解:数仓改变的是存储和读取的方式,为了性能做了集群调度,但是并不改变数据库的基础架构,也不改变sql语言的语法规则,甚至可以看作是多个结构化数据库的集合,怎么用结构化数据库查询就怎么用数仓,当然实际计算上并不是这么简单。

数据仓库选用哪种基础架构,决定了接入数仓的方式和难度。比如java应用原来用mysql,在一开始需要配置Maven中央仓库获取驱动程序的 JAR 文件,将驱动程序的 JAR 文件添加到Java项目的类路径中,然后使用JDBC API来管理数据库连接、执行SQL查询和更新操作等。这之后业务模块才能正常使用数据库。如果换成mysql内核的ADB数仓,以上这些配置可能都不用改,只要改一下数据库链接的url,name,password。但是如果换成DWS,因为DWS是pg内核的,驱动和mysql不一样,另外工具不是用java而是用python写的,所以得修改python相关的数据库接入配置。

【mysql双层架构与pg三层架构】

pg比mysql多了一个schema的概念,操作不同模式下的对象互不干扰,sql的结构类似于select * from database.schema.table_a;

多了一层schema之后,数据库对象更便于隔离和管理,但是增加了复杂度,尤其是分库、分模式的用户和权限控制,系统管理员默认有所有database和schema的权限,为了安全考虑不能用系统管理员账号,所以一个用户是否有schema的owner权限就很重要了。元命令:\dn 可以查看当前数据库中的所有模式及其owner,没有对应权限的账号去查表对象通常会报错,这种错误往往出现在数据库备份还原之后,尤其是本地部署的数据库,也不是专业的DBA运维,还原时不做好用户和权限控制很容易出现还原后无法使用的问题。

还有一类问题是数据库迁移或切换的场景,就是像本次mysql迁移pg,无模式分层迁移到有模式的分层,原数据库做了多个分库,这会产生对应上的问题:

1)在ADB是分库的,要求分库分表结构不能变,而用DRS做数据迁移,开同步任务的时候单个任务必须要选一个库,相当于选中的原数据库成了这边一个库下面的shema;

对象匹配规则是这样的:原SQL在mysql是二级结构,类似于database.table,不改sql的情况下使用DWS,就是schema.table,不影响sql执行。

如果在DWS做分库设计更适合多个环境的情况,比如测试和正式环境,不同的schema可以分给不同业务模块,做好权限控制即可。

2)如果在DWS也做ADB类似的分库,就会出现分库下面带一个与库同名的schema,而且每个database都建一个同步任务,DRS同步任务较多,成本较高;

【初步解决思路】

不改造工具,用一个高性能mysql内核的结构化数据库(Gaussdb for mysql)代替ADB,只要改一下数据库相关配置即可;如不能平替,要有明确结论、改造评估和接入DWS方案。

【解决方案】

  1. 评估Gaussdb for mysql性能

这二者是无法平替的,首先从定位来说Gaussdb for mysql是结构化数据库,尽管查询性能很高,但是跟分布式计算的性能没法比。Gaussdb for mysql的性能是通过缓存存储数据实现的,相当于数据库和缓存各自存储了一份数据,查询的时候先从缓存查,因此性能提高,数据量是PB级;DWS的高性能是因为做了一个分布式计算的集群,多个计算节点并行计算查询,是TB级数据库。还有一个原因决定不能用Gaussdb for mysql,阿里云上用了RDS for mysql,也是一个结构化数据库,后来因性能不达标迁移到ADB,RDS上只用来做数据写入,然后把数据批处理读取到ADB。相当于从开始就否了结构化数据库的方案。

     2. Python语言的应用和DWS的接入适配

 A. DWS支持使用JDBC或ODBC开发,需下载驱动并接入,但是Python语言开发,不支持使用JDBC或ODBC(JDBC针对java,ODBC针对windows环境)。

 B. 使用Python第三方库psycopg2连接DWS

psycopg2 是一个中间工具,使用psycopg2第三方库连接到集群,则可以使用Python访问GaussDB(DWS) 。需要先安装psycopg2第三方库并且开通到DWS的网络,要创建配置文件python_dws.py文件

复制粘贴以下内容放入python_dws.py文件中:

#!/usr/bin/python

# -*- coding: UTF-8 -*-



from __future__ import print_function



import psycopg2





def create_table(connection):

    print("Begin to create table")

    try:

        cursor = connection.cursor()

        cursor.execute("drop table if exists test;"

                       "create table test(id int, name text);")

        connection.commit()

    except psycopg2.ProgrammingError as e:

        print(e)

    else:

        print("Table created successfully")

        cursor.close()





def insert_data(connection):

    print("Begin to insert data")

    try:

        cursor = connection.cursor()

        cursor.execute("insert into test values(1,'number1');")

        cursor.execute("insert into test values(2,'number2');")

        cursor.execute("insert into test values(3,'number3');")

        connection.commit()

    except psycopg2.ProgrammingError as e:

        print(e)

    else:

        print("Insert data successfully")

        cursor.close()





def update_data(connection):

    print("Begin to update data")

    try:

        cursor = connection.cursor()

        cursor.execute("update test set name = 'numberupdated' where id=1;")

        connection.commit()

        print("Total number of rows updated :", cursor.rowcount)

        cursor.execute("select * from test order by 1;")

        rows = cursor.fetchall()

        for row in rows:

            print("id = ", row[0])

            print("name = ", row[1], "\n")

    except psycopg2.ProgrammingError as e:

        print(e)

    else:

        print("After Update, Operation done successfully")





def delete_data(connection):

    print("Begin to delete data")

    try:

        cursor = connection.cursor()

        cursor.execute("delete from test where id=3;")

        connection.commit()

        print("Total number of rows deleted :", cursor.rowcount)

        cursor.execute("select * from test order by 1;")

        rows = cursor.fetchall()

        for row in rows:

            print("id = ", row[0])

            print("name = ", row[1], "\n")

    except psycopg2.ProgrammingError as e:

        print(e)

    else:

        print("After Delete,Operation done successfully")





def select_data(connection):

    print("Begin to select data")

    try:

        cursor = connection.cursor()

        cursor.execute("select * from test order by 1;")

        rows = cursor.fetchall()

        for row in rows:

            print("id = ", row[0])

            print("name = ", row[1], "\n")

    except psycopg2.ProgrammingError as e:

        print(e)

        print("select failed")

    else:

        print("Operation done successfully")

        cursor.close()





if __name__ == '__main__':

    try:

        conn = psycopg2.connect(host='10.154.70.231',

                                port='8000',

                                database='gaussdb',  # 需要连接的database

                                user='dbadmin',

                                password='password')  # 数据库用户密码

    except psycopg2.DatabaseError as ex:

        print(ex)

        print("Connect database failed")

    else:

        print("Opened database successfully")

        create_table(conn)

        insert_data(conn)

        select_data(conn)

        update_data(conn)

        delete_data(conn)

        conn.close()

按照实际集群信息,修改python_dws.py文件中的集群公网访问地址、集群端口号、数据库名称、数据库用户名、数据库密码。

psycopg2接口不提供重试连接的能力,需要在业务代码中实现重试处理。

        conn = psycopg2.connect(host='10.154.70.231',

                                port='8000',

                                database='gaussdb',  # 需要连接的database

                                user='dbadmin',

                                password='password')  # 数据库用户密码

执行以下命令,使用psycopg第三方库连接集群。

python python_dws.py

如果可以直连psycopg第三方库连接集群,则集群可用,只需要应用做代码改造适配。

C. BI报表工具代码改造可行性评估

二开工具使用flask的框架,里面操作数据库是用的sqlalchemy,SQLAlchemy是一个Python SQL工具包和对象关系映射(ORM)库。它提供了一种高效且易于使用的方式来操作关系型数据库,尤其是关系型数据库管理系统(RDBMS)如MySQL、PostgreSQL、SQLite等。

开源的Sqlalchemy可以支持pg数据库,所以该工具可通过代码改造接入psycopg第三方库。

D、SQL兼容性

一般的数据库都可以兼容标准语法,DWS也兼容Mysql标准语法,但是部分MySQL自定义函数和方言需做SQL兼容性改造。可以获取使用最频繁的查询SQL,在DWS数据库执行测试,看看是否报错语法问题。

E、 数据同步问题

如果在DWS不分库,而是分schema,database统一用一个大的,schema与原database是同名的;所有的库都使用同一个用户同步,这个用户有所有的权限,这样只用开一条数据同步任务,成本较低。在DWS不分库,而是分schema的方式不影响执行SQL。

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值