暂无图片
暂无图片
2
暂无图片
暂无图片
暂无图片

「OceanBase 征文」Mysql8.0与OceanBase4.0【安装对比、测试对比】

原创 大数据模型 2023-03-22
1052

前言

2022 年 8 月 10 日, OceanBase 在年度发布会上正式发布了 OceanBase 4.0(代号:小鱼),并在现场展区尝试做了一些有趣的事情,“小鱼”可以单机版部署在个人 PC 以及树莓派,让来到现场的开发者通过简单互动就能进行体验。这个名字代表着真正小型化的全面尝试,像鱼群一样可大可小,也意味着从“分布式”到“单机分布式一体化”的转变

OceanBase 一直以“攻坚大型场景”被大家所熟知,我们可以把它想象成大海里航行的一艘巨轮。而 4.0 版本是业内首个单机分布式一体化架构,这意味着过去运行在数据中心一排排服务器上的分布式数据库,也能够以完整功能、单机部署到更低配置的服务器与个人 PC 上,甚至部署到世界最小电脑:树莓派上。

4.0 版本开启了 OceanBase 的小型化进程,也为支撑业务增长、陪伴开发者成长提供了广阔的想象空间,就像无垠的大海中一条自由游动的“小鱼”。另一方面,4.0 版本在内核能力、兼容性、性能、运维能力等方面都有大幅提升,因此,这也是一条能轻松应对各种恶劣环境的“小鱼”。

一年多前,OceanBase 正式宣布开源,来自世界各地的众多开发者参与到了数据库内核、生态工具的打磨完善中,与我们共同陪伴了“小鱼”的诞生与成长。同样的,“小鱼”也将在未来陪伴无数数据库开发者的成长。

简而言之,OceanBase推出轻量级的OceanBase4.0,更轻、更快、更容易布署,当前世界最轻量级的数据库产品是MySQL,所以本文是MySQL与OceanBase的较量对比。

MySQL版本家族中最具备代表性的是8.0,它是MySQL发展的里程碑,从此5.7版本正式过渡到8.0,无 论功能还是性能都有质的提升,除了对NOSQL功能和JSON数据支持更友好,另外它根据市场需求也增加了窗口函数,例如RANK和ROW_NUMBER等等。最难得可贵的是,8.0在优化器的智能处理得到了极大的提升,过去 MySQL与PostgreSQL比较,一直诟病MySQL的优化器做得不如PostgreSQL好,现在8.0可谓翻身鲤鱼龙门跃 。

本文对MySQL8.0与OceanBase4.0做了功能、性能、体验的对比,力争从开发者的角度 ,在单机上安装MySQL8.0和OceanBase4.0, 保留默认参数不做任何改变,然后在上面建立4个表,通过IDEA运行程序进行数据插入、数据查询体验感受两个产品,从本文可以有以下收获。

  • 单节点安装MySQL8.0与单节点安装OceanBase4.0的安装操作步骤
  • MySQL8.0与OceanBase4.0的整体认识
  • MySQL8.0与OceanBase4.0的性能影响关键因素和重要参数

测试环境

操作系统 CentOS Linux release 7.6.1810
CPU 8核 Intel® Xeon®
内存 16
MySQL mysql 8.0.32
OceanBase OceanBase_CE-v4.0.0.0

安装篇

产品安装对比,LINUX下的软件安装,常用方式有RPM安装、二进制安装、源码安装三个方式。

  • RPM安装操作简单,需要客户端、服务端、库包等,而且安装路径固定死板,默认位置不能更改。
  • 二进制安装可以自定义选择路径修改,甚至基于不同的目录在一个系统安装多个,但是二进制本身经过编译,不能灵活定制编译参数,进行单方面的调较。
  • 源码安装可以按需定制参数调优,也可以在不同的目录安装多个,但是安装花费时间多,过程复杂,容易出错。

MySQL和OceanBase的技术路径发展会支持以上三种安装方式,对于普通开发者来说,他们希望更简单,更关心拿来就用,所以又有docker安装,下面只介绍RPM安装。

mysql8.0 RPM安装

