暂无图片
暂无图片
3
暂无图片
暂无图片
暂无图片

OceanBase 读写分离方案全攻略

2087

在企业数据库里有一种需求是读写分离,本文介绍 OB 的读写分离方案的部署和测试过程,希望可以减少分布式数据库选型时不必要的基本功能测试。读写分离听起来简单,实际内部设计还是有很多巧妙之处,刚学习完 OBCP 的 朋友们不妨也看看。

本文测试内容如下,有相应截图:

  • OCP 的安装部署

  • OB 集群部署

  • OB 只读副本部署及其只读访问测试

  • OB 只读副本和全功能副本的在线转换

  • OB 单副本备集群部署及其只读访问测试

机器准备

硬件资源

机器全部使用公有云 ECS,配置是 32c128G2T。

[root@observer00:/root/t-oceanbase-antman]# lscpuArchitecture:          x86_64CPU op-mode(s):        32-bit, 64-bitByte Order:            Little EndianCPU(s):                32On-line CPU(s) list:   0-31Thread(s) per core:    2Core(s) per socket:    16Socket(s):             1NUMA node(s):          1Vendor ID:             GenuineIntel<...>[root@observer00:/root/t-oceanbase-antman]# free -g              total        used        free      shared  buff/cache   availableMem:            125           1         104           0          19         118Swap:             0           0           0[root@observer00:/root/t-oceanbase-antman]# df -hFilesystem                     Size  Used Avail Use% Mounted on/dev/vda1                       50G   42G  5.1G  90% devtmpfs                        63G     0   63G   0% devtmpfs                           63G     0   63G   0% dev/shmtmpfs                           63G  820K   63G   1% runtmpfs                           63G     0   63G   0% sys/fs/cgroup/dev/mapper/ob_vg-ocp_home     296G  2.0G  279G   1% home/dev/mapper/ob_vg-docker_home  493G   73M  467G   1% docker/dev/mapper/ob_vg-ob_data      2.2T   85M  2.1T   1% data/1/dev/mapper/ob_vg-ob_log       504G   73M  479G   1% data/log1[root@observer00:/root/t-oceanbase-antman]#

机器初始化

机器初始化是很重要的一步,使用 OceanBase 提供的软件包t-oceanbase-antman-1.3.6-1917679.alios7.x86_64.rpm
 可以做一些自动化初始工作。
这部分不再重复描述。详情请参考 https://mp.weixin.qq.com/s/Q-4ksIRFWYa4xbl4Yccw1g
 以前的初始化步骤。

OCP 部署

ocp 的部署可以先参考 OceanBase 2.x 试用版安装体验——OCP 2.3 。

镜像文件准备

一共三个 docker 镜像文件,分别是 OBProxy、OCP、OceanBase。

[root@observer00:/root/t-oceanbase-antman]# ls -lrth *.gz-rw-r--r-- 1 126593 users 404M Jan  3 22:18 obproxy173.tar.gz-rw-r--r-- 1 root   root  688M Jan 17 14:02 ocp-all-in-one-2.5.0-x86.tar.gz-rw-r--r-- 1 root   root  1.4G Jan 17 14:09 OB2273_x86_20201214.tar.gz[root@observer00:/root/t-oceanbase-antman]#

加载镜像文件

[root@observer00:/root/t-oceanbase-antman]# for img in `ls *.gz`;do echo $img; docker load -i $img; doneOB2273_x86_20201214.tar.gz<...>Loaded image: reg.docker.alibaba-inc.com/antman/ob-docker:OB2273_x86_20201214obproxy173.tar.gz<...>Loaded image: reg.docker.alibaba-inc.com/antman/obproxy:OBP173_20200603_1923ocp-all-in-one-2.5.0-x86.tar.gz<...>Loaded image: reg.docker.alibaba-inc.com/oceanbase/ocp-all-in-one:2.5.0-1918031

查看镜像文件。不同版本的镜像文件在版本号上会有一点区别。注意看 tag 标签。镜像文件命名并不重要。实际版本以 tag 为准。

