ShardingSphere应用专题–4.1.1版本–Sharding-Scaling实现弹性伸缩(十七)

26 篇文章 3 订阅
18 篇文章 4 订阅

前言

1.基础的环境介绍请移步ShardingSphere应用专题–4.1.1版本–sharding jdbc环境搭建(四)
你可以同时打开两个页面,避免因查找原始配置上下翻动。

2.ShardingSphere官方文档更新不及时,很容易踩坑。贴出的4.x版本文档实际是4.0.1版本的,如果你准备使用该版本可以参考官方文档。本文使用的是此时最新的正式版本4.1.1版本,配置与官方文档配置不同。事实上,源码中有非常详细的版本配置文档,本文也是参考4.1.1 tag的源码配置。

3.ShardingSphere各版本差异很大,甚至核心依赖的包名都不一样,使用时,一定要确认使用哪个版本,目前调研的结果:3.x、4.0.1、4.1.1、5.0.0-alpha都存在很大的配置差异

4.为了更好理解,在看本文前应先了解Sharding-JDBC,Sharding-Proxy,Sharding-UI相关产品,具体可参阅:
ShardingSphere应用专题–4.1.1版本–Sharding-JDBC环境搭建(四)
中的文章链接

Sharding-Scaling简介

Apache ShardingSphere 提供了数据分片的能力,可以将数据分散到不同的数据库节点上,提升整体处理能力。 但对于使用单数据库运行的系统来说,如何安全简单地将数据迁移至水平分片的数据库上,一直以来都是一个迫切的需求; 同时,对于已经使用了 Apache ShardingSphere 的用户来说,随着业务规模的快速变化,也可能需要对现有的分片集群进行弹性扩容或缩容。

  1. 老项目首次使用Sharding-JDBC按照一定的规则分库分表,老数据怎么办?
  2. 老项目已经使用了Sharding-JDBC将数据分成了2库2表,现在数据量还是很大,想分成10库10表,老数据怎么办?
    这个就是现实中的数据库的弹性伸缩的场景

Sharding-Scaling就是ShardingSphere给出的一个提供给用户的通用数据接入迁移及弹性伸缩的解决方案

弹性伸缩方案架构

在这里插入图片描述

挑战

Apache ShardingSphere 在分片策略和算法上提供给用户极大的自由度,但却给弹性伸缩造成了极大的挑战。 如何找到一种方式,即能支持各类不同用户的分片策略和算法,又能高效地将数据节点进行伸缩,是弹性伸缩面临的第一个挑战;

同时,弹性伸缩过程中,不应该对正在运行的业务造成影响,尽可能减少伸缩时数据不可用的时间窗口,甚至做到用户完全无感知,是弹性伸缩的另一个挑战;

最后,弹性伸缩不应该对现有的数据造成影响,如何保证数据的可用性和正确性,是弹性伸缩的第三个挑战。

目标

支持各类用户自定义的分片策略,减少用户在数据伸缩及迁移时的重复工作及业务影响,提供一站式的通用弹性伸缩解决方案,是 Apache ShardingSphere 弹性伸缩的主要设计目标。

状态

当前处于 alpha 开发阶段。

在这里插入图片描述

核心概念

考虑到 Apache ShardingSphere 的弹性伸缩模块的几个挑战,目前的弹性伸缩解决方案为:临时地使用两个数据库集群,伸缩完成后切换的方式实现。
在这里插入图片描述

这种实现方式有以下优点:

  • 伸缩过程中,原始数据没有任何影响
  • 伸缩失败无风险
  • 不受分片策略限制

同时也存在一定的缺点:

  • 在一定时间内存在冗余服务器

  • 所有数据都需要移动
    弹性伸缩模块会通过解析旧分片规则,提取配置中的数据源、数据节点等信息,之后创建伸缩作业工作流,将一次弹性伸缩拆解为4个主要阶段

  • 准备阶段

  • 存量数据迁移阶段

  • 增量数据同步阶段

  • 规则切换阶段
    在这里插入图片描述

弹性伸缩测试

1.业务场景描述

还是使用 ShardingSphere应用专题–4.1.1版本–服务治理(十四)一文中的数据。

  • 目前的数据分成了mydb0,mydb1两个库,每个库中的bill表按照id%2分成了bill_0,bill_1两张表
  • 目前的业务场景设定为,2张表已经不满足我们的业务数据,需要扩容至4张表