1.下载一个8.0的rpm文件,约25KB wget http://repo.mysql.com/mysql80-community-release-el7-3.noarch.rpm 2.安装rpm文件 yum -y install mysql80-community-release-el7-3.noarch.rpm 3.安装mysql服务,因为 yum -y install mysql-community-server --nogpgcheck 4.启动mysql服务,查看运行状态 systemctl start mysqld.service systemctl status mysqld.service 5.从当前数据库的日志文件中找出初始随机密码 grep "password" /var/log/mysqld.log 6.初始随机密码登录mysql,并修改密码 [root@hdp2 ~]# mysql -uroot -p Enter password: Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 8 Server version: 8.0.32 MySQL Community Server - GPL Copyright (c) 2000, 2023, Oracle and/or its affiliates. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql> 将密码修改为自己的密码 将下面 Mypassword 换成你自己定的密码 ALTER USER 'root'@'localhost' IDENTIFIED BY 'Mypassword'; 7.建立应用访问的用户名和密码 mysql> create user henley identified by 'Mypassword'; Query OK, 0 rows affected (0.02 sec) mysql> grant all privileges on *.* to 'henley'@'%'; Query OK, 0 rows affected (0.04 sec) 8.查看MySQL的关键参数 show global status like '%innodb_buffer_pool%'; show variables like '%Innodb_buffer%'; show variables like '%conn%'; show variables like '%log%';

OceanBase4.0 RPM安装

image.png

下载X86版本

1.下载一个all-in-one包,约330M wget https://obbusiness-private.oss-cn-shanghai.aliyuncs.com/download-center/opensource/oceanbase-all-in-one/7/x86_64/oceanbase-all-in-one-4.0.0.0-100120230113164218.el7.x86_64.tar.gz?Expires=1679311481&OSSAccessKeyId=LTAI5tGVLeRRycCRGerZJMNC&Signature=eBZoWUq8bsRExzF4Zx8ZBkcbnIM%3D 2.解压后目录结构如下,通过README.md文件可以指示你怎么快速展开安装。 [root@hdp2 ob_allinone]# du -sh oceanbase-all-in-one/* 12K oceanbase-all-in-one/bin 264K oceanbase-all-in-one/conf 45M oceanbase-all-in-one/obclient 85M oceanbase-all-in-one/obd 4.0K oceanbase-all-in-one/README.md 201M oceanbase-all-in-one/rpms 4.0K oceanbase-all-in-one/VERSION 3.安装obd布署工具 bin/install.sh 4.安装Oceanbase服务, 快速安装,直接运行obd demo就可以一键安装OB4 如果想个性化安装布署 obd cluster playground -c oceanbase-ce,obproxy-ce,obagent,prometheus,grafana 安装过程中,可能会提示内存不足或者空间不够,根据错误提醒调整后,重新运行obd demo +----------------------------+------+----------+--------+ | url | user | password | status | +----------------------------+------+----------+--------+ | http://192.168.XX.XX:9090 | | | active | +----------------------------+------+----------+--------+ +---------------------------------------------------------------------+ | grafana | +----------------------------------------+-------+-----------+--------+ | url | user | password | status | +----------------------------------------+-------+-----------+--------+ | http://192.168.XX.XX:3000/d/oceanbase | admin | oceanbase | active | +----------------------------------------+-------+-----------+--------+ demo running 5.登录OceanBase,建立资源单元unitfish绑定资源池poolfish,poolfish再与租户tenantfish完成映射。 [root@hdp2 oceanbase-all-in-one]# obclient -h127.0.0.1 -P2881 -uroot Welcome to the OceanBase. Commands end with ; or \g. Your OceanBase connection id is 3221664483 Server version: OceanBase_CE 4.0.0.0 (r103000022023011215-05bbad0279302d7274e1b5ab79323a2c915c1981) (Built Jan 12 2023 15:28:27) Copyright (c) 2000, 2018, OceanBase and/or its affiliates. All rights reserved. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. obclient [(none)]> use oceanbase; Reading table information for completion of table and column names You can turn off this feature to get a quicker startup with -A Database changed 创建15个CPU,3G内存的资源单位unitfish obclient [oceanbase]> CREATE RESOURCE UNIT unitfish MAX_CPU 15, MEMORY_SIZE '3G', MAX_IOPS 1280,LOG_DISK_SIZE '10G', MIN_IOPS=1024; Query OK, 0 rows affected (0.015 sec) 资源单位unitfish绑定资源池poolfish obclient [oceanbase]> CREATE RESOURCE POOL poolfish UNIT = 'unitfish', UNIT_NUM = 1,ZONE_LIST = ('zone1'); Query OK, 0 rows affected (0.025 sec) 资源池poolfish绑定租户tenantfish obclient [oceanbase]> create tenant tenantfish resource_pool_list=('poolfish'), charset=utf8mb4, replica_num=3, zone_list('zone1'), primary_zone=RANDOM, locality='F@zone1' set variables ob_compatibility_mode='mysql', ob_tcp_invited_nodes='%'; Query OK, 0 rows affected (24.164 sec) obclient [oceanbase]> SELECT unit_config_id,name,max_cpu,min_cpu,memory_size/1024/1024/1024 FROM __all_unit_config; +----------------+-----------------+---------+---------+----------------------------+ | unit_config_id | name | max_cpu | min_cpu | memory_size/1024/1024/1024 | +----------------+-----------------+---------+---------+----------------------------+ | 1 | sys_unit_config | 1 | 1 | 2.000000000000 | | 1015 | unitfish | 15 | 15 | 3.000000000000 | +----------------+-----------------+---------+---------+----------------------------+ 2 rows in set (0.003 sec) 6.以root的身份登录租户tenantfish,创建用户名和密码,并授权访问 [root@hdp2 oceanbase-all-in-one]# obclient -h192.168.30.221 -uroot@tenantfish -P2883 -c -A oceanbase Welcome to the OceanBase. Commands end with ; or \g. Your OceanBase connection id is 13 Server version: OceanBase_CE 4.0.0.0 (r103000022023011215-05bbad0279302d7274e1b5ab79323a2c915c1981) (Built Jan 12 2023 15:28:27) Copyright (c) 2000, 2018, OceanBase and/or its affiliates. All rights reserved. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. obclient [oceanbase]> create user henley identified by 'P@ssw0rd'; Query OK, 0 rows affected (0.111 sec) obclient [oceanbase]> grant all privileges on *.* to 'henley'@'%'; Query OK, 0 rows affected (0.045 sec)

