数据库"负载均衡,备份,异地容灾"设计
Author: Digoal
PS - 纯属个人看法,仅供参考.
1. 数据对象按分类放到不同的SCHEMA
为了方便实施数据库层面的备份和容灾,必须将数据对象按内容进行逻辑分类设计.
例如: (某下载系统)
1.tbl_app_info 表 - 存储应用信息,新应用部署时需要插入该表,应用下线时需要更新或删除该表的记录,用户下载时需要查询该表,还有等等一些其他操作;数据增长缓慢,数据量视应用数决定.
2.tbl_download_rec 表 - 存储用户下载记录,当用户下载成功后会往该表写入下载记录,数据仓库需要抽取该表作为分析,某些在线统计可能会查询该表,业务逻辑中没有对该表的DELETE操作;数据增长迅速,数据量视用户下载量决定.
分析:
1.用户下载依赖tbl_app_info表的数据.
2.用户下载不依赖tbl_download_rec表的数据,但是tbl_download_rec表需要存在才能正确的写入下载记录.
SCHEMA设计:
1.新建 "APPUSER" schema 存放 tbl_app_info表.
2.新建 "APPUSER_LOG" schema 存放 tbl_download_rec表.
备份设计:
1.备份 "APPUSER" schema 的 DATA 和 METADATA.
2.备份 "APPUSER_LOG" schema 的 METADATA.
优点:节约备份时间和存储空间以及网络带宽,降低了备份给生产库带来的压力,减少了数据恢复时间.
容灾设计:
1.同步或异步复制 "APPUSER" schema 的 DATA 和 METADATA.
2.同步或异步复制 "APPUSER_LOG" schema 的 METADATA.
优点:节约同步时间和存储空间以及网络带宽,降低了数据复制给生产库带来的压力,减少了数据复制时间.
小结:
1.数据按照是否被应用程序依赖大体可以分为 "业务数据" , "Insert_Select Only型数据" ; 在SCHEMA设计时将两类数据分开可以给备份和容灾带来极大的好处.
2. SEQUENCE步长调整
为了方便实施数据库层面的负载均衡或异地容灾,有必要将SEQUENCE的步长作调整.
例如: (某下载系统)
1.seq_app_info 序列 - tbl_app_info 表对应的序列(PK),当插入tbl_app_info时,取该序列的值.
SEQUENCE步长设计:
1.假设数据库容灾系统或负载均衡系统使用复制表的技术将tbl_app_info表复制到异地或本地的另一台数据库中,在这些节点取序列值需要全局唯一,这个时候sequence的步长就发挥了很好的作用,如(取步长=10,可以容纳最多10个节点包含自身,容灾或负载均衡使用):
节点0:create sequence seq_app_info increment by 10 minvalue 0 maxvalue 999999999999999 start with 0 ;
节点1:create sequence seq_app_info increment by 10 minvalue 1 maxvalue 999999999999999 start with 1 ;
节点2:create sequence seq_app_info increment by 10 minvalue 2 maxvalue 999999999999999 start with 2 ;
节点3:create sequence seq_app_info increment by 10 minvalue 3 maxvalue 999999999999999 start with 3 ;
节点4:create sequence seq_app_info increment by 10 minvalue 4 maxvalue 999999999999999 start with 4 ;
节点5:create sequence seq_app_info increment by 10 minvalue 5 maxvalue 999999999999999 start with 5 ;
节点6:create sequence seq_app_info increment by 10 minvalue 6 maxvalue 999999999999999 start with 6 ;
节点7:create sequence seq_app_info increment by 10 minvalue 7 maxvalue 999999999999999 start with 7 ;
节点8:create sequence seq_app_info increment by 10 minvalue 8 maxvalue 999999999999999 start with 8 ;
节点9:create sequence seq_app_info increment by 10 minvalue 9 maxvalue 999999999999999 start with 9 ;
这些节点取seq_app_info序列的值将获得全局唯一的结果.
小结:
1.调整SEQUENCE步长将得到全局唯一的序列值,在容灾系统中起服务的时候避免序列值不正确造成的失败.
2.缺点是可能要浪费一些数值.
3. create_time字段设计
对于Insert_Select Only型数据表,为了更好地实施ELT,在设计数据表的时候需要考虑加入记录创建时间的标记列.
例如: (某下载系统)
1.tbl_download_rec 表 - 存储用户下载记录,当用户下载成功后会往该表写入下载记录,数据仓库需要抽取该表作为分析,某些在线统计可能会查询该表,业务逻辑中没有对该表的DELETE操作;数据增长迅速,数据量视用户下载量决定.
create_time字段设计:
1.给tbl_download_rec 表加入一个时间类型字段,每次插入记录时取当时的数据库服务器系统时间,这样的话给ETL和表分区带来了极大的便利.
小结:
1.在某些场景自增长的ID(PK)作为ETL标记列也是不错的选择,但是为了确保不产生数据气泡,必须将自增长使用的SEQUENCE修改为no cache和order属性,在高并发的场景下面可能会带来巨大的性能损失.因此时间类型字段作为ETL标记不失为一个更好的选择.
2.给记录添加时间字段也是表分区的一个比较常用的手段,向tbl_download_rec这类表,每天插入的记录数可能上亿,没有分区的话是致命的,按照时间来分表或分区是一个明智的选择.
4. modify_time字段设计
对于Insert_Update_Delete_Select 型数据表,为了更好地实施ELT或数据合并操作,在设计数据表的时候需要考虑加入记录修改时间的标记列.
例如: (某下载系统)
1.tbl_app_info 表 - 存储应用信息,新应用部署时需要插入该表,应用下线时需要更新或删除该表的记录,用户下载时需要查询该表,还有等等一些其他操作;数据增长缓慢,数据量视应用数决定.
modify_time字段设计:
1.给tbl_app_info 表加入一个时间类型字段,每次修改记录的时候,更新modify_time字段为当前的数据库服务器系统时间,在做ETL的时候可以选择modify_time比上一次ETL更新并且create_time小于等于上一次ETL的create_time的数据抽取,抽取完在DW进行数据合并.这样做的话降低了ETL抽取的带宽开销和时间开销,当然还需要抽取create_time大于上次ETL时间的记录.
小结:
1.对于不经常修改的表或者是修改的记录数占整表比较小的情况,使用modify_time来抽取的话可以降低ETL开销,减少ETL的时间.
5. PK设计
理论上每个表都应该有PK列,如更新记录的时候使用PK的值可以定位到被更新的行.这里的话主要讨论PK在数据复制的用途.
例如: (某下载系统)
1.tbl_app_info 表 - 存储应用信息,新应用部署时需要插入该表,应用下线时需要更新或删除该表的记录,用户下载时需要查询该表,还有等等一些其他操作;数据增长缓慢,数据量视应用数决定.
PK设计:
1.给tbl_app_info 表增加一个ID字段,确保ID非空,唯一,并且不会被更新.
数据复制设计:
1.使用物化视图,多主复制,Slony等手段,当记录被更新,删除,或插入时,在主库(复制源)记录下该表的ID,以及其他可选字段的内容.在目标库(复制接收端)抓取在主库记录下的ID以及那些行的数据插入或更新到本地.
小结:
1.使用PK来标记需要复制的数据好处是,多次更新一次复制,大大的降低了复制带来的带宽开销.同时使复制的效率提升了很多.
2.对于Insert_Select Only型数据表的复制不建议使用.
6. 字符集设计
理论上需要交互的库都选取相同的字符集.
1.字符集决定了数据被存储在数据库中占用的空间,如某些字符集存储英文字母需要1个字节,某些定长的字符集可能存储英文字母需要2个字节,某些变长的字符集存储中文可能需要2-3个字节等等.
2.字符集也决定了存储的字符范围,如要存储中文字的话就不能选取某些单字节存储的字符集.
3.对于两个不同字符集的数据库,如果有数据交互的操作,存在字符集转换的操作;对于小字符集到大字符集的转换还比较好,如果是大字符集到小字符集可能存在数据丢失的现象.
小结:
1.在字符集的选取上,数据仓库推荐使用较大的字符集(如UTF8),其他的业务库如果有数据交互字符集也必须一致,条件允许的情况下建议所有数据库使用统一的字符集.
7. 数据库负载均衡,容灾设计
这里仅考虑数据库层面的设计,理论上来说应用来考虑负载均衡的设计会比较合理,不过某些场景下面,可能应用已经定型了或者是数据库实施起来比较方便,也会考虑使用数据库负载均衡的做法.
例如: (某下载系统)
1.业务依赖 A类表(记录) - 存储应用信息,新应用部署时需要插入该类表,应用下线时需要更新或删除该类表的记录,用户下载时需要查询该类表,还有等等一些其他操作;数据增长缓慢,数据量视应用数决定.
2.业务依赖 B类表(定义) - 存储用户下载记录,当用户下载成功后会往该类表写入下载记录,数据仓库需要抽取该类表作为分析,某些在线统计可能会查询该类表,业务逻辑中没有对该类表的DELETE操作;数据增长迅速,数据量视用户下载量决定.
数据库负载均衡设计:
1.创建并复制A类表.可选手段如Oracle的MVIEW,GoldenGate,PostgreSQL的Slony等.
2.创建B类表.
3.调整SEQUENCE步长,在不同的节点使用不同的起点值.
8. 数据库备份设计
这里仅考虑数据库层面的设计,对于不同的应用定制不同的备份策略.
首先要搞清楚需求,为什么要备份?(法律?数据恢复?),例如:
1.接到用户的投诉时,可能要找出很久以前的用户行为记录,如果已经不在业务系统数据库了,还是不得不从备份中恢复出来查找.
2.业务数据库发生了不可恢复的灾难时,需要使用备份来重建或恢复业务库.
3.某些法律可能强制某些业务数据必须保留几年以上.
数据库恢复需求:
1.要求数据恢复到过去的任意时间点到当前的时间点的状态,要求恢复的数据库数据一致.
对数据恢复的要求比较高,在数据库层面的备份可以选择的方法比较少,如Oracle 打开归档的情况下使用rman的备份,PostgreSQL打开归档的情况下的备份等等.
2.要求数据可以恢复到最近几天内就可以,要求恢复的数据库数据一致,不一定要到数据库的关机状态.
对于这类备份需求,定期的逻辑备份就可以满足需求.
其他:
其他可以考虑的数据库容灾的手段还有存储复制,文件系统同步等等.
说明:
数据对象 - 数据库中的一切实体都被称为数据对象,例如TABLE,INDEX,SEQUENCE,FUNCTION,PROCEDURE,TRIGGER,VIEW,SYNONYM,DBLINK等.