这里偷懒了一下,仍然使用mydb0,mydb1两个库,表名更改为bill_scaling

2.表结构准备

DROP TABLE IF EXISTS `mydb0`.`bill_scaling_0`;
CREATE TABLE `mydb0`.`bill_scaling_0`
(
    `id`          bigint unsigned  NOT NULL AUTO_INCREMENT COMMENT '主键',
    `bill_name`   varchar(255)     NOT NULL DEFAULT '' COMMENT '账单名称',
    `bill_amount` int unsigned     NOT NULL DEFAULT '0' COMMENT '账单金额',
    `create_time` datetime(3)      NOT NULL COMMENT '创建时间',
    `is_delete`   tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0:未删除 1:已删除',
    PRIMARY KEY (`id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;


DROP TABLE IF EXISTS `mydb0`.`bill_scaling_1`;
CREATE TABLE `mydb0`.`bill_scaling_1`
(
    `id`          bigint unsigned  NOT NULL AUTO_INCREMENT COMMENT '主键',
    `bill_name`   varchar(255)     NOT NULL DEFAULT '' COMMENT '账单名称',
    `bill_amount` int unsigned     NOT NULL DEFAULT '0' COMMENT '账单金额',
    `create_time` datetime(3)      NOT NULL COMMENT '创建时间',
    `is_delete`   tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0:未删除 1:已删除',
    PRIMARY KEY (`id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

DROP TABLE IF EXISTS `mydb0`.`bill_scaling_2`;
CREATE TABLE `mydb0`.`bill_scaling_2`
(
    `id`          bigint unsigned  NOT NULL AUTO_INCREMENT COMMENT '主键',
    `bill_name`   varchar(255)     NOT NULL DEFAULT '' COMMENT '账单名称',
    `bill_amount` int unsigned     NOT NULL DEFAULT '0' COMMENT '账单金额',
    `create_time` datetime(3)      NOT NULL COMMENT '创建时间',
    `is_delete`   tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0:未删除 1:已删除',
    PRIMARY KEY (`id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

DROP TABLE IF EXISTS `mydb0`.`bill_scaling_3`;
CREATE TABLE `mydb0`.`bill_scaling_3`
(
    `id`          bigint unsigned  NOT NULL AUTO_INCREMENT COMMENT '主键',
    `bill_name`   varchar(255)     NOT NULL DEFAULT '' COMMENT '账单名称',
    `bill_amount` int unsigned     NOT NULL DEFAULT '0' COMMENT '账单金额',
    `create_time` datetime(3)      NOT NULL COMMENT '创建时间',
    `is_delete`   tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0:未删除 1:已删除',
    PRIMARY KEY (`id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;





DROP TABLE IF EXISTS `mydb1`.`bill_scaling_0`;
CREATE TABLE `mydb1`.`bill_scaling_0`
(
    `id`          bigint unsigned  NOT NULL AUTO_INCREMENT COMMENT '主键',
    `bill_name`   varchar(255)     NOT NULL DEFAULT '' COMMENT '账单名称',
    `bill_amount` int unsigned     NOT NULL DEFAULT '0' COMMENT '账单金额',
    `create_time` datetime(3)      NOT NULL COMMENT '创建时间',
    `is_delete`   tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0:未删除 1:已删除',
    PRIMARY KEY (`id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

DROP TABLE IF EXISTS `mydb1`.`bill_scaling_1`;
CREATE TABLE `mydb1`.`bill_scaling_1`
(
    `id`          bigint unsigned  NOT NULL AUTO_INCREMENT COMMENT '主键',
    `bill_name`   varchar(255)     NOT NULL DEFAULT '' COMMENT '账单名称',
    `bill_amount` int unsigned     NOT NULL DEFAULT '0' COMMENT '账单金额',
    `create_time` datetime(3)      NOT NULL COMMENT '创建时间',
    `is_delete`   tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0:未删除 1:已删除',
    PRIMARY KEY (`id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;


DROP TABLE IF EXISTS `mydb1`.`bill_scaling_2`;
CREATE TABLE `mydb1`.`bill_scaling_2`
(
    `id`          bigint unsigned  NOT NULL AUTO_INCREMENT COMMENT '主键',
    `bill_name`   varchar(255)     NOT NULL DEFAULT '' COMMENT '账单名称',
    `bill_amount` int unsigned     NOT NULL DEFAULT '0' COMMENT '账单金额',
    `create_time` datetime(3)      NOT NULL COMMENT '创建时间',
    `is_delete`   tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0:未删除 1:已删除',
    PRIMARY KEY (`id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;



DROP TABLE IF EXISTS `mydb1`.`bill_scaling_3`;
CREATE TABLE `mydb1`.`bill_scaling_3`
(
    `id`          bigint unsigned  NOT NULL AUTO_INCREMENT COMMENT '主键',
    `bill_name`   varchar(255)     NOT NULL DEFAULT '' COMMENT '账单名称',
    `bill_amount` int unsigned     NOT NULL DEFAULT '0' COMMENT '账单金额',
    `create_time` datetime(3)      NOT NULL COMMENT '创建时间',
    `is_delete`   tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否删除 0:未删除 1:已删除',
    PRIMARY KEY (`id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4;

mydb0,mydb1中分别创建了4张bill_scaling表,即bill_scaling_$->{id%4}

3.配置Sharding-Proxy

由于存在非分库分表的表无法正确查询的bug(具体参考ShardingSphere应用专题–4.1.1版本–Sharding-Proxy的使用(十六)-表名附带库名,非分库分表逻辑表路由错误的bug,这里使用Proxy的源码进行配置,方便使用Navicat查看数据

(1)配置文件
(a)server.yaml
orchestration:
  registry:
    orchestrationType: registry_center,config_center,distributed_lock_manager
    instanceType: zookeeper
    serverLists: 127.0.0.1:2181
    namespace: sharding-namespace
    props:
      overwrite: true
      retryIntervalMilliseconds: 500
      timeToLiveSeconds: 60
      maxRetries: 3
      operationTimeoutMilliseconds: 500

authentication:
  users:
    root:
      password: root
    sharding:
      password: sharding
      authorizedSchemas: sharding_db

props:
  max.connections.size.per.query: 1
  acceptor.size: 16  # The default value is available processors count * 2.
  executor.size: 16  # Infinite by default.
  proxy.frontend.flush.threshold: 128  # The default value is 128.
    # LOCAL: Proxy will run with LOCAL transaction.
  # XA: Proxy will run with XA transaction.
  # BASE: Proxy will run with B.A.S.E transaction.
  proxy.transaction.type: LOCAL
  proxy.opentracing.enabled: false
  proxy.hint.enabled: false
  query.with.cipher.column: false
  sql.show: true
  allow.range.query.with.inline.sharding: false

(b)config-sharding.yaml
schemaName: scaling_db

dataSources:
  ds_0:
    url: jdbc:mysql://127.0.0.1:4406/mydb0?serverTimezone=UTC&useSSL=false
    username: root
    password: 111
    connectionTimeoutMilliseconds: 30000
    idleTimeoutMilliseconds: 60000
    maxLifetimeMilliseconds: 1800000
    maxPoolSize: 50
  ds_1:
    url: jdbc:mysql://127.0.0.1:4406/mydb1?serverTimezone=UTC&useSSL=false
    username: root
    password: 111
    connectionTimeoutMilliseconds: 30000
    idleTimeoutMilliseconds: 60000
    maxLifetimeMilliseconds: 1800000
    maxPoolSize: 50

shardingRule:
  tables:
    bill:
      actualDataNodes: ds_$->{0..1}.bill_scaling_$->{0..3}
      tableStrategy:
        inline:
          shardingColumn: id
          algorithmExpression: bill_scaling_$->{Long.parseLong(String.valueOf(id)) % 4}
      keyGenerator:
        type: SNOWFLAKE
        column: id
      databaseStrategy:
        inline:
          shardingColumn: bill_amount
          algorithmExpression: ds_$->{bill_amount % 2}
  defaultDataSourceName: ds_0
(c)Sharding-UI确认配置

process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMxNDU3NjY1,size_16,color_FFFFFF,t_70)

配置中心已经获取目标数据源的配置

(d)确认proxy的配置正确

通过navicat 链接proxy,测试

  • 插入
INSERT INTO `bill`(`id`, `bill_name`, `bill_amount`, `create_time`, `is_delete`) VALUES (1, 'test-bill', 106, '2020-12-27 13:14:00', 0);
INSERT INTO `bill`(`id`, `bill_name`, `bill_amount`, `create_time`, `is_delete`) VALUES (2, 'test-bill', 107, '2020-12-27 13:14:00', 0);
INSERT INTO `bill`(`id`, `bill_name`, `bill_amount`, `create_time`, `is_delete`) VALUES (3, 'test-bill', 108, '2020-12-27 13:14:00', 0);
INSERT INTO `bill`(`id`, `bill_name`, `bill_amount`, `create_time`, `is_delete`) VALUES (4, 'test-bill', 109, '2020-12-27 13:14:00', 0);

INSERT INTO `bill`(`id`, `bill_name`, `bill_amount`, `create_time`, `is_delete`) VALUES (5, 'test-bill', 110, '2020-12-27 13:14:00', 0);
INSERT INTO `bill`(`id`, `bill_name`, `bill_amount`, `create_time`, `is_delete`) VALUES (6, 'test-bill', 111, '2020-12-27 13:14:00', 0);
INSERT INTO `bill`(`id`, `bill_name`, `bill_amount`, `create_time`, `is_delete`) VALUES (7, 'test-bill', 112, '2020-12-27 13:14:00', 0);
INSERT INTO `bill`(`id`, `bill_name`, `bill_amount`, `create_time`, `is_delete`) VALUES (8, 'test-bill', 113, '2020-12-27 13:14:00', 0);

在这里插入图片描述
在这里插入图片描述
分库分表逻辑也正确。ok,新的proxy配置没问题。删除测试数据
在这里插入图片描述

4.启动Shading-Scaling

具体的启动参考官方文档,这里就不说了

5.使用Sharding-UI创建弹性伸缩任务

在这里插入图片描述

  1. 配置项的名字叫Source,即源数据的Schema.这样,源数据的配置中心数据就指定了
  2. 这个用户名及密码是配置的proxy的用户名密码
  3. 配置的时proxy的jdbc链接地址
  4. 同时启动的任务数,如果数据量比较大,增加这个参数会提高并行度

源数据的配置,通过Source配置项拿到了,目标数据配置,Proxy中定义了,这样,

  • Proxy就可以通过配置获取到源数据源的数据,然后将数据通过目标数据源配置,正确的写入到目标数据源
  • 对于增量数据,proxy使用了mysql的同步协议拉取源数据的binlog.获取到增量数据后,和上面一样写入到目标数据源

点击确认:
在这里插入图片描述
出现问题了

1.scaling 使用Integer接收id的bug

目前数据库中是我使用系统自带的雪花算法生成的id,结果:

在这里插入图片描述

毕竟是alpha项目,算了,也懒得改了,就直接更换我的老数据,使用int的数据

再次配置并确认:

在这里插入图片描述
在这里插入图片描述
ok,历史数据同步显示正确,再看看数据库
在这里插入图片描述
数据没有问题,历史数据确认ok了

2.同步的serviceId写死的bug

这个时候,观察scaling的日志发现下面这个问题:
在这里插入图片描述

Sharding Scaling增量同步阶段,会通过binlog的方式同步增量数据,而mysql有个机制,在slave订阅masterbinlog的时候,需要告诉master自己的service_uuid/service_id,且同一个master下,不同订阅者的service_uuid/service_id不能相同,否则后者相同的slave将无法正常建立主从同步。
-service_uuid是mysql初始化时生成的一串uuid,且生成后写入auto.conf,除非复制了已经启动的mysql,此时会导致uuid一样(我应该不是这种)
-service_id这个是协议中规定的,这个就要看scaling的参数传得是个啥了

查看源码,scaling在建立主从同步时,使用的serviceId是写死的12345(!!!)
在这里插入图片描述
好吧,修改源码,使用不同的id就好,使用源码启动。问题得到解决,增量同步也ok。圆满完成,后面的数据就不贴出来了

毕竟是alpha版本,就忍忍吧。当然,我遇到这个问题是因为,我定义的mydb0,mydb1在同一个数据库,如果分处在不同的数据库,这里写死的也不会出现这个问题。

6.规则切换阶段

通过设置数据库只读或ShardingSphere的熔断机制,让旧数据节点中的数据短暂静态,确保增量同步已完全完成。

这个窗口期时间短则数秒,长则数分钟,取决于数据量和用户是否需要对数据进行强校验。 确认完成后,Apache ShardingSphere 可通过配置中心修改配置,将业务导向新规则的集群,弹性伸缩完成

评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值