[root@observer00:/root/t-oceanbase-antman]# docker imagesREPOSITORY                                            TAG                    IMAGE ID            CREATED             SIZEreg.docker.alibaba-inc.com/oceanbase/ocp-all-in-one   2.5.0-1918031          2e635ca841b8        2 weeks ago         1.55GBreg.docker.alibaba-inc.com/antman/ob-docker           OB2273_x86_20201214    4da7b6c59465        5 weeks ago         2.89GBreg.docker.alibaba-inc.com/antman/obproxy             OBP173_20200603_1923   781b6520e237        7 months ago        1.15GB[root@observer00:/root/t-oceanbase-antman]#

OCP部署配置文件 obcluster.conf

下面直接给出关键的几个配置.
第一次跑的时候在 root/t-antman-oceanbase/ 下没有这个目录。执行脚本初始化一个 

[root@observer00:/root/t-oceanbase-antman]#sh init_obcluster_conf.sh
[root@observer00:/root/t-oceanbase-antman]# vim obcluster.conf## obcluster.conf##SINGLE_OCP_MODE=TRUE################################   根据环境必须修改  MUST CHANGE ACCORDING ENVIRONMENT   ############################################  填写机器IP和root/admin密码  Edit Machine IP and Password Of root/admin  ############ZONE1_RS_IP=172.23.152.220OBSERVER01_ROOTPASS=*******OBSERVER01_ADMINPASS=******SSH_PORT=22############  根据服务器CPU、内存设置容器资源编排  Allocate Container Resources According To Server  ############OB_docker_cpus=20OB_docker_memory=92GOCP_docker_cpus=6OCP_docker_memory=16GOBProxy_docker_cpus=2OBProxy_docker_memory=6G############  填写OCP各组件容器的版本信息  Edit Docker Image, Repo And Tag of OCP Components  ############# OB dockerdocker_image_package=OB2273_x86_20201214.tar.gzOB_image_REPO=reg.docker.alibaba-inc.com/antman/ob-dockerOB_image_TAG=OB2273_x86_20201214# OCP dockerocp_docker_image_package=ocp-all-in-one-2.5.0-x86.tar.gzOCP_image_REPO=reg.docker.alibaba-inc.com/oceanbase/ocp-all-in-oneOCP_image_TAG=2.5.0-1918031# OBPROXY dockerobproxy_docker_image_package=obproxy173.tar.gzobproxy_image_REPO=reg.docker.alibaba-inc.com/antman/obproxyobproxy_image_TAG=OBP173_20200603_1923

自动化安装

OCP的部署命令非常简单。只要机器环境没有问题,安装部署就是一个命令,自动过。

