使用 gravity 做大表的分表操作
gravity 是摩拜单车出票的一个 异构/同构 数据复制通道软件,提供主流软件的支持,并支持k8s云原生。比较看好它的发展。
项目地址: https://github.com/moiot/gravity
官方文档:https://github.com/moiot/gravity/blob/master/docs/2.0/01-quick-start.md
gravity的编译和部署不是这里的重点,我们直接跳过。
gravity的部署:
cd /root/ git clone https://github.com/moiot/gravity.git cd gravity && make mkdir /usr/local/gravity/ cd /usr/local/gravity/ cp /root/gravity/bin/gravity /usr/local/gravity/ 配置文件这里先忽略,
下面是我的架构图:
业务场景:
一个老表,随着业务量增大,考虑到分表,按照 user_id 做hash取模拆分,然后业务层面去做数据CRUD操作。
数据表如下:
create database testdb; use testdb; CREATE TABLE `gravity_t1` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', `user_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '用户id', `s_status` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '状态', PRIMARY KEY (`id`), KEY `idx_uid` (`user_id`) USING BTREE ) COMMENT = '测试表' ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4; 准备拆分后的4个分表: use testdb; create table t1_shard1 LIKE gravity_t1 ; create table t1_shard2 LIKE gravity_t1 ; create table t1_shard3 LIKE gravity_t1 ; create table t1_shard4 LIKE gravity_t1 ;
测试数据库连接方式:
数据库地址:192.168.2.4 超级账号: dts 密码: dts 假设业务用的普通账号叫rd ,密码无所谓。
造些测试用的数据:
for i in {1..10000} ; do mysql -hdts -pdts -h 192.168.2.4 -e "insert into testdb.gravity_t1 (user_id,s_status) values (\"$RANDOM\",'0');" done
结果大致这样:
[test] > select count(*) from gravity_t1 ; +----------+ | count(*) | +----------+ | 10000 | +----------+ 1 row in set (0.007 sec) [testdb] > select (user_id%4) as hash_id,count(*) FROM gravity_t1 group by (user_id%4); +---------+----------+ | hash_id | count(*) | +---------+----------+ | 0| 2537 | | 1 | 2419 | | 2 | 2509 | | 3| 2535 | +---------+----------+ 4 rows in set (0.009 sec)
shard1的配置文件,内容如下:
cat config_shard1.toml
# name 必填,这里保持每个配置文件的唯一性 name = "shard1" # 内部用于保存位点、心跳等事项的库名,默认为 _gravity , 实测发现这里改了名字也没用,保持默认即可 internal-db-name = "_gravity" # # Input 插件的定义,此处定义使用 mysql # [input] type = "mysql" mode = "replication" [input.config.source] host = "192.168.2.4" username = "dts" password = "dts" port = 3306 # # Output 插件的定义,此处使用 mysql # [output] type = "mysql" [output.config.target] host = "192.168.2.4" username = "dts" password = "dts" port = 3306 # 路由规则的定义 [[output.config.routes]] match-schema = "testdb" match-table = "gravity_t1" target-schema = "testdb" target-table = "t1_shard1" # 这个target-table 代表的是需要写入到的分片名称,每个gravity实例的配置中都需要修改
开4个窗口演示:
cd /usr/local/gravity/ ./bin/gravity -config config_shard1.toml -http-addr ":8083" ./bin/gravity -config config_shard2.toml -http-addr ":8184" ./bin/gravity -config config_shard3.toml -http-addr ":8185" ./bin/gravity -config config_shard4.toml -http-addr ":8186"
TIPS:
如果我们此时开了数据库的general_log的话, 能看到gravity到dest端是使用replace into方式插入全量数据的。然后再根据启动时候监听的binlog 实现增量数据的追平操作。
然后,看下 gravity 自动生成的库,存放都是和数据复制相关的信息:
[testdb] > show tables from _gravity ; +----------------------+ | Tables_in__gravity | +----------------------+ | gravity_heartbeat_v2 | | gravity_positions | +----------------------+ 2 rows in set (0.000 sec) [testdb] > select * from _gravity.gravity_heartbeat_v2; +--------+--------+----------------------------+----------------------------+ | name | offset | update_time_at_gravity | update_time_at_source | +--------+--------+----------------------------+----------------------------+ | shard1 | 57 | 2020-03-26 16:19:08.070483 | 2020-03-26 16:19:08.070589 | | shard2 | 51 | 2020-03-26 16:19:07.469721 | 2020-03-26 16:19:07.469811 | | shard3 | 50 | 2020-03-26 16:19:09.135751 | 2020-03-26 16:19:09.135843 | | shard4 | 48 | 2020-03-26 16:19:08.448371 | 2020-03-26 16:19:08.448450 | +--------+--------+----------------------------+----------------------------+ 4 rows in set (0.001 sec) [testdb] > select * from _gravity.gravity_positions\G *************************** 1. row *************************** name: shard1 stage: stream position: {"current_position":{"binlog-name":"mysql-bin.000014","binlog-pos":28148767,"binlog-gtid":"fd2adbd9-e263-11e8-847a-141877487b3d:1-2600359"},"start_position":{"binlog-name":"mysql-bin.000014","binlog-pos":12866955,"binlog-gtid":"fd2adbd9-e263-11e8-847a-141877487b3d:1-2559919"}} created_at: 2020-03-26 16:16:14 updated_at: 2020-03-26 16:19:26 *************************** 2. row *************************** name: shard2 stage: stream position: {"current_position":{"binlog-name":"mysql-bin.000014","binlog-pos":28155813,"binlog-gtid":"fd2adbd9-e263-11e8-847a-141877487b3d:1-2600366"},"start_position":{"binlog-name":"mysql-bin.000014","binlog-pos":16601348,"binlog-gtid":"fd2adbd9-e263-11e8-847a-141877487b3d:1-2569941"}} created_at: 2020-03-26 16:16:31 updated_at: 2020-03-26 16:19:29 *************************** 3. row *************************** name: shard3 stage: stream position: {"current_position":{"binlog-name":"mysql-bin.000014","binlog-pos":28151964,"binlog-gtid":"fd2adbd9-e263-11e8-847a-141877487b3d:1-2600363"},"start_position":{"binlog-name":"mysql-bin.000014","binlog-pos":20333055,"binlog-gtid":"fd2adbd9-e263-11e8-847a-141877487b3d:1-2579960"}} created_at: 2020-03-26 16:16:35 updated_at: 2020-03-26 16:19:29 *************************** 4. row *************************** name: shard4 stage: stream position: {"current_position":{"binlog-name":"mysql-bin.000014","binlog-pos":28152473,"binlog-gtid":"fd2adbd9-e263-11e8-847a-141877487b3d:1-2600364"},"start_position":{"binlog-name":"mysql-bin.000014","binlog-pos":24076960,"binlog-gtid":"fd2adbd9-e263-11e8-847a-141877487b3d:1-2589987"}} created_at: 2020-03-26 16:16:40 updated_at: 2020-03-26 16:19:29 4 rows in set (0.000 sec)
TIPS:
到这一步,我们的4个分表的数据同步都配好了,我们可以再插入几条数据测试下。
-- insert into testdb.gravity_t1(user_id,s_status) values ('11111','0'); -- insert into testdb.gravity_t1(user_id,s_status) values ('11112','0'); -- 我这里演示就不插了
原始和拆分表的数据条数对比:
[testdb] > select (user_id%4) as hash_id,count(*) FROM gravity_t1 group by (user_id%4); +---------+----------+ | hash_id | count(*) | +---------+----------+ | 0 | 2537 | | 1 | 2419 | | 2 | 2509 | | 3 | 2535 | +---------+----------+ 4 rows in set (0.009 sec
select count(*) FROM t1_shard1 where user_id%4=0; select count(*) FROM t1_shard2 where user_id%4=1; select count(*) FROM t1_shard3 where user_id%4=2; select count(*) FROM t1_shard4 where user_id%4=3;
先做一次对分表中不需要的数据的删除操作,防止后期切换后删除数据量过大:
delete from t1_shard1 where user_id %4!=0; delete from t1_shard2 where user_id %4!=1; delete from t1_shard3 where user_id %4!=2; delete from t1_shard4 where user_id %4!=3; ## 注意:生产环境大表的删除操作,建议使用pt-archiver进行
然后,再到原始表和分表中查询对比下数据是否一致:
select (user_id%4),count(*) as hash_id FROM gravity_t1 group by (user_id%4); select count(*) FROM t1_shard1 where user_id%4=0; select count(*) FROM t1_shard2 where user_id%4=1; select count(*) FROM t1_shard3 where user_id%4=2; select count(*) FROM t1_shard4 where user_id%4=3;
然后,等低峰期进行操作。
1、dba对涉及到的业务账号 对这个大表写权限回收掉
revoke insert,update,delete on testdb.gravity_t1 from rd@'%'; flush hosts; flush tables;
2、通知业务方发版,切换数据库连接到4个新表
3、切换完成后,dba再执行一次删除各个分表脏数据的操作,
delete from t1_shard1 where user_id %4!=0; delete from t1_shard2 where user_id %4!=1; delete from t1_shard3 where user_id %4!=2; delete from t1_shard4 where user_id %4!=3;
4、打开4个新表的写权限
GRANT select,insert,update,delete on testdb.t1_shard1 TO rd@'%'; GRANT select,insert,update,delete on testdb.t1_shard2 TO rd@'%'; GRANT select,insert,update,delete on testdb.t1_shard3 TO rd@'%'; GRANT select,insert,update,delete on testdb.t1_shard4 TO rd@'%';
5、然后,通知业务方测试。
6、业务方验证无问题后收工。至此,单表 拆分为分表的操作全部完成。
7、回退方案,待补充 (打开gravity的双向复制??)
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
什么是暗网?访问它你将会发现什么?
暗网定义 首先说,它是日常的搜索引擎所无法寻找到的,仅能在电脑上进行一系列特殊的操作设置或在特殊软件的辅助之下又或对本机的特殊授权之后方能进入访问的一种网络——即称之为“暗网”。“ 暗网”之中的数据统统是以检索难度极大的“隐身”的方式进行传输交流,服务器地址亦是如此。此外,极高的私密性是其中用户联系彼此的一大特点,对进行拦截的手段和网络技术的要求极高,并且破译拦截后的信息也是一大难题。 暗网是深网的一个分支,目前可以通过“洋葱网络”或者“I2P网络”进行。统计数据表明,我们平时所能见的表层网络的域名数量仅仅占据暗网的1/400到1/500。 暗网因其与生俱来的隐匿特性,现在被不法分子广泛运用于网络犯罪。从个人行为的网络黑客窃密、数字货币交易、私售非法禁售物品、非法人口买卖、甚至进行杀人越货的行为甚至到国家意志的叛国无耻行径,都依托暗网的隐匿服务。 引人不适的暗网报道:食人癖 深色网络是互联网的一部分,未被搜索引擎指明。但在此之前,您已经听说过将“暗网”作为犯罪活动的温床的话题,而且事实的确如此。 伦敦国王学院的研究人员丹尼尔·摩尔(Daniel Moore)和托马斯·里德(Thomas...
- 下一篇
用docker搭建selenium grid分布式环境实践之路
用docker搭建selenium grid分布式环境实践之路最近需要测试zoom视频会议,同时模拟100个人加入会议。经过了解,zoom提供了直接通过url链接加入会议的方式(只能通过chrome浏览器或者FireFox浏览器,因为用的协议是webrtc)。 顺着这个思路考虑可以通过Selenium自动化,同时启动多个浏览器进程,每个进程代表一个视频会议用户,达到模拟多方会议的效果。不过有以下两个难点: 需要多个chrome浏览器进程同时存活,在电脑上启动一个chrome浏览器进程差不多要消耗220M左右。视频会议的音频和视频源的问题。针对视频会议的音频和视频源的问题,chrome浏览器有比较好的支持,在Selenium脚本中初始化Chrome浏览器的参数中,只需要加入如下配置: chrome_options.add_argument("--use-fake-ui-for-media-stream")chrome_options.add_argument("--use-fake-device-for-media-stream")就能在加入视频会议之后,使用虚拟的视频和音频。不过有个问...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
-
Docker使用Oracle官方镜像安装(12C,18C,19C)
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- CentOS8编译安装MySQL8.0.19
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- MySQL8.0.19开启GTID主从同步CentOS8
- CentOS7,8上快速安装Gitea,搭建Git服务器
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
推荐阅读
最新文章
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2配置默认Tomcat设置,开启更多高级功能
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Hadoop3单机部署,实现最简伪集群
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- MySQL8.0.19开启GTID主从同步CentOS8
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16
- CentOS7,CentOS8安装Elasticsearch6.8.6