问题引发的关于原子性与锁的逐步探讨

68 阅读2分钟

导读

有一个分布式的系统,系统的其中一个接口功能是获取一个连续的、递增的编码;

这个获取获取一个连续的、递增的编码的接口逻辑无非就是三步:

  1. 从存储系统中拿出编码
  2. 编码值加一写回存储系统
  3. 返回编码值

伪代码

上述功能接口伪代码如下

int code = selectCode();//从存储系统中拿出编码

updateCode(code+1);//编码值加一,写回存储系统

return code;//返回编码值

即每次调用这个接口获取返回值为1、2、3、4一直递增;

进一步探讨

可想而知,会遇到的问题如下:

  1. 节点A和节点B同时请求接口,如何保证节点A和节点B是获取到的连续递增的编码,节点A获取了编码为2之后,编码递增还没回写到存储系统,节点B也来获取编码,节点B得到的值也是2,但节点B应该获取的正确的值是3
  2. 另外一个问题就是,从上一个问题中衍生出来;当节点A去获取编码的时候,那么节点B就应该排队等待节点A先获取编码,而不是同时去拿编码,导致获取同一个编码

概念引入

这里我们先引入一个【原子性】概念:

原子性:是指一个操作不可中断,要么全部成功,要么全部失败,不可能存在成功一部分,失败一部分的情况。

导致上面提到的第一个问题出现的原因之一就是没有考虑原子性;

当节点A请求接口时,接口逻辑开始执行,从取出编码,递增并回写编码到最后返回编码,应该一气呵成。

但是,就算一气呵成的昨晚这一系列操作,很明显还是无法避免节点B也拿到同样编码;

这个时候就需要锁的出现:

我们在 节点A 请求的时候,把这个方法给锁起来,不让其它节点来请求,等接口方法 一气呵成 的执行完 之后,再把锁解开,让其它节点可以请求这个方法。

结语

至此,通过原子性和锁,就保证了准确无误的实现 获取一个连续的、递增的编码 的功能。

通过这篇文档的探讨,引入了原子性和锁的概念,计划接下来的文章采用Rediss+Redisson分布式锁来实现这个功能。

文章逻辑和思路有什么问题,欢迎在评论区指出,一起讨论。