[root@observer00:/root/t-oceanbase-antman]# ./install.sh -i 1-run install.sh with DEBUG=FALSE, INSTALL_STEPS=1 2 3 4 5 6 7 8 CLEAR_STEPS= CONFIG_FILE=/root/t-oceanbase-antman/obcluster.conf[2021-01-23 15:51:01.148954] INFO [start antman API service]LB_MODE=none[2021-01-23 15:51:01.534776] INFO [step1: making ssh authorization, logfile: root/t-oceanbase-antman/logs/ssh_auth.log][2021-01-23 15:51:04.782001] INFO [step1: ssh authorization done][2021-01-23 15:51:04.792041] INFO [step2: no action is required when LB_MODE=none][2021-01-23 15:51:04.795448] INFO [step3: check whether OBSERVER port 2881,2882 are in use or not on 172.23.152.220][2021-01-23 15:51:09.462947] INFO [step3: OBSERVER port 2881,2882, 2022 are idle on 172.23.152.220][2021-01-23 15:51:09.466502] INFO [step3: installing ob cluster, logfile: root/t-oceanbase-antman/logs/install_ob.log][2021-01-23 15:51:35.760209] INFO [start container: docker run -d -it --name META_OB_ZONE_1 --net=host     -e OBCLUSTER_NAME=obcluster      -e DEV_NAME=eth0     -e ROOTSERVICE_LIST="172.23.152.220:2882:2881"     -e DATAFILE_DISK_PERCENTAGE=90     -e CLUSTER_ID=100000     -e ZONE_NAME=META_OB_ZONE_1     -e OCP_VIP=172.23.152.220     -e OCP_VPORT=8080     -e METADB_CLUSTER_NAME=obcluster     -e app.password_root=ro0T@20#Ra     -e app.password_admin=ro0T@20#Ra     -e OPTSTR="cpu_count=20,memory_limit=89G,__min_full_resource_pool_memory=1073741824,_ob_enable_prepared_statement=false,memory_limit_percentage=90"     --cpu-period 100000     --cpu-quota 2000000     --cpuset-cpus 0-19     --memory 92G     -v home/admin/oceanbase:/home/admin/oceanbase     -v data/log1:/data/log1     -v data/1:/data/1     -v backup:/backup     --restart on-failure:5     reg.docker.alibaba-inc.com/antman/ob-docker:OB2273_x86_20201214]0dbbc671f4cbf3792067e64eade064a397f46cacabd65af63de699826c4d940c[2021-01-23 15:51:35.971611] INFO [installing OB docker and starting OB server on 172.23.152.220, pid: 19062, log: root/t-oceanbase-antman/logs/install_OB_docker.log and home/admin/logs/ob-server/ inside docker][2021-01-23 15:51:39.090756] INFO [install_OB_docker.sh finished and reg.docker.alibaba-inc.com/antman/ob-docker:OB2273_x86_20201214 started on 172.23.152.220][2021-01-23 15:51:39.094245] INFO [waiting on observer ready on 172.23.152.220][2021-01-23 15:54:39.103957] INFO [waiting on observer ready on 172.23.152.220 for 3 Minitues][2021-01-23 15:55:39.114452] INFO [waiting on observer ready on 172.23.152.220 for 4 Minitues][2021-01-23 15:55:39.504591] INFO [observer on 172.23.152.220 is ready][2021-01-23 15:55:39.514450] INFO [observer installation on all hosts done][2021-01-23 15:55:39.521402] INFO [Now, start bootstrap on 172.23.152.220: alter system bootstrap REGION "OCP_META_REGION" ZONE "META_OB_ZONE_1" SERVER "172.23.152.220:2882"][2021-01-23 15:56:59.700068] INFO [bootstrap done, observer now ready][2021-01-23 15:56:59.710201] INFO [major_freeze start][2021-01-23 15:57:59.759744] INFO [major_freeze done][2021-01-23 15:57:59.763844] INFO [step3: installation of ob cluster done][2021-01-23 15:57:59.767362] INFO [step4: initializing ocp metadb, logfile: root/t-oceanbase-antman/logs/init_metadb.log][2021-01-23 15:58:04.640267] INFO [step4: initialization of ocp metadb done][2021-01-23 15:58:04.643938] INFO [step5: check whether OCP port 8080 is in use or not on 172.23.152.220][2021-01-23 15:58:06.202247] INFO [step5: OCP port 8080 is idle on 172.23.152.220][2021-01-23 15:58:06.206098] INFO [step5: installing temporary ocp, logfile: root/t-oceanbase-antman/logs/install_tmp_ocp.log][2021-01-23 15:58:26.476181] INFO [ob server is ready on host 172.23.152.220][2021-01-23 15:58:26.625129] INFO [init metadb: docker run --net host --workdir=/home/admin/ocp-init/src/ocp-init --entrypoint=python reg.docker.alibaba-inc.com/oceanbase/ocp-all-in-one:2.5.0-1918031 create_metadb.py 172.23.152.220 2881 root@ocp_meta X21FRlH9{@ ocp root@ocp_monitor ^I4SH6HsU@ ocp_monitor]create_metadb.py:356: YAMLLoadWarning: calling yaml.load() without Loader=... is deprecated, as the default Loader is unsafe. Please read https://msg.pyyaml.org/load for full details.  data = yaml.load(file)<...>[root@observer00:/root/t-oceanbase-antman]#[root@observer00:/root/t-oceanbase-antman]# docker psCONTAINER ID        IMAGE                                                               COMMAND                  CREATED             STATUS              PORTS               NAMES5333a8797e7b        reg.docker.alibaba-inc.com/oceanbase/ocp-all-in-one:2.5.0-1918031   "/usr/bin/supervisor…"   7 minutes ago       Up 7 minutes                            ocp60bd06244095        reg.docker.alibaba-inc.com/antman/obproxy:OBP173_20200603_1923      "sh start_obproxy.sh"    8 minutes ago       Up 8 minutes                            obproxy0dbbc671f4cb        reg.docker.alibaba-inc.com/antman/ob-docker:OB2273_x86_20201214     "/usr/bin/supervisor…"   20 minutes ago      Up 20 minutes                           META_OB_ZONE_1[root@observer00:/root/t-oceanbase-antman]#

