区块链:基础知识篇

区块链本身并不是新的理论或者技术,而是对已经存在的技术理论进行实现的一个新事物而已,因此基础是构成它的基石。这里概要讲述大多数书籍必定会遇到的一些基础知识和相关点。

一致性问题(Consistency)

理想的分布式系统一致性应该满足:
可终止性(Termination):一致的结果在有限时间内能完成;
共识性(Consensus):不同节点最终完成决策的结果应该相同;
合法性(Validity):决策的结果必须是其它进程提出的提案。

强一致性(Strong Consistency)主要包括下面两类:

  • 顺序一致性(Sequential Consistency):Leslie Lamport 1979 年经典论文《How to
    Make a Multiprocessor Computer That Correctly Executes Multiprocess Programs》中
    提出,是一种比较强的约束,保证所有进程看到的 全局执行顺序(total order)一致,并
    且每个进程看自身的执行(local order)跟实际发生顺序一致。例如,某进程先执行 A,
    后执行 B,则实际得到的全局结果中就应该为 A 在 B 前面,而不能反过来。同时所有其
    它进程在全局上也应该看到这个顺序。顺序一致性实际上限制了各进程内指令的偏序关
    系,但不在进程间按照物理时间进行全局排序。
  • 线性一致性(Linearizability Consistency):Maurice P. Herlihy 与 Jeannette M. Wing
    在 1990 年经典论文《Linearizability: A Correctness Condition for Concurrent Objects》
    中共同提出,在顺序一致性前提下加强了进程间的操作排序,形成唯一的全局顺序(系
    统等价于是顺序执行,所有进程看到的所有操作的序列顺序都一致,并且跟实际发生顺
    序一致),是很强的原子性保证。但是比较难实现,目前基本上要么依赖于全局的时钟
    或锁,要么通过一些复杂算法实现,性能往往不高。

弱一致性(Weak Consistency)

强一致的系统往往比较难实现。很多时候,人们发现实际需求并没有那么强,可以适当放宽一致性要求,降低系统实现的难度。例如在一定约束下实现所谓最终一致性(Eventual
Consistency),即总会存在一个时刻(而不是立刻),系统达到一致的状态,这对于大部分
的 Web 系统来说已经足够了。这一类弱化的一致性,被笼统称为弱一致性(Weak
Consistency)

共识算法

实际上,要保障系统满足不同程度的一致性,往往需要通过共识算法来达成。
共识算法解决的是对某个提案(Proposal),大家达成一致意见的过程。提案的含义在分布
式系统中十分宽泛,如多个事件发生的顺序、某个键对应的值、谁是领导……等等,可以认
为任何需要达成一致的信息都是一个提案。
注:实践中,一致性的结果往往还需要客户端的特殊支持,典型地通过访问足够多个服务节
点来验证确保获取共识后结果。

问题挑战

现实中这样“完美”的系统并不存在,如响应请求往往存在时延、网络会发生中
断、节点会发生故障、甚至存在恶意节点故意要破坏系统。
一般地,把故障(不响应)的情况称为“非拜占庭错误”,恶意响应的情况称为“拜占庭错误”(对应节点为拜占庭节点)

常见算法

针对非拜占庭错误的情况,一般包括 Paxos、Raft 及其变种。
对于要能容忍拜占庭错误的情况,一般包括 PBFT 系列、PoW 系列算法等。从概率角度,PBFT 系列算法是确定的,一旦达成共识就不可逆转;而 PoW 系列算法则是不确定的,随着时间推移,被推翻的概率越来越小。
[以上算法能通最好,支付宝中有提到]

FLP 不可能性原理

FLP 不可能原理:在网络可靠,存在节点失效(即便只有一个)的最小化异步模型系统
中,不存在一个可以解决一致性问题的确定性算法。

提出该定理的论文是由 Fischer, Lynch 和 Patterson 三位作者于 1985 年发表,该论文后来获
得了 Dijkstra(就是发明最短路径算法的那位)奖。

FLP 不可能原理实际上告诉人们,不要浪费时间去为异步分布式系统设计在任意场景下都能实现共识的算法

科学告诉你什么是不可能的;工程则告诉你,付出一些代价,我可以把它变成可能。
这就是工程的魅力。
那么,退一步讲,在付出一些代价的情况下,我们能做到多少?
回答这一问题的是另一个很出名的原理:CAP 原理

