1,读写分离与实时主备的区别
和实时主备非常相似,部署过程主要有两个区别:
(1)归档方式
(2)配置文件dm_svc.conf
1.1,归档方式
dmarch.ini文件中,归档方式不同,读写分离是TIMELY即时归档,实时主备是REALTIME实时归档,主备节点的dmarch.ini文件都要修改
#dmarch.ini
[ARCHIVE_TIMELY1]
ARCH_TYPE = TIMELY #实时归档类型
ARCH_DEST = CHENx #实时归档目标实例名
[ARCHIVE_LOCAL1]
ARCH_TYPE = LOCAL #本地归档类型
ARCH_DEST = /home/dmdba/dmarch #本地归档文件存放路径
ARCH_FILE_SIZE = 128 #单位 Mb,本地单个归档文件最大值
ARCH_SPACE_LIMIT = 4096 #单位 Mb, 0 表示无限制,必须改成非0
1.2,配置文件dm_svc.conf
在客户端上配置,比如在CHEN3机器上远程登录CHEN1实例,就需要在CHEN3机器上修改dm_svc.conf配置文件。
一般在安装数据库时会生成,Linux服务器上该文件存在目录/etc下面,如果/etc下没有dm_svc.conf就手动创建一个。
该文件中包含 DM 各接口及客户端需要配置的一些参数。
其中服务名的作用是可以在url串中替代IP地址连接整个集群,可以根据需要,设置成别的名字。
#dm_svc.conf
TIME_ZONE=(480)
LANGUAGE=(cn)
DMRW1=(192.168.37.201:5240,192.168.37.202:5240)
DMRW2=(192.168.37.201:5240,192.168.37.202:5240)
##服务配置
[DMRW1]
RW_SEPARATE=(1)
RW_PERCENT=(0)
[DMRW2]
RW_SEPARATE=(1)
RW_PERCENT=(100)
其中,
TIME_ZONE 和 LANGUAGE 分别对应操作系统时区和语言;
DMRW1=(192.168.37.201:5240,192.168.37.202:5240)表示一个服务名,把主机和备机都集成一个名字DMRW1,可以在disql登录时使用服务名替换url串中的IP地址,从而连接整个集群;
比如一般登录某个实例的命令为
./disql SYSDBA/SYSDBA@192.168.37.201:5240
在这里,可以使用以下命令登录读写分离集群
./disql SYSDBA/SYSDBA@DMRW1
login_mode的值为1,表示只连接主库;这个一定要局部配置,否则可能会影响disql的使用。此处未配置;
RW_SEPARATE=1,表示开启读写分离;
RW_PERCENT=100,表示将只读任务分发给备库的比例。比如在这里设置2个服务名,url地址一样,只有读写分离的分发比不同:
DMRW1对应的RW_PERCENT=0,表示主库读取比例设置为0,所以读取操作必定分配到备库;DMRW2对应的RW_PERCENT=100,表示主库读取比例设置为100,所以读取操作必定在主库。
2,数据库创建连接顺序
接口在备库上创建的连接是读写分离集群自动创建的;对用户而言,就是在主库上创建了一个数据库连接。下图以配置了两个备库的读写集群为例,说明了读写分离集群的连接创建流程。
读写分离集群数据库连接创建流程:
- 用户发起数据库连接请求。
- 接口(JDBC、DPI 等)根据服务名配置(在连接串或 dm_svc.conf 中进行配置)登录主库。
- 主库挑选一个有效即时备库或实时备库的 IP/Port 返回给接口。
- 接口根据返回的备库 IP 和 Port 信息,向备库发起一个连接请求。
- 备库返回连接成功信息。
- 接口响应用户数据库连接创建成功。
3,集群语句分发流程
实现读写分离集群的基本思路是:利用备库提供只读服务、无法修改数据的特性,优先将所有操作发送到备库执行,一旦备库执行报错,则发送到主库重新执行。通过备库“试错”这么一个步骤,自然地将只读操作分流到备库执行。并且,备库“试错”由接口层自动完成,对应用透明。
读写分离集群的sql语句分发流程:
- 接口收到用户的请求。
- 接口优先将 SQL 发送到备库执行。
- 备库执行并返回执行结果。如果接口收到的是备库执行成功消息,则转到第 6 步,如果接口收到的是备库执行失败消息,则转到第 4 步。
- 重新将执行失败的 SQL 发送到主库执行。只要第 3 步中的 SQL 在备库执行失败,则同一个事务后续的所有操作(包括只读操作)都会直接发送到主库执行。
- 主库执行并返回执行结果给接口。一旦主库上执行的写事务提交,则下次继续从第 1 步开始执行。
- 接口响应用户并将执行结果返回给用户。
4,读写分离功能测试
4.1,开启SQL日志
可以使用sqllog,用于记录sql语句具体在哪个实例上被执行。
sqllog.ini用于SQL日志的配置,当且仅当INI参数SVR_LOG=1时使用。 如果在服务器启动过程中,修改了sqllog.ini文件。修改之后的文件,只要调用过程SP_REFRESH_SVR_LOG_CONFIG() 就会生效。
可以直接使用sql命令查看SVR_LOG参数
select * from v$dm_ini where para_name like '%SVR_LOG%';
修改SVR_LOG参数
sp_set_para_value(1,'SVR_LOG',1);
更新参数
sp_refresh_svr_log_config();
4.2,修改配置文件sqllog.ini
一般会自动生成,路径为/home/dmdba/dmdbms/CHENx/CHEN/sqllog.ini
#sqllog.ini
BUF_TOTAL_SIZE = 10240 #SQLs Log Buffer Total Size(K)(1024~1024000)
BUF_SIZE = 1024 #SQLs Log Buffer Size(K)(50~102400)
BUF_KEEP_CNT = 6 #SQLs Log buffer keeped count(1~100)
[SLOG_ALL]
FILE_PATH = ../log
PART_STOR = 0
SWITCH_MODE = 2
SWITCH_LIMIT = 128
ASYNC_FLUSH = 1
FILE_NUM = 5
ITEMS = 0
SQL_TRACE_MASK = 1
MIN_EXEC_TIME = 0
USER_MODE = 0
USERS =
EXECTIME_PREC_FLAG = 0
[SLOG_ERROR]
SQL_TRACE_MASK = 23
FILE_PATH = ../log
[SLOG_DDL]
SQL_TRACE_MASK = 3
[SLOG_LONG_SQL]
SQL_TRACE_MASK = 25
MIN_EXEC_TIME = 60000
在/home/dmdba/dmdbms/log目录下可以看到对应的sql日志
4.3,登录读写分离集群
./disql SYSDBA/SYSDBA@DMRW1
比如使用服务名DMRW1登录时,会显示连接上主库
4.4,执行读写操作
insert into users values('1004','Dog');
commit;
select * from users;
可以发现,插入1004之后select,查不到1004
查看备库的sql日志,可以看到,备库尝试执行insert命令,但是报错了
查看-710对应的报错信息
select * from v$err_info where code like '-710';
说明备库执行insert命令报错了,然后看主库的sql日志,主库开始执行insert命令
但是备库的sql日志显示,commit命令是在备库上执行的,主库上并没有执行commit命令。所以insert命令最后会被回滚。所以最后执行select命令并不会查询到1004。
查看当前数据库模式,发现登录的是备库
select * from v$instance;
修改dm_svc.conf文件,添加配置项login_mode=(1)
login_mode的默认值为4,修改为1,只连接主库。
但是客户端重启之后,显示当前连接的数据库实例还是备库。不知道为什么,应该是bug。
总之现在,客户端只能连接到备库,读写分离的所有操作都在备库上执行,写操作必然会失败。
理论上,应该连接上主库,然后读操作在备库执行,写操作失败后转到主库执行。