如果安装报错了,就把报错的步骤 回滚掉 -c
 。

OB 集群部署

部署规划

目标:

  • 部署一个 1-1-1 的 OB 集群。

  • 部署一个只读副本。

  • 部署一个单副本备集群。

主机名IPREGIONIDCZone备注
observer01172.23.152.221RG1IDC1ZONE_1OB 主副本
observer02172.30.118.66RG1IDC2ZONE_2OB 备副本
observer03172.30.118.67RG2IDC3ZONE_3OB 备副本
observer04172.26.154.55RG2IDC22ZONE_4OB 只读副本
observer05172.26.154.54RG3IDC4ZONE_1OB 备集群单副本

注意:这里的 REGION 和 IDC 信息都是特别设计的,后面可以看到效果。

做到后面发现这里的 IDC22 应该命名为 IDC33 更贴切一些。不过不好调整了。在实际生产环境里,IDC22 跟 IDC3 通常是同一个物理机房或者同一个城市,属于同一个 REGION。

机器资源池录入

  • 新增机型

  • 新增凭据

  • 新增机房

  • 添加主机

重复添加所有主机后,OCP 管理的机器资源如下:

部署 OB 集群

注意,选机器的时候,ZONE、IDC、IP 都要跟规划一致。

  • 可选:指定一些 OB 集群参数。

这些参数是常用的,性能测试时会有用。不是必须的。有关参数介绍请参考:OB 开发测试建议 (中)

提交后生成安装任务。

OceanBase 集群的自动化安装任务相比手动安装是更严谨一些,这符合企业级数据库运维平台的基本要求。子任务切分很细,并且有很多环境检查准备等工作。OCP 提供了图形化的进度浏览。多个节点能同时安装。