CAP 原理

CAP 原理最早由 Eric Brewer 在 2000 年,ACM 组织的一个研讨会上提出猜想,后来 Lynch
等人进行了证明。
该原理被认为是分布式系统领域的重要原理。

分布式计算系统不可能同时确保一致性(Consistency)、可用性(Availablity)和分区容忍性
(Partition),设计中往往需要弱化对某个特性的保证。

  • 一致性(Consistency):任何操作应该都是原子的,发生在后面的事件能看到前面事件
    发生导致的结果,注意这里指的是强一致性;
  • 可用性(Availablity):在有限时间内,任何非失败节点都能应答请求;
  • 分区容忍性(Partition):网络可能发生分区,即节点之间的通信不可保障

应用场景
既然 CAP 不可同时满足,则设计系统时候必然要弱化对某个特性的支持。

弱化一致性
对结果一致性不敏感的应用,可以允许在新版本上线后过一段时间才更新成功,期间不保证
一致性。
例如网站静态页面内容、实时性较弱的查询类数据库等,CouchDB、Cassandra 等为此设
计。
弱化可用性
对结果一致性很敏感的应用,例如银行取款机,当系统故障时候会拒绝服务。MongoDB、
Redis 等为此设计。
Paxos、Raft 等算法,主要处理这种情况。
CAP 原理
56
弱化分区容忍性
现实中,网络分区出现概率减小,但较难避免。某些关系型数据库、ZooKeeper 即为此设
计。
实践中,网络通过双通道等机制增强可靠性,达到高稳定的网络通信

ACID 原则

即 Atomicity(原子性)、Consistency(一致性)、Isolation(隔离性)、Durability(持久
性)。

ACID 原则描述了对分布式数据库的一致性需求,同时付出了可用性的代价。
- Atomicity:每次操作是原子的,要么成功,要么不执行;
- Consistency:数据库的状态是一致的,无中间状态;
- Isolation:各种操作彼此互相不影响;
- Durability:状态的改变是持久的,不会失效。

一个与之相对的原则是 BASE(Basic Availiability,Soft state,Eventually Consistency),牺牲掉对一致性的约束(最终一致性),来换取一定的可用性。

Paxos 与 Raft

Paxos 问题是指分布式的系统中存在故障(fault),但不存在恶意(corrupt)节点场景(即
可能消息丢失或重复,但无错误消息)下的共识达成(Consensus)问题。因为最早是 Leslie
Lamport 用 Paxon 岛的故事模型来进行描述而命名。
Paxos
1990 年由 Leslie Lamport 提出的 Paxos 共识算法,在工程角度实现了一种最大化保障分布
式系统一致性(存在极小的概率无法实现一致)的机制。Paxos 被广泛应用在 Chubby、
ZooKeeper 这样的系统中,Leslie Lamport 因此获得了 2013 年度图灵奖。
故事背景是古希腊 Paxon 岛上的多个法官在一个大厅内对一个议案进行表决,如何达成统一
的结果。他们之间通过服务人员来传递纸条,但法官可能离开或进入大厅,服务人员可能偷
懒去睡觉。
Paxos 是第一个被证明的共识算法,其原理基于 两阶段提交 并进行扩展。

作为现在共识算法设计的鼻祖,以最初论文的难懂(算法本身并不复杂)出名。算法中将节点分为三种类型:

  • proposer:提出一个提案,等待大家批准为结案。往往是客户端担任该角色;
  • acceptor:负责对提案进行投票。往往是服务端担任该角色;
  • learner:被告知结案结果,并与之统一,不参与投票过程。可能为客户端或服务端。

并且,算法需要满足 safety 和 liveness 两方面的约束要求(实际上这两个基础属性是大部分分布式算法都该考虑的):

  • safety:保证决议结果是对的,无歧义的,不会出现错误情况。
    决议(value)只有在被 proposers 提出的 proposal 才能被最终批准;
    在一次执行实例中,只批准(chosen)一个最终决议,意味着多数接受(accept)
    的结果能成为决议;
  • liveness:保证决议过程能在有限时间内完成。
    决议总会产生,并且 learners 能获得被批准(chosen)的决议。

