分布式一致性思想描述及Paxos算法学习

讲述的不完全正确,后面有时间改,请先不要阅读。

在分布式的情况下,出于可用性(单点问题导致全部不可用)和规模性(单点支撑能力有限)的考虑,通过使用多个参与者提供服务。

如何保证通过多个参与者写入和读取的值相同,即分布式中的数据一致性,是一个复杂的问题。

为了保持一致性,一般是两种方案,一种是所有节点每个事务里都一致(强一致);另一种不是所有节点在每个事物里都完全一致,比如采用主节点先更新,其他节点追加式更新的模式。

强一致模式下,服务可能会因为等待所有节点的同步更新和反馈,服务变得非常慢或者中断。节点间不完全一致的模式,如果仅看一个节点,可能在主节点崩溃后,其他节点没有最新数据。

受分布式系统不可靠特点的影响,多个参与者在一个事物里不一致将是常态,因此使用强一致模式会容易出现不能达到或代价太高的问题。

两阶段和三阶段提交的本质都是想要达到强一致,即通过先做准备工作,参与者在准备工作做完后进入准备状态的一致,然后再一起做提交操作,达到参与者都一致的目的。但很明显,提交操作过程中还可能有新的不一致情况,所以不能保证达到强一致效果。

另外一条道路就是节点状态不一定完全一致,但是还可以达到写入和读取数据的值相同的效果。

从直观感觉上想到的是,要么取一个维度的最值情况来确定一个值,比如取一个最新时间等;要么取大家投票的方式,取多数的原则来确定一个值。

按照一个维度取最值的方法,困难在于不稳定性和误差。取多个节点(提供服务的参与者)中最新时间更新的值,取数指令发出后,可能记录最新时间更新值的节点宕机或网络不可达,那么就会出现读写不一致的问题。写进去的最新值是100,但读出来可能是50。即使节点和网络都正常,也还会存在授时误差的问题,节点1比节点2绝对时间新,但节点2的误差原因造成节点2记录的是最新的,也会导致读写不一致的问题。

基于上述情况,只能考虑基于大家投票的方式,取投票占到一半以上的值作为最终值(用一半以上是为了保证唯一性)。paxos算法就是此类算法。

因为paxos是理论性的研究,具体的工程实践差别较大,下面从我想到的两个经典例子进行说明。在例子中,使用3个请求者,5个分布式服务提供者。

例如,5个服务提供者最后更新的值,分别是:1,2,3,2,2那么投票结果就是2为最终值。如果没有一半以上的要求,那么1,2,2,3,3,3的情况就会没法得到最终状态值了。

1. 更新操作

最简单的情况是<key, old_value>更新成<key, new_value>的过程。

3个请求者分别发送一个或多个请求,将一个key的value进行更新。因为没有时间戳,服务提供者只能按照到达的时间先后顺序来更新值。

这种情况没有严格的时间顺序,不同服务提供者的更新情况可能差距很多,然后给最后更新值对应的请求者发送更新成功,给其他请求者发送更新失败。当然从理论上讲也是可以的,但是想达到一半以上很困难。

为了提升效率,可以在请求中加入时间戳,也就是<key, new_value, timestamp>的格式,这样服务提供者在接收到后可以根据时间来判断是否要更新,如果更大的时间值(更大意味着更晚的时间)那么就更新值,否则就不更新值,5个服务者更容易达成一致。

这样还不够,因为可能请求者1读取现在key对应的值是3,想更新成5,但是它的请求达到服务提供者时,该key对应的值可能已经被更新成8了,这时再更新成5不见得是预期效果,所以最好还要加上原值,如果原值不匹配的话更新失败,这样确保可以达到预期的更新效果。也就是<key, old_value, new_value, timestamp>的格式。

在更新操作中,使用这样的请求格式,如果一半以上的服务提供者返回了更新成功的结果,那么更新就认为是成功了。如果有服务提供者出现故障,通过多数的数量优势,恢复最后的值。如果3个更新成功,2个更新不成功,然后有1个更新成功的节点宕掉,这样应该是依赖于宕掉节点是否在日志中记录了成功的状态。如果记录了,恢复后认为更新成功,否则认为更新失败(当然这是工程手段,可能根据场景不同而不同)。

2. 插入操作

插入操作跟更新操作的不同之处在于其key值是不确定的,因此多了一个先要生成唯一key值的过程。

从理论上讲,可以每个请求者随机生成一个key值,但在工程上,为了符合key值的规则和后续查询的效率,通常是先去取一个当前最大的key值,然后做+1操作。

从理论上讲,有了这个key值以后,就可以加上value值发起请求进行更新操作;服务提供者接收到请求后,如果key值已经被占用那么直接返回失败,否则就进行插入操作,如果一半以上服务提供者都返回了成功,那么插入就成功了。

但在工程上看,多个请求者高并发进行访问时,可能会出现拿着同样的key值进行更新的情况,这样服务提供者会跟第一种更新的情况一样,插入完成具有随机性,会因为多个插入的碰撞导致效率比较差。

因此还是需要加上时间这个附加因素,又变成了<key, value, time_stamp>的组成结构,当然也可以把time_stamp和key组合在一起,这样可以进一步减少key值相同的可能,并把time_stamp放在高位上,确保时间新旧的可以通过比较大小获得。

这样就可以使用<key, value, time_stamp>或<key+time_stamp, value>格式进行插入操作了,当请求者把该请求发送给所有的服务提供者时,服务提供者按照时间是否更大的原则进行插入操作,如果一半以上的服务提供者返回了成功,那么这个操作就完成了。当然也可能出现下面的情况:

1)可能会出现key值被占用的返回,因为可能多个请求者都读取了最大key值然后进行了+1操作。

  为了减少这个环节的冲突,可以先进行一次预请求,请求者先拿着key值进行请求,如果服务提供者插入过该key值,那么就反馈一个已经占用,否则就反馈没有占用。当然服务提供者此时并不会停止接受新的请求,可能下一时间就有其他请求者使用了这个key值,所以key值反馈不一定是对的。这是从工程上减少概率而已。我感觉这种情况适用于要插入的value值特别长的情况,这样因为冲突而造成的网络和时间浪费较大,所以通过预请求尽量避免一下。

 2)可能出现一半或以下服务提供者返回成功的情况。存在另外一个请求者也使用该key值,不同的服务请求者插入了不同的value值。

以上基本上把原理说明了一下,但在工程实践中实现可能差距很大,可以根据具体的场景具体设计。

转载于:https://www.cnblogs.com/hoopoe/p/8030102.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值