OceanBase 集群的安装时间绝大部分都是这一步任务的时间。这一步是为了测试主机上 IO 的综合能力,然后生成一个文件 `/home/admin/oceanbase/etc/io_resource.conf 。

[admin@observer01:/home/admin]# ps -ef|grep ob_adminadmin     7002  6963 99 17:47 ?        00:08:40 home/admin/oceanbase/bin/ob_admin io_bench -c home/admin/oceanbase/etc -d data/1/obdemoadmin    10848  5779  0 17:49 pts/0    00:00:00 grep --color=auto ob_admin[admin@observer01:/home/admin]#

部署 OBProxy 集群

给业务部署一个 OBProxy,用于业务读写。由于测试环境我没有 VIP,所以这里集群的 IP 填写了第一个后端 OBProxy 的 IP。

创建 OB 租户

新建 OB 的 ORALCE 租户

OCP 可以创建租户,选择兼容 MySQL 或者 ORACLE。这个细节就不重复了。

初始化 ORACLE 租户数据

这里用 BenchmarkSQL 工具初始化 TPCC 场景数据。

vim props.obdb=oceanbasedriver=com.alipay.oceanbase.obproxy.mysql.jdbc.Driverconn=jdbc:oceanbase://172.30.118.66:2883/tpcc?useAffectedRows=true&emulateUnsupportedPstmts=false&characterEncoding=utf8&enableQueryTimeouts=false&useLocalSessionState=false&useLocalTransactionState=false&rewriteBatchedStatements=true&allowMultiQueries=true&socketTimeout=600000user=tpcc@oboracle01#obdemopassword=123456warehouses=100loadWorkers=10

OB 只读副本部署

新增一个 ZONE

在集群 obdemo
的管理界面里点击“新增 Zone”,选一个机器,用于只读副本。

新增一个只读副本

在租户里新增一个副本,类型选择“只读副本”。

OB 单副本备集群部署

新建备集群

在集群 obdemo
 的集群管理界面,点击“新建备集群”。

新建备集群的任务里面也会有 IO 测试,bootstrap
 操作。搭建备集群并不是增加一个备副本,而是搭建一个独立的 OB 集群。

新增 OBProxy

新增一个 OBProxy 访问只读副本。

目前 OCP 还不支持创建 2 个 OBProxy 集群关联到一个 OB 集群。所以这个 OBProxy 暂时只能手动创建。

OBProxy 启动的时候指定 obconfig_url
 。

需要取这个值中的 IP 和端口部分,替换下面参数中的 IP和端口。

[admin@observer04:/opt/taobao/install/obproxy]# cd opt/taobao/install/obproxy && bin/obproxy -p2883 -cobdemo -o "obproxy_config_server_url=http://172.23.152.220:8080/services?Action=GetObProxyConfig&User_ID=alibaba-inc&uid=ocpmaster,proxy_idc_name=IDC22"bin/obproxy -p2883 -cobdemo -o obproxy_config_server_url=http://172.23.152.220:8080/services?Action=GetObProxyConfig&User_ID=alibaba-inc&uid=ocpmaster,proxy_idc_name=IDC22listen port: 2883cluster_name: obdemooptstr: obproxy_config_server_url=http://172.23.152.220:8080/services?Action=GetObProxyConfig&User_ID=alibaba-inc&uid=ocpmaster,proxy_idc_name=IDC22[admin@observer04:/opt/taobao/install/obproxy]# ps -ef|grep obproxyadmin     6761     1 30 19:31 ?        00:00:01 bin/obproxy -p2883 -cobdemo -o obproxy_config_server_url=http://172.23.152.220:8080/services?Action=GetObProxyConfig&User_ID=alibaba-inc&uid=ocpmaster,proxy_idc_name=IDC22admin     7192 31451  0 19:31 pts/0    00:00:00 grep --color=auto obproxy[admin@observer04:/opt/taobao/install/obproxy]#

注意:备副本的 OBPROXY 我在启动的时候特地指定了 proxy_idc_name=IDC22
这个参数。当通过这个 OBPROXY 发起弱一致性读
时,会按下面顺序路由:

  • 同一个 IDC 下的备副本所在的 OBSERVER 节点。

  • 同一个 REGION 下的其他 IDC 下的备副本所在的 OBSERVER 节点。

  • 其他 REGION 下的备副本所在的 OBSERVER 节点

集群拓扑

  • 主集群视角的拓扑

  • 备集群视角的拓扑

也可以在集群里通过 SQL 确认:

select t1.name resource_pool_name, t3.unit_id, t2.`name` unit_config_name, t2.max_cpu, t2.min_cpu, round(t2.max_memory/1024/1024/1024) max_mem_gb, round(t2.min_memory/1024/1024/1024) min_mem_gb, t3.unit_id, t3.zone, concat(t3.svr_ip,':',t3.`svr_port`) observer,t4.tenant_id, t4.tenant_namefrom __all_resource_pool t1 join __all_unit_config t2 on (t1.unit_config_id=t2.unit_config_id)    join __all_unit t3 on (t1.`resource_pool_id` = t3.`resource_pool_id`)    left join __all_tenant t4 on (t1.tenant_id=t4.tenant_id)order BY t1.tenant_id ,t1.`resource_pool_id`, t2.`unit_config_id`, t3.unit_id;SELECT * FROM __all_zone WHERE name IN ('region','idc');

测试验

确认集群租户资源分布

这个不是必须的。只是顺道展示一下 OCP 新增的功能。也方便大家对只读副本的理解。

确认表(分区)的位置

以表bmsql_item
为例。这是个单表。

运行下面 SQL 查询这个表分区的位置

SELECT  t.tenant_id, a.tenant_name, d.database_name, t.table_name,  tg.tablegroup_name , t.part_num , t2.partition_id, t2.ZONE, t2.svr_ip, t2.ROLE, t2.data_size    , a.primary_zone      , IF(t.locality = '' OR t.locality IS NULL, a.locality, t.locality) AS locality   FROM oceanbase.__all_tenant AS a      JOIN oceanbase.__all_virtual_database AS d ON ( a.tenant_id = d.tenant_id  )     JOIN oceanbase.__all_virtual_table AS t  ON (t.tenant_id = d.tenant_id AND t.database_id = d.database_id)       JOIN oceanbase.__all_virtual_meta_table t2 ON (t.tenant_id = t2.tenant_id AND (t.table_id=t2.table_id OR t.tablegroup_id=t2.table_id)  AND t2.ROLE IN (1,2) )    LEFT JOIN oceanbase.__all_virtual_tablegroup AS tg ON (t.tenant_id = tg.tenant_id and  t.tablegroup_id = tg.tablegroup_id) WHERE a.tenant_id IN (1001 ) AND  t.table_type IN (3)   AND d.database_name LIKE '%TPCC%'AND t.table_name IN ('BMSQL_ITEM');

从图中看表bmsql_item
的主副本在 221 上,其他节点都是备副本。

确认 SQL 路由节点的方法

OceanBase 里所有的 SQL 都会在sys
租户的内部视图gv$sql_audit
里记录。这个对排查问题非常方便。
下面语句是根据 SQL 文本查询执行信息

SELECT /*+ read_consistency(weak) ob_querytimeout(100000000) */ substr(usec_to_time(request_time),1,19) request_time_, s.svr_ip, s.client_Ip, s.sid, s.plan_type,  s.query_sql, s.affected_rows, s.return_rows, s.ret_codeFROM gv$sql_audit sWHERE  s.tenant_id=1001  AND user_name LIKE '%TPCC%'  AND query_sql LIKE '%TEST_RO%'ORDER BY request_time DESCLIMIT 10;

其中

  • client_ip
     是 SQL 在 OceanBase 集群视角的客户端 IP。如果客户端是通过 OBPROXY 访问 OB,那么这个地址通常就是 OBPROXY 的地址。

  • svr_ip
     是 SQL 被路由到 OceanBase 集群的节点 IP。通常是 SQL 访问分区的主副本 IP,不过有时候也不是。这个跟 OBPROXY 路由策略有关。这个以后可以独立成篇去介绍。

  • plan_type
     是 SQL 的执行类型。1:表示在该节点(指svr_ip
    )本机执行;2:表示是发送到其他节点远程执行。发送到哪个节点这里看不到(通常是指发送到分区主副本节点);3 表示是这个 SQL 是个分布式执行计划,会涉及到多个分区。有可能这些分区还跨节点了。

所以,上图的解释是这个 SQL 从 55 这个 IP 路由到 55 这个节点。由于访问的表的主副本不在这个节点,所以又再次路由到其他节点(实际是主副本所在节点,即 221 )。

业务读写验证

前面的 TPCC 场景的数据初始化使用的就是第一个 OBProxy 集群,包含读写操作。

首先我们看有一个实时读写的单表 SQL 会被路由到哪个节点。测试 SQL 类似

select /*+ test_rw */ count(*) cnt from bmsql_item\G

注意:/*+ */ 是 SQL 的注释语法,也是 HINT 语法。 test_rw
不是标准的 SQL HINT,所以会被 SQL 引擎忽略。写在这里只是为了标记这个 SQL,方面后面从 SQL 审计视图里定位到这个 SQL。

为了简化情况,让下面的测试案例可以复现。请严格按照测试方法做。每次执行 SQL 时都重新连接。不要复用老的连接。

开始测试,通过 observer02 上的 OBPROXY 连接集群看看。然后换 observer01 上的 OBPROXY 连接集群看看。

[root@observer00:/root]# obclient -hobserver02 -utpcc@oboracle01#obdemo -P2883 -p123456 -s -e "select *+ test_rw_10 */ count(*) cnt from bmsql_item\G "obclient: [Warning] Using a password on the command line interface can be insecure.*************************** 1. row ***************************CNT: 100000[root@observer00:/root]# obclient -hobserver01 -utpcc@oboracle01#obdemo -P2883 -p123456 -s -e "select *+ test_rw_10 */ count(*) cnt from bmsql_item\G "obclient: [Warning] Using a password on the command line interface can be insecure.*************************** 1. row ***************************CNT: 100000

看 SQL 审计结果

所以,无论从哪个 OBPROXY 链接 OB 集群,通常单表 SQL 最后都会被路由到该表主副本所在的节点。这种路由规则叫强一致性读

本项验证的目的已经达到。下面演示弱一致性读
的路由规则。弱一致性读只允许就近读取备副本。需要指定 HINT (read_consistency(weak)
 或者在会话级别设置。

select /*+ read_consistency(weak) test_rw_13 */ count(*) cnt from bmsql_item\G

观察 SQL 路由信息

注意: SQL 审计视图按时间顺序是从下往上看。

从图中可以看出,如果选择备副本所在节点的 OBPROXY 连接 OB 集群,它就转发给本地的 OBSERVER 节点了,然后 SQL 也是本地执行(plan_type
=1)。如果选择主副本所在节点的 OBPROXY 连接 OB 集群,它就随机转发给同一个 REGION 的 OBSERVER 节点。

除了用 SQL HINT 外,还有个办法就是通过 SESSION 变量来设置弱一致性读

[root@observer00:/root]# obclient -hobserver01 -utpcc@oboracle01#obdemo -P2883 -p123456  -s -e "set session ob_read_consistency=weak; select *+ test_rw_14 */ count(*) cnt from bmsql_item\G"obclient: [Warning] Using a password on the command line interface can be insecure.*************************** 1. row ***************************CNT: 100000[root@observer00:/root]# obclient -hobserver02 -utpcc@oboracle01#obdemo -P2883 -p123456  -s -e "set session ob_read_consistency=weak; select *+ test_rw_14 */ count(*) cnt from bmsql_item\G"obclient: [Warning] Using a password on the command line interface can be insecure.*************************** 1. row ***************************CNT: 100000[root@observer00:/root]#

弱一致性读通常用于少量的读写分离
场景。对于大量的读写分离需求,或者为了绝对不影响主副本的读写,那推荐使用只读副本。

只读副本访问验证

只读副本主要用于读写分离场景。对于一些业务上能接受些许延时的查询,可以访问“只读副本”减轻主副本的压力。只读副本的访问也必须使用弱一致性读

下面就验证只读副本的访问是否真的会路由到只读副本的节点。为了便于理解,我加了一些强一致性读进行对比。

obclient -h172.23.152.221 -utpcc@oboracle01#obdemo -P2883 -p123456  -s -e "select *+ test_ro_28 */ count(*) cnt from bmsql_item\G"obclient -h172.23.152.221 -utpcc@oboracle01#obdemo -P2883 -p123456  -s -e "set session ob_read_consistency=weak; select *+ test_ro_28 */ count(*) cnt from bmsql_item\G"obclient -h172.26.154.55 -utpcc@oboracle01#obdemo -P2883 -p123456  -s -e "select *+ test_ro_28 */ count(*) cnt from bmsql_item\G"obclient -h172.26.154.55 -utpcc@oboracle01#obdemo -P2883 -p123456  -s -e "set session ob_read_consistency=weak; select *+ test_ro_28 */ count(*) cnt from bmsql_item\G"

注意: SQL 审计视图按时间顺序是从下往上看。

从上图可以看出,发往只读副本所在节点的 OBPROXY(这个 OBPROXY 启动时指定了特别的 IDC 参数,见前面说明)的弱一致性读,会路由到同一个 IDC 下的 OBSERVER 节点(也是本机节点,测试环境受限就这么巧),而不是随机到其他备副本节点。这就是只读副本的目的。

同时也看出,发往只读副本所在节点的 OBPROXY 的强一致性读,还是会被路由到主副本所在的节点。这个就是 OB 的只读副本跟其他分布式数据库主从读写分离方案最大的不同。OB 绝对不会出现错误的写了只读副本(双写)。
然而 OB 更特殊的优势还在只读副本故障时的情形。

只读副本故障后验证

通常模拟故障就是直接登录节点 杀掉 OBSERVER 进程。最近 OCP 增加了停止节点的功能,这里就顺便演示一下。(以前有客户吐槽 OB 不能停机,现在可以了 😆)

同样的,停 OBSERVER 节点也会生成一个任务,并且拆分为很多原子任务。这个过程会比我直接 KILL 节点要长很多。这是因为 OCP 选择了一种严谨的稳妥的步骤。

确认节点状态

select a.zone,concat(a.svr_ip   ,':',a.svr_port) observer, usec_to_time(b.last_offline_time) last_offline_time, usec_to_time(b.start_service_time) start_service_time, b.status, b.with_rootserver from __all_virtual_server_stat a     join __all_server b on (a.svr_ip=b.svr_ip and a.svr_port=b.svr_port)
order by a.ZONE, a.svr_ip
;



再跑弱一致性验证

obclient -h172.23.152.221 -utpcc@oboracle01#obdemo -P2883 -p123456  -s -e "select /*+ test_ro_29 */ count(*) cnt from bmsql_item\G"

obclient -h172.23.152.221 -utpcc@oboracle01#obdemo -P2883 -p123456 -s -e "set session ob_read_consistency=weak; select /*+ test_ro_29 */ count(*) cnt from bmsql_item\G"

obclient -h172.26.154.55 -utpcc@oboracle01#obdemo -P2883 -p123456 -s -e "select /*+ test_ro_29 */ count(*) cnt from bmsql_item\G"

obclient -h172.26.154.55 -utpcc@oboracle01#obdemo -P2883 -p123456 -s -e "set session ob_read_consistency=weak; select /*+ test_ro_29 */ count(*) cnt from bmsql_item\G"



从图中可以看出,当只读副本不可访问时,原弱一致性读的 SQL 会被路由到同一个 REGION(RG2)的其他 IDC(IDC3) OBSERVER 节点。

也就是说即使只读副本故障了,那些只读查询业务也不会受影响(OBPROXY 会迅速把路由切换到其他候选的备副本所在 OBSERVER 节点)。这点也是 OB 跟其他分布式数据库中间件读写分离最大的不同。尽管后者也可以通过高可用 agent 去判断只读实例故障然后更改各个备实例的读写权重。读写权重那个设置是全局层面的,无法按业务切分。


只读副本跟全功能备副本之间的在线转换

OceanBase 更特别的地方就是只读副本跟全功能副本可以在线转换。


上图是编辑Zone3 的全功能副本,改为只读副本。也可以改 Zone4 的只读副本为全功能副本。基本上 1 分钟就生效。

任务图如下:



最终结果如下:


只读副本和全功能副本的在线转换这个能力,通常用于 OceanBase 集群在线跨机房跨城市搬迁。支付宝每年双11 大促前后常做这种在线搬迁。


备集群的访问

OB 现在也支持主备集群架构(DATAGUARD)。备集群的使用详情以后再接受,这里只展示一下备集群的访问。

首先备集群的访问跟主集群一样,只是集群名字后面多了一个 :2



上图: obdemo:1
是主集群,obdemo:2
是备集群。

备集群访问方式:

obclient -h172.26.154.55 -utpcc@oboracle01#obdemo:2 -P2883 -p123456  -s -e "set session ob_read_consistency=weak; select /*+ test_ro_30 */ count(*) cnt from bmsql_item\G"

obclient -h172.26.154.55 -utpcc@oboracle01#obdemo:2 -P2883 -p123456 -s -e "select /*+ test_ro_30 */ count(*) cnt from bmsql_item\G"



注意:备集群只能读不能写,并且这个读必须是弱一致性读

通常主集群的任意一个 OBPROXY 也可以访问备集群。

下面是上面 SQL 在备集群的 SQL 审计视图里的路由信息。




总结


综上所述,OB 的读写分离有三种方案:

  • 三副本或者五副本架构下,个别 SQL 通过弱一致性读 HINT 或者会话设置,就近只读备副本。

  • 三副本或五副本架构下,额外增加一个或多个只读副本,为只读副本配置单独的 OBPROXY ,只读业务走这个 OBPROXY 专门访问只读副本。

  • 为 OB 集群搭建一个备集群,可以是单副本或者三副本。只读业务专门访问备集群。


至于要选择哪种方案呢,还是要看“读写分离”的目的。想在什么范围内隔离只读查询对读写业务的影响,决定了选择哪种方案更合适。

OB 读写分离方案的优势有两点:

  • 无论什么状况都不用担心误写了“备副本或只读副本”,因为它不支持写,写操作会被路由到主副本。(当然备集群那个例外,不能跨集群路由)。

  • 无论什么时候都不用担心“备副本或只读副本”故障了,因为 OBPROXY会就近路由到其他备副本。(当然单副本备集群不能,如果要防范这个风险,就搭建三副本备集群就行,自身有高可用)。


用惯了 ORACLE 的 ADG 或者 MySQL 的主从读写分离的,可能会觉得 OB 的读写分离方案复杂。这个就需要转变观念了。读写分离方案严格的说要考虑各种异常情况,OB 把这些异常都做到内部去了,但对用户使用是极其方便的,对运维的工作也是很友好的。当企业的数据库机器规模成百上千后,企业级的自动化运维平台应该长什么样呢?命令行下脚本运维肯定是不行,自动化任务失败率过高时也是不行。

小提示:仅仅通过 OCP 完成只读副本和备集群搭建还不算真正掌握这个能力,其背后具体的操作步骤(尤其是 SQL)才是关键,感兴趣的朋友,可以在任务列表里下载这些任务的日志进行详细研究。 HAVE FUN 😆!


参考

文章转载自OceanBase技术闲谈,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论