基本过程包括 proposer 提出提案,先争取大多数 acceptor 的支持,超过一半支持时,则发送
结案结果给所有人进行确认。一个潜在的问题是 proposer 在此过程中出现故障,可以通过超
时机制来解决。极为凑巧的情况下,每次新的一轮提案的 proposer 都恰好故障,系统则永远
无法达成一致(概率很小)。

Paxos 能保证在超过 的正常节点存在时,系统能达成共识。

单个提案者+多接收者

如果系统中限定只有某个特定节点是提案者,那么一致性肯定能达成(只有一个方案,要么达成,要么失败)。提案者只要收到了来自多数接收者的投票,即可认为通过,因为系统中
不存在其他的提案。
但一旦提案者故障,则系统无法工作。

多个提案者+单个接收者

限定某个节点作为接收者。这种情况下,共识也很容易达成,接收者收到多个提案,选第一个提案作为决议,拒绝掉后续的提案即可。
缺陷也是容易发生单点故障,包括接收者故障或首个提案者节点故障。
以上两种情形其实类似主从模式,虽然不那么可靠,但因为原理简单而被广泛采用。
当提案者和接收者都推广到多个的情形,会出现一些挑战。

多个提案者+多个接收者

既然限定单提案者或单接收者都会出现故障,那么就得允许出现多个提案者和多个接收者。
问题一下子变得复杂了。
一种情况是同一时间片段(如一个提案周期)内只有一个提案者,这时可以退化到单提案者的情形。需要设计一种机制来保障提案者的正确产生,例如按照时间、序列、或者大家猜拳(出一个数字来比较)之类。考虑到分布式系统要处理的工作量很大,这个过程要尽量高效,满足这一条件的机制非常难设计。

另一种情况是允许同一时间片段内可以出现多个提案者。那同一个节点可能收到多份提案,怎么对他们进行区分呢?这个时候采用只接受第一个提案而拒绝后续提案的方法也不适用。很自然的,提案需要带上不同的序号。节点需要根据提案序号来判断接受哪个。比如接受其中序号较大(往往意味着是接受新提出的,因为旧提案者故障概率更大)的提案。

如何为提案分配序号呢?一种可能方案是每个节点的提案数字区间彼此隔离开,互相不冲突。为了满足递增的需求可以配合用时间戳作为前缀字段。
此外,提案者即便收到了多数接收者的投票,也不敢说就一定通过。因为在此过程中系统中其它提案者

两阶段的提交

提案者发出提案之后,收到一些反馈。这个时候得知的一种结果是自己的提案被大多数接受
了,一种结果是没被接受。没被接受的话好说,过会再试试。

即便受到来自大多数的接受反馈,也不能认为就最终确认了。因为这些接收者自己并不知道自己刚反馈的提案就恰好是全局的绝大多数。

那么引入了新的一个阶段,即提案者在前一阶段拿到所有的反馈后,判断这个提案是可能被大多数接受的提案,需要对其进行最终确认。
Paxos 里面对这两个阶段分别命名为准备(prepare)和提交(commit)。准备阶段解决大家对哪个提案进行投票的问题,提交阶段解决确认最终值的问题。

准备阶段:

  • 提案者发送自己计划提交的提案的编号到多个接受者,试探是否可以锁定多数接受者的支持。
  • 接受者时刻保留收到过提案的最大编号和接受的最大提案。如果收到提案号比目前保留的最大提案号还大,则返回自己已接受的提案值(如果还未接受过任何提案,则为空)给提案者,更新当前最大提案号,并说明不再接受小于最大提案号的提案。

提交阶段:

  • 提案者如果收到大多数的回复(表示大部分人听到它的请求),则可准备发出带有刚才提案号的接受消息。如果收到的回复中不带有新的提案,说明锁定成功。则使用自己的提案内容;如果返回中有提案内容,则替换提案值为返回中编号最大的提案值。如果没收到足够多的回复,则需要再次发出请求。
  • 接受者收到接受消息后,如果发现提案号不小于已接受的最大提案号,则接受该提案,并更新接受的最大提案。

一旦多数接受了共同的提案值,则形成决议,成为最终确认。

Raft

Raft 是对 Paxos 的重新设计和实现。
Raft 算法是Paxos 算法的一种简化实现。
包括三种角色:leader、candiate 和 follower,其基本过程为:

  • Leader 选举:每个 candidate 随机经过一定时间都会提出选举方案,最近阶段中得票最
    多者被选为 leader;
  • 同步 log:leader 会找到系统中 log 最新的记录,并强制所有的 follower 来刷新到这个记录;

