本文以搭建阿里云双机房数据访问代理(ODP)实例访问 OceanBase 为例,介绍如何使用阿里云双机房下的 ODP。
本文以上海非金区(华东 2)为例,其他地域的操作步骤类似。
示例背景
部署拓扑:应用部署于上海非金可用区 A 与可用区 C,每个可用区的应用承载 50 个分片的流量(依赖流量调拨);同时创建部署于可用区 A 与可用区 C 的 ODP 实例(分别映射到可用区 A 与可用区 C 的交换机),应用连接当前可用区内的 ODP 实例。
数据拓扑:共分 100 个分片,即百库百表。使用公有云 OceanBase 的单集群双租户,每个租户分配 50 分片。其中,第一个租户的主可用区设置为可用区 A,分配前 50 分片;第二个可用区的主可用区设置为可用区 C,分配后 50 分片。
前 50 分片的 leader 所在可用区 A 宕机后,OB 会将该 50 分片的 leader 切换至可用区 B
此时,前 50 分片的流量会调拨给 A 可用区内的应用,应用连接当前可用区 A 的 ODP(未产生跨机房),ODP 会连接主可用区在可用区 A 的 OceanBase 租户,访问该租户内的前 50 个分片物理库表(同样未产生跨机房)。
现实情况中,由于上海非金地域中 ODP 实例仅支持可用区 A、C、D,暂时不支持部署在可用区 E、F、G,而 OceanBase 目前仅支持机房 E、F、G 作为主可用区,因此暂时匹配不上,从而出现跨机房访问。
对于三可用区的 OB 集群而言,每个可用区均分布一台 OBServer。在主可用区为 A 的租户中创建的所有分区,其 leader 均为可用区 A;如某个分区的 leader 为可用区 A,则读写该分区时都默认访问位于可用区 A 的 OBServer。
前 50 分片的 leader 所在可用区 A 宕机后,OB 会将该 50 分片的 leader 切换至可用区 B,并且应用流量也会全部调拨到可用区 B。此时,依然可以为 100 个分片提供数据访问服务(OB 多副本机制)。
前置条件
开通数据访问代理(ODP)组件服务。
在华东 2(上海)地域创建一个专有网络 VPC,并在上海可用区 A 和可用区 C 分别创建一个虚拟交换机 vSwitch。详见 搭建专有网络。
购买 ODP 实例
登录 ODP 控制台页面,左侧导航栏选择 实例,单击 创建实例。
在实例购买页面,选择地域、可用区、实例规格以及类型等。
地域:选择华东2(上海)。
可用区:选择上海非金可用区-A。
实例规格:选择 8 核 16 GB。
类型:选择 OceanBase。
专有网络:选择之前创建好的 VPC。
虚拟交换机:选择位于上海可用区 A 的虚拟交换机实例 ID。
说明请尽量选择 ODP 实例所在可用区的虚拟交换机。如果 ODP与应用不在同一可用区,或者 ODP 没有映射到应用所在可用区的虚拟交换机,应用访问 ODP 时则需要进行跨可用区访问,将会导致较高的延时问题。
单击 立即购买 进入购买预览页面。
确认订单信息无误并阅读产品服务条款后,勾选 数据访问代理服务协议,单击 去开通 完成购买。
在购买成功后的提示页面,单击 管理控制台 返回 ODP 实例列表,可以看到刚刚创建的 ODP 实例。
单击该实例 ID 进入其详情页,您可以看到已有的一个机房,单击详情页右上角的 添加机房,为该逻辑实例添加第二个机房。
在新页面中,选择当前地域的另外一个可用区,如 上海非金可用区-C,且虚拟交换机也需选择位于可用区 C 的虚拟交换机实例 ID。
购买后,返回该实例详情页,即可看到已存在两个机房。此时,该逻辑实例便对应了两个物理实例(即逻辑实例在某一个机房中的真实实例),分别部署在上海非金可用区 A 和上海非金可用区 C,两个物理实例共享相同的元信息配置。
添加物理数据节点
登录 OceanBase 管理控制台,创建一个集群与两个租户,并设置主可用区分别为 华东 2(上海)可用区 E 和 F。详见 创建集群 与 创建租户。
将 ODP 地址加入到该 OceanBase 集群的白名单中:
在 ODP 控制台 > 运维 > 物理数据节点 页面,点击 添加节点,在弹出窗口中,获取 数据访问代理地址。
返回 OB 集群工作台,单击 集群白名单 栏旁边的编辑图标,添加该 ODP 地址。
为该 OB 集群下的两个租户分别创建一个超级账号。详见 新建账号。
返回 ODP 控制台 > 运维 > 物理数据节点 页面,分别添加两个租户的数据节点。
物理数据节点 ID:格式为
masterintranet + 租户 ID
,如masterintranett22okxxxxxxxx
。链接地址:输入该物理数据节点的访问地址。
数据库类型:选择 OceanBase。
网络类型:选择 专有网络。
VPC ID:输入物理节点所在专有网络 VPC 的 ID。
添加完成后,在物理数据节点列表,即可看到这两个节点。
创建逻辑库与物理库
进入 ODP 控制台 > 数据库 页面,单击 创建数据库。
在弹出的 创建数据库 窗口中,选择正确的 ODP 实例,单击 创建。
在 选择数据节点 页面,选择刚刚添加的两个物理数据节点。
单击 下一步,根据提示,填写或选择基本信息。根据本文的示例场景,需将 物理分库数 设置为 100,如下图所示。
单击 下一步,进入建库预览,确认各项信息无误后,选择 所有数据节点使用不同账号,并为两个数据节点配置账号信息,如下图所示。
信息确认完毕,单击 创建 开始创建数据库。
进入该数据库详情页,您可以查看到对应可用区-A(实际为 E)的租户承载前 50 分片,对应可用区-C(实际为 F)的租户承载后 50 分片。
创建逻辑表与物理表
在刚刚创建的数据库详情页,单击右侧页面下方的 新增数据表。
进入创建数据表向导,填写或选择各项数据表信息,勾选 现在创建物理表,并点击 下一步。示例:以 user 表为例,创建拆分表,分表数为 100,分表规则为 MySQL 风格的字符串截断(-2 ~ 2),即取
user_id
字符串的最后两位作为sharding_key
(分库分表位)。输入 DDL 语句来进行创建数据表,单击 执行。
返回数据库详情页,单击右上角的 配置生效,并 确定。
应用连接逻辑库
在业务 VPC 内,您可以直接使用内网地址访问 ODP。您也可以申请公网地址,然后在本地通过 MySQL CLI 来访问 ODP。
使用逻辑库中的 MYSQL 客户端命令行命令,即可访问某个可用区的 ODP 实例中的逻辑库。
执行 show topology from $tableName
,即可查看某张逻辑表的拓扑结构,如下图所示。
应用可以通过 dbp-connector 较为便捷地访问双机房 ODP。详细的配置方法,可参见 配置同城双活模式。
配置时,需要特别注意以下几点:
在引入 dbp-connector 的依赖时,版本号必须是 1.1.1 及以上。
在配置连接池时,
url
配置的格式为jdbc:mysql://${阿里云 ODP 实例 ID}@zone@.sofaodp.aliyuncs.com:8306/${数据库名称}
。<bean id="simpleDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://${yourDbpInstanceId}@zone@.sofaodp.aliyuncs.com:8306/${yourDatabase}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </bean>
配置与访问示例
修改 Spring 文件。本文示例如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd" default-autowire="byName"> <bean id="dbpDiscovery"class="com.alipay.sofa.dbp.discovery.DbpDiscovery"/> <bean id="simpleDataSourceConnector"class="com.alipay.sofa.dbp.DbpDataSource" init-method="init"> <property name="delegate" ref="simpleDataSource"/> <property name="appName" value="ldc_demo_app"/> <property name="database" value="ldc_demo"/> <property name="dbpInstanceId" value="sofaodp-l8eh5cdite4w"/> <property name="clientTracer" ref="clientTracer"/> </bean> <!-- dataSource pool --> <bean id="simpleDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <!-- 这里为了本地测试使用了公网域名,实际应用部署时应该使用内网域名,即不带public --> <property name="url" value="jdbc:mysql://sofaodp-lxxxxxxxtest@zone@.public.sofaodp.aliyuncs.com:8306/ldc_demo"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </bean> <bean id="clientTracer" class="com.alipay.sofa.dbp.DbpClientTracer"> <!-- 设置客户端日志才样的阈值,默认3ms(3ms内成功的sql按10%采样),设置为0 全部打印 --> <property name="sampleThreshold" value="3"/> </bean> </beans>
在应用代码(以 Java 为例)中,测试插入一条位于 23 分片的记录,然后查询该条记录。示例如下:
public class DbpConnectorAliyunTest extends AbstractTestBase{ @Autowired @Qualifier("simpleDataSourceConnector") private DataSource dataSource; static{ // 应用部署时,发布部署系统会自动为您注入此系统变量为当前可用区,无需手动设置,此处仅为演示 System.setProperty("com.alipay.ldc.datacenter","cn-shanghai-a"); } @Test public void test() throws SQLException{ // user_id的最后两位为分片值,即当前这条数据要落到23分片 String userId ="随机生成的数字串23"; String username ="user23"; String insertSql ="insert into user (id, user_id, username) values (?, ?, ?)"; Connection connection = dataSource.getConnection(); PreparedStatement insertStmt = connection.prepareStatement(insertSql); insertStmt.setInt(1,0); insertStmt.setString(2, userId); insertStmt.setString(3, username); insertStmt.executeUpdate(); insertStmt.close(); String querySql ="select username from user where user_id = ?"; PreparedStatement queryStmt = connection.prepareStatement(querySql); queryStmt.setString(1, userId); ResultSet resultSet = queryStmt.executeQuery(); resultSet.next(); Assert.assertEquals(username, resultSet.getString(1)); } }
连接至物理库,验证数据路由的正确性。