架构师训练营第 0 期第 6 周作业
1、简述 CAP 原理
1-1、关于事务
事务会把数据库从一种【一致状态】转换为另一种【一致状态】;
事务是一组【不可分割】的操作集合,这些操作要么都成功执行,要么都取消执行;
最典型的事务场景就是【银行账户间转账】:
账户 A 给账户 B 转账 100 元,账户 A 中的金额要扣减 100 元,账户 B 中的金额要增加 100 元,两个账户的金额必须都更新成功才算成功;
事务有四个特征【ACID】:
原子性(Atomicity):数据库事务是【不可分割】的工作单位,事务中的所有操作,要么全部成功,要么全部失败,不能出现部分成功,部分失败的情况;
一致性(Consistency):指事务将数据库从一种状态转变为下一种【一致的】状态,在事务开始之前和事务结束之后,数据库的【完整性约束】没有被破坏;以转账操作为例,假如 A 和 B 账户在转账前各有 100 元,两个账户的总金额是 200,那么两个账户间转账多次,两个账户的总金额仍然是 200 元;
隔离性(Isolation):事务的隔离性要求每个读写事务的对象,对其他事务的操作对象相互隔离;事务的隔离级别,由低到高是【读未提交、读已提交、可重复读和串行化】;
持久性(Durability):事务完成对数据的更改不会丢失;
2、本地事务实现原理
传统的单服务器,单关系型数据库下的事务,就是本地事务。本地事务由资源管理器管理,JDBC 事务就是一个非常典型的本地事务。这里以 MySQL 为例;
MySQL 事务日志
MySQL 的 InnoDB 事务日志包括 redo log 和 undo log。
redo log(重做日志):通常是物理日志,记录的是数据页的物理修改,而不是某一行或某几行修改成怎样,它用来恢复提交后的物理数据页。
undo log(回滚日志):是逻辑日志,和 redo log 记录物理日志的不一样。
可以这样认为,当 delete 一条记录时,undo log 中会记录一条对应的 insert 记录,当 update 一条记录时,它记录一条对应相反的 update 记录。
MySQL 事务 的 ACID 特性实现原理
原子性:是使用【undo log】来实现的,如果事务执行过程中出错或者用户执行了 rollback,系统通过【undo log】日志返回事务开始的状态。
一致性:通过回滚、恢复,以及并发情况下的隔离性,从而实现一致性。
隔离性:通过【锁】使事务相互隔离。
持久性:使用【redo log】来实现,只要【redo log】日志持久化了,当数据库宕机,也可以通过【redo log】把数据恢复。
3、分布式事务
上面讨论的是在【单个数据库】操作,数据库本身支持 ACID 特性,当数据更新不在一个数据库中,如何保证事务的 ACID 特性,比如有以下场景:
当单个数据库的存储或者 IO 访问出现瓶颈,单纯升级【硬件资源】也无法满足要求时,需要对数据库进行分库,一旦分库就可能出现【跨库】事务的情况;比如上面提到的转账例子,两个用户的数据落在不同数据库上;
随着应用规模不断扩大,业务功能和需求变复杂,又需要对单体应用进行服务化拆分,原来在一个应用中的数据操作,分布到多个应用处理,【跨服务】事务的情况也可能发生,这里典型的场景:跨银行的转账操作;
基于这两种场景,引出了【分布式事务】的概念。
根据之前的例子,所谓的分布式事务,就是指:事务的参与者、支持事务的服务器、资源服务器以及事务管理器分别位于分布式系统的不同节点上。
分布式事务有以下场景:
跨数据库分布式事务;
跨服务分布式事务;
混合分布式事务;
如果要在【分布式事务】场景下,满足 ACID 特性,单体事务模式已无法胜任,为了保证分布式的可用性和一致性,出现了 CAP 和 BASE 这样的分布式系统理论;
4、CAP 理论
4-1、什么是 CAP 原理?
对于一个分布式系统,或者分布式数据存储系统而言,一致性(Consistency)、可用性(Availability)和分区容忍性(Partition tolerance)不能同时满足;
4-2、一致性(Consistency)
每次读取的数据都应该是【最近写入】的数据或者返回一个错误(Every read receives the most recent write or an error),而不是过期的数据,也就是说,数据是一致的;
在【分布式环境】中,数据在【多个副本之间】【保持一致】;对于将数据副本保存在不同分布式节点的系统,如果对第一个节点的数据进行更新并且更新成功后,却没有更新第二个节点上的数据,就是典型的【分布式不一致】情况;
这里引出了【强一致性】的概念: 在分布式系统中,如果能够做到针对一个数据项的更新操作成功后,所有的用户都可以读取到最新的值;
4-3、可用性(Availability)
每次请求都应该得到一个响应,而不是返回一个错误或者失去响应,不过这个响应结果不需要保证数据时最近写入的(Every request receives a (non-error) response, without the guarantee that it contains the most recent write),也就是说系统一直都是正常使用,不会返回调用者异常,但是并不保证响应的数据时最新的;
可用性,最重要的就是系统提供的服务必须一直处于可用状态,对用户的每一个操作请求总是能够在【有限的时间内】【返回结果】。这里对【有限的时间内】和【返回结果】做说明:
“有限的时间内”:对于用户(人或者系统)的一个操作请求,系统必须能够在指定的时间(即响应时间)内返回对应的处理结果,超过这个时间范围则认为系统不可用;【有限时间内】是在系统设计之初就设定好的系统运行指标,不同系统之家会有不同;
“返回结果”:要求系统在完成对用户请求的处理后,返回一个【正常的响应结果】;【正常的响应结果】要么成功,要么失败,必须能够明确地反映出请求的处理结果;对于 Java 语言编写的系统来说,不能返回类似“OutOfMemoryError”这样的提示;
4-4、分区耐受性(Partition tolerance)
即使因为网络原因,部分服务器节点之间消息丢失或者延迟,系统依然可以操作(The system continues to operate despite an arbitrary number of messages being dropped or delayed by the network between nodes);
分布式系统遇到任何【网络分区】故障的时候,仍然需要保证对外提供满足【一致性】和【可用性】服务,除非是整个网络环境都发生了故障;
【网络分区】是指分布式系统中,不同的节点分布在不同的【子网络】(机房或异地网络等),由于一些特殊原因导致这些【子网络】之间出现网络不连通的情况,但各个子网络内部是正常的,从而导致整个系统的网络环境被切分成若干个孤立的区域。
4-5、CAP 总结
对于分布式系统来说,各个服务或数据库必须要部署到不同节点,而对于分布式系统而言,网络问题又必定会出现,因此分区容错性就成为分布式系统必须要解决的问题;
当网络分区失效发生的时候,我们要么取消操作,这样数据就是一致的,但系统却不可用;要么我们继续写入数据,但是数据的一致性就得不到保证;
对于一个分布式系统而言,网络失效一定会发生,也就是说,分区耐受性必须要保证,只有在可用性和一致性上二选一;
网络分区失效,也就是网络不可用的时候,如果选择一致性,系统就可能返回一个错误码或者干脆超时,即系统不可用;如果选择可用性,那么系统总是可以返回一个数据,但是不能保证这个数据是最新的;
关于 CAP 原理,更准确的说法是:在分布式系统必须满足【分区耐受性】的情况下,可用性和一致性无法同时满足;
5、BASE 理论
BASE 是对 CAP 中一致性和可用性权衡的结果,是基于 CAP 理论逐步演化而来,其核心思想是即使无法做到【强一致性(Strong consistency)】,但每个应用都可以根据自身业务特点,采用适当的方式来使系统达到【最终一致性(Eventual consistency)】。
BASE 是 Basically Available(基本可用)、Soft state(软状态)和 Eventually consistency(最终一致性)三个短语的缩写。
5-1、基本可用 (Base Available)
【基本可用】是指分布式系统在出现不可预知故障的时候,允许损失【部分可用性】,但不等价于系统不可用。
典型的例子:
响应时间上的损失:正常情况,一个在线搜索引擎要做 0.5 秒内返回给用户查询结果,但是由于系统部分机房发生断电或网络故障,查询结果的【响应时间】增加的 1~2 秒;
功能上的损失:正常情况下,在一个电子商务网站购物,消费者能够顺利完成每一笔订单,但是在大促高峰期间,由于消费者购物行为激增,为了保护系统的稳定性,部分消费者可能会被引导到一个降级页面;
5-2、软状态(Soft State)
允许系统中的数据存在【中间状态】,并认为该【中间状态】的存在不会影响系统的整体可用性,即允许系统在不同节点的数据副本之间进行【数据同步】的过程存在【延时】。
5-3、最终一致性(Eventual Consistency)
【最终一致性】强调的是系统中所有数据副本,经过一段时间同步后,最终能够达到一致性状态。【最终一致性】的本质是【需要系统保证最终数据能够达到一致】,而不需要实时保证系统数据的【强一致性】。
5-4、总结
最终一致性是一种特殊的一致性:系统能够保证在【没有其他更新操作】的情况下,数据最终一定能够达到一致的状态,所有客户端对系统的数据访问都能够获取到最新的值。在没有发生故障的前提下,数据达到一致状态的时间延迟,取决于网络延迟、系统负载和数据复制方案设计等因素。
【Base 理论】是面向【大型高可用可扩展的分布式系统】,和传统事务的 ACID 特性相反,不同于 ACID 的【强一致性】,而是提出通过牺牲强一致性来获得可用性,并允许数据在一段时间内是不一致的,但最终达到一致状态。
最终一致性不只是大型分布式系统才有的特性,传统的关系型数据库也采用最终一致性模式。在关系型数据库中,大多采用【同步和异步方式】来实现主备数据复制技术。
在同步方式中,数据的复制过程通常是更新事务的一部分,因此在事务完成后,主备数据库的数据就会达到一致;
在异步方式中,备库的更新往往存在延时,这取决于事务日志在主备数据库之间传输的时间长短,如果传输时间过长或者甚至在传输过程中出现异常,导致无法及时将事务更新到备库,在备库读取的数据将是旧的,就出现了数据不一致的情况。通过多次重试或者人为数据订正,关系型数据库还是能保证最终数据达到一致。
最终一致性存在以下五类主要变种
5-4-1、因果一致性(Causal Consistency)
因果一致性是指,如果进程 A 在更新完某个数据项后通知进程 B,那么进程 B 对该数据项的访问应该能获取到进程 A 更新后的最新值,并且如果进程 B 对该数据项进行操作,也必须基于进程 A 更新后的最新值,即不能发生【丢失更新】情况。
5-4-2、读己之所写(Read your writes)
读己之所写是指,进程更新一个数据项后,进程自己总是能够访问到更新过的最新值,而不会看到旧值。
5-4-3、会话一致性(Session Consistency)
会话一致性将对系统数据的访问过程框定在一个会话中:系统能保证在同一个有效的会话中实现“读己之所写”的一致性,也就是说,执行更新操作后,客户端能够在同一个会话中始终读取到该数据项的最新值。
5-4-4、单调读一致性(Monotonic read consistency)
单调读一致性是指如果一个进程从系统中读取一个数据项后,那么系统对于该进程后续的任何数据访问都不应该返回更旧的值。
5-4-5、单调写一致性(Monotonic write consistency)
单调写一致性是指,一个系统需要能够保证来自同一个进程的写操作被顺序执行。
5-5、最终一致性实现
1、根据时间戳,实现写覆盖
两个事物更新同一个数据,最终以时间戳更新的那个事物最准;
需要分布式系统中不同节点时间戳需要【保持高度一致】;
缺点:必须在每台服务器上都要保证时钟一致;
2、由客户端解决最终冲突
场景:
用户在不同客户端登录电商网站,往购物车中添加商品,最终在一个客户端中合并用户购物车中的商品信息;
6、NoSQL 产品解决 CAP 问题
6-1、Cassandra【投票解决】冲突
Cassandra 集群出现分区中断,无法保证集群中【一半以上机器投票】,这样写入和读取就会失败,牺牲一部分可用性;
Cassandra 的分布架构
在写入时,Cassandra 客户端访问集群中的一个节点,节点等待集群中投票等待【大于一半的】机器写入成功后,再返回客户端写成功;
在读取时,仍然从客户端读取数据,集群中每个节点可能出现数据不一致的情况,需要集群中大于一半的机器【投票决定】,返回最新的数据;
6-2、HBase 数据库一致性
HBase 全程 Hadoop Database,是 Google Bigtable 的开源实现,是一个基于 Hadoop 文件系统设计的面向海量数据的高可靠性、高性能、面向列、可伸缩的分布式数据存储系统。
与大部分分布式 NoSQL 数据库不同,HBase 针对数据写入具有【强一致性】的特性,甚至包括索引列也实现强一致性。
HBase 有以下特性:
强一致读/写:HBase 不是一个“最终一致性”数据存储。这使得它使用于【高速计数聚合任务】。(Strongly consistent reads/writes: HBase is not an "eventually consistent" DataStore. This makes it very suitable for tasks such as high-speed counter aggregation.)。
自动分片:HBase 表通过 Regions 分布在集群上,Regions 可以【随着数据增长】【自动分片】和【重新分布】;(Automatic sharding: HBase tables are distributed on the cluster via regions, and regions are automatically split and re-distributed as your data grows.)。
RegionServer 自动故障转移(Automatic RegionServer failover)。
Hadoop/HDFS 集成:HBase 支持本机外 HDFS 作为它的分布式文件系统(Hadoop/HDFS Integration: HBase supports HDFS out of the box as its distributed file system)。
MapReduce: HBase 通过 MapReduce 支持大并发处理, HBase 可以同时做源和目标(MapReduce: HBase supports massively parallelized processing via MapReduce for using HBase as both source and sink.)。
Java 客户端 API: HBase 支持易于使用的 Java API 进行编程访问(Java Client API: HBase supports an easy to use Java API for programmatic access.)。
Thrift/REST API: HBase 也支持 Thrift 和 REST 作为非 Java 前端(Thrift/REST API: HBase also supports Thrift and REST for non-Java front-ends)。
Block Cache 和 Bloom Filters: 对于大容量查询优化, HBase 支持 Block Cache 和 Bloom Filters(Block Cache and Bloom Filters: HBase supports a Block Cache and Bloom Filters for high volume query optimization)。
运维管理: HBase 提供内置网页用于运维视角和 JMX 度量(Operational Management: HBase provides build-in web-pages for operational insight as well as JMX metrics)。
6-2-1、HBase 架构
6-2-2、HBase 架构角色的作用
1、Client
HBase 客户端负责寻找相应的 RegionServers 来处理行。先查询 .META.
和 -ROOT
目录表,然后再确定 region 的位置。定位到所需要的区域后,客户端会直接去访问相应的 region(不经过 master),发起读写请求。这些信息会缓存在客户端,这样就不用每发起一个请求就去查一下。如果一个 region 已经废弃(原因可能是 master load balance 或者 RegionServer 死了),客户端就会重新进行这个步骤,决定要去访问的新的地址。
2、HMaster
HMaster 是 Master Server 的实现。Master Server 的作用是在集群中负责监视所有的 RegionServer 实例,和所有元数据变化的接口。
当某个 RegionServer 挂掉的时候,Zookeeper 会因为在一段时间内无法接收心跳信息,而删除掉该 RegionServer 服务器对应的 rs 状态 节点。与此同时,HMaster 会收到 Zookeeper 的 NodeDelete 通知,从而感知到某个节点断开,并立即开始容错工作 -- HMaster 会将挂掉的 RegionServer 处理的数据分片重新路由到其他节点,并记录到 Meta 信息中供客户端查询。
3、HRegionServer
HRegionServer 是 RegionServer 的实现。它负责服务和管理 Region。在一个分布式集群中,一个 RegionServer 运行在一个数据节点上;(HRegionServer is the RegionServer implementation. It is responsible for serving and managing regions. In a distributed cluster, a RegionServer runs on a DataNode.)。
4、HRegion
Regions 是对于表可用性和分布的基本元素,由每个列族(Column Family)的一个存储组成。
6-2-3、HBase 的强一致性实现原理
Client 通过【HMaster】知道某条数据应该通过哪个 HRegionServer 进行读写,然后调用对应的 HRegionServe 处理数据。
一份数据通过一个 HRegionServer 进行数据存储,HRegionServer 的底层是 Hadoop 的文件系统 HDFS,HDFS 在做存储时会复制多份,当服务器宕机时,数据也不会丢失。
一个 Key 只会通过一个 HRegionServer 负责,不会由多个节点负责数据处理。
HBase 的可用性较差,当一个 HRegionServe 出现系统故障、负载均衡、配置修改、Region 分裂与合并时,这期间数据是【不可用】的,需要重新恢复或者迁移数据到其他 HRegionServe。
版权声明: 本文为 InfoQ 作者【Arthur】的原创文章。
原文链接:【http://xie.infoq.cn/article/78aef90c0e9b320b7bfa7940b】。未经作者许可,禁止转载。
评论