天天看点

数据库"负载均衡,备份,异地容灾"设计

数据库"负载均衡,备份,异地容灾"设计

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或数据合并操作,在设计数据表的时候需要考虑加入记录修改时间的标记列.

  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在数据复制的用途.

  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等.