前言:当一个网站开始刚刚创建时,可能只是考虑一天只有几十或者几百个人访问,数据库可能就个db,所有表都放一起,一台普通的服务器可能就够了,而且开发人员也非常高兴,而且信心十足,因为所有的表都在一个库中,这样查询语句就可以随便关联了,多美的一件事情。但是随着访问压力的增加,读写操作不断增加,数据库的压力绝对越来越大,可能接近极限,这时可能人们想到增加从服务器,做什么集群之类的,可是问题又来了,数据量也快速增长。这时可以考虑对数据库读写操作进行分离,按照业务把不同的数据放到不同的库中。其实在一个大型而且臃肿的数据库中表和表之间的数据很多是没有关系的,或者更加不需要(join)操作,理论上就应该把他们分别放到不同的服务器。例如用户的收藏夹的数据和博客的数据库就可以放到两个独立的服务器。这个就叫垂直划分。把一个表的数据按规律分到不同的数据库,两个数据库表结构一样,就叫数据库的水平拆分。

  1. 数据库垂直划分(数据库表无关联)

按照功能划分,把数据分别放到不同的数据库和服务器上,即为数据库的垂直划分。垂直拆分取决于当前模块要拆分的表是否有关联。比如工资模块和员工工资档案模块是没有关联的,该两个模块对应的表独立,就可以拆分。

  1. 数据库水平划分

数据库水平拆分是将一个表的数据换分到不同数据库,两个数据库表结构一样。

对于表的拆分是要根据一样的规则,例如根据id拆分,然后根据一定的规则先获知要操作的数据在哪个数据库。一刚才的博客为例,可以根据用户id的奇偶数来确定数据的划分,把奇数划到A数据库,偶数划到B数据库,所以通过userId%2就可以判断该数据在哪个数据库了;或者将前5千万条数据放到A数据库,后面的数据放到B数据库,再者还可以根据Hash算法来处理。

3.数据库读写分离

数据库读写分离,基本的原理是让主数据库处理事务性增、改、删操作(INSERT、UPDATE、DELETE),而从数据库处理SELECT查询操作。数据库复制被用来把事务性操作导致的变更同步到集群中的从数据库。

 

数据库分库、分表、读写分离的原因:

 单表的数据量限制,当单表数据量到一定条数之后数据库性能会显著下降。数据多了之后,对数据库的读、写就会很多。分库减少单台数据库的压力。接触过几个分库分表的系统,都是通过主键进行散列分库分表的。这类数据比较特殊,主键就是唯一的获取该条信息的主要途径。比如:京东的订单、财付通的交易记录等。。。该类数据的用法,就是通过订单号、交易号来查询该笔订单、交易。

还有一类数据,比如用户信息,每个用户都有系统内部的一个userid,与userid对应的还有用户看到的登录名。那么如果分库分表的时候单纯通过userid进行散列分库,那么根据登录名来获取用户的信息,就无法知道该用户处于哪个数据库中。

或许有朋友会说,我们可以维护一个email—-userid的映射关系,根据email先查询到userid,在根据userid的分库分表规则到对应库的对应表来获取用户的记录信息。这么做是可以的,但是这个映射关系的条数本身也是个瓶颈,原则上是没有减少单表内数据的条数,算是一个单点。并且要维护这个映射关系和用户信息的一致性(修改登录名、多登录名等其他特殊需求),最大一个原因,其实用户信息是一个读大于写的库,web2.0都是以用户为中心,所有信息都和用户信息相关联,所以对用户信息拆分还是有一定局限性的。对于这类读大于写并且数据量增加不是很明显的数据库,推荐采用读写分离+缓存的模式,试想一下一个用户注册、修改用户信息、记录用户登录时间、记录用户登录IP、修改登录密码,这些是写操作。但是以上这些操作次数都是很小的,所以整个数据库的写压力是很小的。唯一一个比较大的就是记录用户登录时间、记录用户登录IP这类信息,只要把这些经常变动的信息排除在外,那么写操作可以忽略不计。所以读写分离首要解决的就是经常变化的数据的拆分,比如:用户登录时间、记录用户登录IP。这类信息可以单独独立出来,记录在持久化类的缓存中(可靠性要求并不高,登陆时间、IP丢了就丢了,下次来了就又来了)

以Oracle为例,主库负责写数据、读数据。读库仅负责读数据。每次有写库操作,同步更新cache,每次读取先读cache(缓存服务器集群是为了减轻数据库负担)在读DB。写库就一个,读库可以有多个,采用dataguard来负责主库和多个读库的数据同步。

java completefuture 并行查询sql java并发查询数据库_数据

利用数据库同步软件完成主从数据库的同步。例如:dataguard;