共计 1146 个字符,预计需要花费 3 分钟才能阅读完成。
1、Elasticsearch 并发冲突问题
对于一般的 ES 操作流程是:1、先 get document 数据, 比如获取到商品数据,将数据显示到网页上,同时在内存中缓存该 documentd 的数据 2、当网页发生了购买后,直接基于内存中的数据,进行计算和操作 3、将计算后的结果写回 ES 中
下面描述一下场景比如在电商场景下,假设说,我们有一个程序,工作流程如下:1、读取商品的信息 2、用户下单购买 3、更新商品信息(主要是将库存减 1)我们假设程序是多线程的,所以说可能有多个线程并发的去执行上述的 3 个步骤流程
将上述场景具体到某个商品的库存修改的时候,假设一个牙膏的库存是 100 件,现在同时有两个人都过来读取了牙膏的数据,然后下单购买了这管牙膏,此时两个线程并发执行,同时在进行商品库存的修改。
如图所示,在正常的情况下,我们期望线程 A 将库存 -1,设置为 99 件;然后线程 B 接着这个 99 件,将库存 -1,变为 98 件,然后写入到 ES 中。但是总有一个线程是先到的,假设就是线程 A,此时线程 A 就会先将牙膏的库存设置为 99 件,然后线程 B 再次将牙膏的库存设置为 99 件,结果很显然就不是我们想要的。
上述的这个流程,其实就是 ES 中的并发冲突问题,会导致数据不准确。
2、悲观锁与乐观锁两种并发控制方案
这里先附上中华石衫老师画的手工图
下面简单做一下描述和概括悲观锁:所谓悲观锁就是在任何情况下都上锁,上锁之后,就只有一个线程可以操作这一条数据,其它线程只能等待,当然在不同的场景下,上的锁会有所不同,可以是行级锁,表级锁,读锁,写锁。通俗的来讲,加了悲观锁的话,对数据操作的时候就相当于是单线程的了。乐观锁:其实所谓的乐观锁,根本就没有加锁,只是多了一标识字段,这个字段可以是一个整数类型的,也可以是时间类型的。主要的作用就是在每次修改数据的时候会做一层判断,判断数据是否已经被修改过了,如果已经被修改了,那么就会重新获取数据,在修改,这个过程不断进行知道数据修改成功。
下面比较一下两种锁的优缺点 1、对于悲观锁,它使用起来很方便,直接加锁就可以了,对于应用程序来说,它是透明的,不需要做额外的操作。但是每次都需要获取到锁之后才能对数据进行修改,也就是同一时间只能有一个线程能够进行操作,并发能力很低 2、对于乐观锁,它根本就没有加锁,所以并发能力很高。但是每次更新数据的时候都需要对标识字段做一个判断,这个过程可能要重复很多遍。而且是需要应用程序做处理的。
3、Elasticseach 基于_version 进行乐观锁的并发控制
对于 ES 来说,它是采用乐观锁,对应的乐观锁的标识字段是_version,是一个整数类型,一开始创建 document 时,_version 是等于 1 的,之后对 document 每修改一次,_version 版本号就会自动加 1。