# 数据存储架构


## 数据库主从复制
将 MySQL 主数据库中的数据复制到从数据库中去

原理：
当应用程序客户端发送一条更新命令到主服务器数据库的时候，数据库会
把这条更新命令同步记录到 Binlog 中，然后由另外一个线程从 Binlog 中读取这条日志，
通过远程通讯的方式将它复制到从服务器上面去。

从服务器获得这条更新日志后，将其加入到自己的 Relay Log 中，然后由另外一个 SQL 执
行线程从 Relay log 中读取这条新的日志，并把它在本地的数据库中重新执行一遍，这样当
客户端应用程序执行一个 update 命令的时候，这个命令会同时在主数据库和从数据库上执
行，从而实现了主数据库向从数据库的复制，让从数据库和主数据库保持一样的数据。

通过数据库主从复制的方式，我们可以实现数据库读写分离。写操作访问主数据库，读操作
访问从数据库，使数据库具有更强大的访问负载能力，支撑更多的用户访问。

采用一主多从的方案，当某个从数据库宕机的时候，还可以将读操作迁移到其他从数据库
上，保证读操作的高可用。但如果主数据库宕机，系统就没法使用了，因此现实中，也会采
用 MySQL 主主复制的方案。也就是说，两台服务器互相备份，任何一台服务器都会将自
己的 Binlog 复制到另一台机器的 Relay Log 中，以保持两台服务器的数据一致。

使用主主复制需要注意的是，主主复制仅仅用来提升数据写操作的可用性，并不能用来提高
写操作的性能。任何时候，系统中都只能有一个数据库作为主数据库，也就是说，所有的应
用程序都必须连接到同一个主数据库进行写操作。只有当该数据库宕机失效的时候，才会将
写操作切换到另一台主数据库上。这样才能够保证数据库数据的一致性，不会出现数据冲
突。

此外，不管是主从复制还是主主复制，都无法提升数据库的存储能力，也就是说，不管增加
多少服务器，这些服务器存储的数据都是一样的。如果数据量太大，数据库无法存下这么多
的数据，通过数据库复制是无法解决问题的。
## 数据库分片
数据库主从复制无法解决数据库的存储问题，但是数据库分片技术可以解
决。也就是说，将一张表的数据分成若干片，每一片都包含了数据表中一部分的行记录，然
后每一片存储在不同的服务器上，这样一张表就存储在多台服务器上了。

最简单的数据库分片存储可以采用硬编码的方式，在程序代码中直接指定一条数据库记录要
存放到哪个服务器上。但是硬编码方式的缺点比较明显。首先，如果要增加服务器，那么就必须修改分片逻辑代
码，这样程序代码就会因为非业务需求产生不必要的变更；其次，分片逻辑耦合在处理业务
逻辑的程序代码中，修改分片逻辑或者修改业务逻辑都可能使另一部分代码因为不小心的改
动而出现 Bug。

可以通过使用分布式关系数据库中间件解决这个问题，将数据的分片逻辑在中间件
中完成，对应用程序透明。

实践中，更常见的数据库分片算法是我们所熟悉的余数 Hash 算法，根据主键 ID 和服务器
的数目进行取模计算，根据余数连接相对应的服务器。
## 关系数据库的混合部署
对于数据访问和存储压力不太大，对可用性要求也不太高的系统，也许部署在单一服务器上
的数据库就可以解决，所有的应用服务器都连接访问这一台数据库服务器。

如果访问量比较大，同时对数据可用性要求也比较高，那么就需要使用数据库主从复制技
术，将数据库部署在多台服务器上。

不同的业务数据库，其数据库存储的数据和访问压力也是不同的，比如用户数据库的数据量
和访问量就可能是类目数据库的几十倍，甚至上百倍。那么这时候就可以针对用户数据库进
行数据分片，而每个分片数据库还可以继续进行主从复制或者主主复制。

## Nosql数据库
NoSQL 数据库主要用来解决大规模分布式数据的存储
问题

NoSQL 数据库面临的挑战之一是数据一致性问题。如果数据分布存储在多台服务器组成的
集群上，那么当有服务器节点失效的时候，或者服务器之间网络通信故障的时候，不同用户
读取的数据就可能会不一致。

关于分布式存储系统有一个著名的 CAP 原理，CAP 原理说：一个提供数据服务的分布式系
统无法同时满足数据一致性（Consistency）、可用性（Availability）和分区耐受性
（Partition Tolerance）这三个条件。

CAP 原理是说，当网络分区失效发生的时候，我们要么取消操作，保证数据就是一致的，
但是系统却不可用；要么继续写入数据，但是数据的一致性就得不到保证了。

对于一个分布式系统而言，网络失效一定会发生，也就是说，分区耐受性是必须要保证的，
而对于互联网应用来说，可用性也是需要保证的，分布式存储系统通常需要在一致性上做一
些妥协和增强。

Apache Cassandra 解决数据一致性的方案是，在用户写入数据的时候，将一个数据写入
集群中的三个服务器节点，等待至少两个节点响应写入成功。用户读取数据的时候，从三个
节点尝试读取数据，至少等到两个节点返回数据，并根据返回数据的时间戳，选取最新版本
的数据。这样，即使服务器中的数据不一致，但是最终用户还是能得到一个一致的数据，这
种方案也被称为最终一致性。