安装总结

mysql8.0的rpm安装方式轻巧且灵活,必须保持联网,通过YUM源就可以进行安装,安装成功后服务端提供随机密码保障安全,root登录后要完成改密码,并进行用户、授权等操作。前段安装简单【安装YUM安装】,后段使用【创建授权】也方便,但是整体建设欠妥,工程师需要额外安装监控、报警等相关服务。

OceanBase4.0需要把安装介质下载到本地,再通过obd脚本自动化安装,安装成功后 需要root登录sys租户, 完成创建租户、创建用户、授权等操作。OceanBase4.0的安装考虑周全,不仅必需的observer,其它的生态工具promethous、grafna都会自动化安装完成。前段还算顺利【介质安装、执行脚本安装】,但是后段较麻烦,OB有多租户的概念,需要创建资源单元、绑定资源池、建立租户,最后才是创建用户以及授权。

另外OceanBase4.0需要的硬盘空间较多,提前下载安装介质 以及安装过程对硬盘的容量需求,相对来说需要比MySQL8.0要大,你必须有一定的大容量才能安装OceanBase4.0。

测试篇

基本性能

程序指定两个不同的用户,8.0要用8.0的驱动,OB的用户注意要加上租户信息。
// private static final String JDBC_CLASS_NAME = “com.mysql.cj.jdbc.Driver”;
// private static final String JDBC_URL = “jdbc:mysql://xxxx:3306/fish?useUnicode=true” +
// “&characterEncoding=UTF-8&useSSL=false&rewriteBatchedStatements=true” +
// “&allowPublicKeyRetrieval=true”;
// private static final String JDBC_USER = “henley”;
// private static final String JDBC_PWD = “xxxx”;

// private static final String JDBC_CLASS_NAME = “com.mysql.jdbc.Driver”;
// private static final String JDBC_URL = “jdbc:mysql://xxxx:2881/fish?useServerPrepStmts=true” +
// “&rewriteBatchedStatements=true” +
// “&allowMultiQueries=true” +
// “&useSSL=false”;
// private static final String JDBC_USER = “henley@tenantfish”;
// private static final String JDBC_PWD = “xxxx”;

建立4个表 用户表、订单表、产品表、仓库表 ,制定以下基本测试用例,代码层面上没有使用多线程并发,针对OB用的是5.1.46,而MySQL8用的是8.0.22驱动。

image.png

image.png

image.png

  • 测试用例1. 应用数据写入 ,仓库表100条数据,用户表1000条数据,产品表10000条数据,订单表100万条数据。通过java流的方式生成数据,以1000的方式批量写入。记录时间,观察CPU使用消耗,查看数据
  • 测试用例2. 全表扫描查询,对4个表进行select 字段1,字段2 from 表名,记录SQL查询消耗。
  • 测试用例3,两表关联查询 ,订单表关联用户表, 订单表关联产品表,订单表关联仓库表,记录查询消耗。