注:此处 log 并非是指日志消息,而是各种事件的发生记录。

拜占庭问题与算法

拜占庭问题更为广泛,讨论的是允许存在少数节点作恶(消息可能被伪造)场景下的一致性达成问题。拜占庭算法讨论的是最坏情况下的保障。

Byzantine Fault Tolerant 算法
面向拜占庭问题的容错算法,解决的是网络通信可靠,但节点可能故障情况下的一致性达
成。
最早由 Castro 和 Liskov 在 1999 年提出的 Practical Byzantine Fault Tolerant(PBFT)是第
一个得到广泛应用的 BFT 算法。只要系统中有 的节点是正常工作的,则可以保证一致
性。
PBFT 算法包括三个阶段来达成共识:Pre-Prepare、Prepare 和 Commit。

新的解决思路
拜占庭问题之所以难解,在于任何时候系统中都可能存在多个提案(因为提案成本很低),
并且要完成最终的一致性确认过程十分困难,容易受干扰。但是一旦确认,即为最终确认。
比特币的区块链网络在设计时提出了创新的 PoW(Proof of Work) 算法思路。一个是限制一
段时间内整个网络中出现提案的个数(增加提案成本),另外一个是放宽对最终一致性确认
的需求,约定好大家都确认并沿着已知最长的链进行拓宽。系统的最终确认是概率意义上的
存在。这样,即便有人试图恶意破坏,也会付出很大的经济代价(付出超过系统一半的算
力)。
后来的各种 PoX 系列算法,也都是沿着这个思路进行改进,采用经济上的惩罚来制约破坏
者。

密码学技术

工程领域从来没有黑科技;密码学不是工程。
密码学在信息技术领域的重要地位无需多言。如果没有现代密码学的研究成果,人类社会根本无法进入信息时代。
密码学领域十分繁杂,本章将介绍密码学领域中跟区块链相关的一些基础知识,包括 hash 算
法与摘要、加密算法、数字签名和证书、PKI 体系、Merkle 树、同态加密等,以及如何使用
这些技术实现信息的机密性、完整性、认证性和不可抵赖性。

Hash 算法

定义

Hash (哈希或散列)算法是信息技术领域非常基础也非常重要的技术。它能任意长度的二进制值(明文)映射为较短的固定长度的二进制值(Hash 值),并且不同的明文很难映射为相同的 Hash 值。

例如计算一段话“hello blockchain world, this is yeasy@github”的 MD5 hash 值为
89242549883a2ef85dc81b90fb606046

注:MD5 是一个经典的 hash 算法,其和 SHA-1 算法都已被 证明 安全性不足应用于商业场景。

一个优秀的 hash 算法,将能实现:

  • 正向快速:给定明文和 hash 算法,在有限时间和有限资源内能计算出 hash 值。
  • 逆向困难:给定(若干) hash 值,在有限时间内很难(基本不可能)逆推出明文。
  • 输入敏感:原始输入信息修改一点信息,产生的 hash 值看起来应该都有很大不同。
  • 冲突避免:很难找到两段内容不同的明文,使得它们的 hash 值一致(发生冲突)。

冲突避免有时候又被称为“抗碰撞性”。如果给定一个明文前提下,无法找到碰撞的另一个明文,称为“弱抗碰撞性”;如果无法找到任意两个明文,发生碰撞,则称算法具有“强抗碰撞性”。

很多场景下,也要求对于任意长的输入内容,输出定长的 hash 结果。

流行的算法
目前流行的 Hash 算法包括 MD5、SHA-1 和 SHA-2。

使用案例:数字摘要
顾名思义,数字摘要是对数字内容进行 Hash 运算,获取唯一的摘要值来指代原始数字内容。
数字摘要是解决确保内容没被篡改过的问题(利用 Hash 函数的抗碰撞性特点)。

加解密算法

对称加密

  • 加解密密钥相同或可推算,计算效率高,加密强度高需提前共享密钥;
  • 易泄露
  • DES、3DES、AES、IDEA

非对称加密
- 加解密密钥不相关,无需提前共享密钥
- 计算效率低,仍存在中间人攻击可能
- RSA、ElGamal、椭圆曲线系列算法

猜你喜欢

转载自blog.csdn.net/zjcjava/article/details/80888831