三个测试用例采集的数据如下
image.png

索引功能

对订单进行索引过滤查询,记录未建索引前的查询时间,以及建立索引花费的时间,建立索引后的查询时间。

mysql建立索引前

mysql> explain  SELECT * FROM tb_order where warehouse_number = 'whs_0000000075';   
+----+-------------+----------+------------+------+---------------+------+---------+------+--------+----------+-------------+
| id | select_type | table    | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra       |
+----+-------------+----------+------------+------+---------------+------+---------+------+--------+----------+-------------+
|  1 | SIMPLE      | tb_order | NULL       | ALL  | NULL          | NULL | NULL    | NULL | 994284 |    10.00 | Using where |
+----+-------------+----------+------------+------+---------------+------+---------+------+--------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

mysql建立索引

mysql> CREATE INDEX `tb_order_idx02` ON  fish.`tb_order` (`warehouse_number`, `product_number`);
Query OK, 0 rows affected (18.98 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql建立索引后

mysql> explain  SELECT * FROM tb_order where warehouse_number = 'whs_0000000075';
+----+-------------+----------+------------+------+----------------+----------------+---------+-------+-------+----------+-------+
| id | select_type | table    | partitions | type | possible_keys  | key            | key_len | ref   | rows  | filtered | Extra |
+----+-------------+----------+------------+------+----------------+----------------+---------+-------+-------+----------+-------+
|  1 | SIMPLE      | tb_order | NULL       | ref  | tb_order_idx02 | tb_order_idx02 | 82      | const | 19526 |   100.00 | NULL  |
+----+-------------+----------+------------+------+----------------+----------------+---------+-------+-------+----------+-------+
1 row in set, 1 warning (0.00 sec)

oceanbase建立索引前

obclient [fish]> explain  SELECT * FROM tb_order where warehouse_number = 'whs_0000000075';

|ID|OPERATOR               |NAME    |EST. ROWS|COST  |
------------------------------------------------------

|0 |PX COORDINATOR         |        |10000    |106628|
|1 | EXCHANGE OUT DISTR    |:EX10000|10000    |93272 |
|2 |  PX PARTITION ITERATOR|        |10000    |63232 |

|3 |   TABLE SCAN          |tb_order|10000    |63232 |
======================================================

Outputs & filters: 
-------------------------------------

  0 - output([INTERNAL_FUNCTION(tb_order.id, tb_order.ord_number, tb_order.custom_number, tb_order.product_number, tb_order.warehouse_number, tb_order.ord_status, tb_order.order_time)]), filter(nil), rowset=256
  1 - output([INTERNAL_FUNCTION(tb_order.id, tb_order.ord_number, tb_order.custom_number, tb_order.product_number, tb_order.warehouse_number, tb_order.ord_status, tb_order.order_time)]), filter(nil), rowset=256, dop=1
  2 - output([tb_order.id], [tb_order.warehouse_number], [tb_order.ord_number], [tb_order.custom_number], [tb_order.product_number], [tb_order.ord_status], [tb_order.order_time]), filter(nil), rowset=256
  3 - output([tb_order.id], [tb_order.warehouse_number], [tb_order.ord_number], [tb_order.custom_number], [tb_order.product_number], [tb_order.ord_status], [tb_order.order_time]), filter([tb_order.warehouse_number = 'whs_0000000075']), rowset=256, 
      access([tb_order.id], [tb_order.warehouse_number], [tb_order.ord_number], [tb_order.custom_number], [tb_order.product_number], [tb_order.ord_status], [tb_order.order_time]), partitions(p[0-7])

oceanbase建立索引

obclient [fish]> CREATE INDEX `tb_order_idx02` ON  fish.`tb_order` (`warehouse_number`, `product_number`);
Query OK, 0 rows affected (44.654 sec)

oceanbase建立索引后

obclient [fish]> explain  SELECT * FROM tb_order where warehouse_number = 'whs_0000000075';

|ID|OPERATOR               |NAME                    |EST. ROWS|COST |
---------------------------------------------------------------------

|0 |PX COORDINATOR         |                        |10000    |86879|
|1 | EXCHANGE OUT DISTR    |:EX10000                |10000    |73523|
|2 |  PX PARTITION ITERATOR|                        |10000    |43482|

|3 |   TABLE SCAN          |tb_order(tb_order_idx02)|10000    |43482|
=====================================================================

Outputs & filters: 
-------------------------------------

  0 - output([INTERNAL_FUNCTION(tb_order.id, tb_order.ord_number, tb_order.custom_number, tb_order.product_number, tb_order.warehouse_number, tb_order.ord_status, tb_order.order_time)]), filter(nil), rowset=256
  1 - output([INTERNAL_FUNCTION(tb_order.id, tb_order.ord_number, tb_order.custom_number, tb_order.product_number, tb_order.warehouse_number, tb_order.ord_status, tb_order.order_time)]), filter(nil), rowset=256, dop=1
  2 - output([tb_order.id], [tb_order.warehouse_number], [tb_order.ord_number], [tb_order.custom_number], [tb_order.product_number], [tb_order.ord_status], [tb_order.order_time]), filter(nil), rowset=256
  3 - output([tb_order.id], [tb_order.warehouse_number], [tb_order.ord_number], [tb_order.custom_number], [tb_order.product_number], [tb_order.ord_status], [tb_order.order_time]), filter(nil), rowset=256, 
      access([tb_order.id], [tb_order.warehouse_number], [tb_order.ord_number], [tb_order.custom_number], [tb_order.product_number], [tb_order.ord_status], [tb_order.order_time]), partitions(p[0-7])

倒序索引

mysql8.0建立倒序索引后的查询时间,对比 OceanBase4.0的查询时间。

首先在mysql8.0和OceanBase4.0执行以下语句

SELECT custom_number, product_number from tb_order order by custom_number, product_number DESC ;

然后建立建立mysql的倒序索引

CREATE INDEX `tb_order_idx01` ON fish.`tb_order` (`custom_number`, `product_number` DESC);

再建立oceanbase的索引

CREATE INDEX `tb_order_idx01` ON fish.`tb_order` (`custom_number`, `product_number` );

未建倒序索引前mysql8.0花了2.56 sec,建立倒序索引后0.65 sec, 而OceanBase4.0花了9.340 sec,建立索引后花费时间11.771 sec。

测试总结

关于基本性能,发现批写入的JDBC连接串不同,OB进行应用数据写入时,jdbc连接串必须是useServerPrepStmts=true&rewriteBatchedStatements=true&allowMultiQueries=true&useSSL=false,否则不能批量提交,同样写入数据,mysql8可以自由select coun(*)查看写入状态,但是OB4会提示报错,需要提高ob_query_timeout的数值。大表写入,mysql8明显比OB4写入的速度快,笔者揣测这里与OB4的配置参数有关,obd demo生成的observer配置是 memory_limit=6G,system_memory=1G,cpu_count=16,实际上留给observer只有5G内存,在资源分配的时候,租户tennatfish实际只能得到3G内存。

全表扫描查询与关联两表查询,两者的距离不大,相差不是很远。

关于索引功能,mysql8与ob4未加索引前,两者的查询速都是差不多,查看查询计划发现都没有使用索引,注意mysql的查询计划面板与OB4不一样,mysql8与ob4加上索引后,两者的查询速度差不多,但是mysql8的索引创建花了18.98 sec,而ob4却花了44.654 sec。

关于倒序索引,据说倒序索引是mysql8的亮点,也是mysql8区别于5系列的标识,有关数据排序方面,OB4完全不如mysql8。未建倒序索引前mysql8.0花了2.56 sec,建立倒序索引后0.65 sec,而OceanBase4.0花了9.340 sec,建立常规索引后花费时间11.771 sec。

最后总结

我的判断是没有Mysql8比OB4快,同样OB4没有比Mysql8快,关键是什么样的司机,但是普通的司机【一般开发者】可能更喜欢开箱即用,一脚油门就能走,不关心发动机带不带T,具体是怎么工作的,也不关心底盘调校是什么参数,只希望汽车的默认参数直接能够支撑他走个10年。

mysql是单机系列数据库产品,Oceanbase4是分布式系列数据库产品,本来两者没有可比性的,但是Oceanbase要迈军轻量化,要技术布道深入广大开发者群众,所以有了比较衡量。

开发者的选择,到底是MySQL8好还是OceanBase4.0好,笔者说一个真实的事, 某家公司的内部系统开发,数据库选型长期以来一直是mysql,如果要迭代升级,最多升到5.7,怎么也愿往8上面升级, 原因是8会有更多的行为习惯改变,对团队来说有更多的学习成本。所以性能快不是最重要的,功能多也不是必要的,只有合适业务才是最好的。从用户需求的性质出发,数据库是长期的事业,Oceanbase以后的发展,必须坚持技术布道,逐步改变开发者的偏见和误解。

最后修改时间:2023-03-31 12:06:52
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

文章被以下合辑收录

评论