1、并发冲突问题

image.png
image.png

2、图解剖析悲观锁与乐观锁两种并发控制方案

image.png

3、图解Elasticsearch内部如何基于_version进行乐观锁并发控制

(1)_version元数据
在第一次创建document时内部的_version的内部版本号就为1,每次多document进行增删改时,_version就自动加1
在delete之后,在进行put数据,内部版本号还在+1,这就侧面说明,在delete之后,数据并没有被删除, 他的内部_version等信息还存在。
(2)在es 7.9版本,是基于if_seq_no和if_primary_term进行乐观锁并发控制

  1. PUT /bobotest/_doc/5/
  2. {
  3. "name": "lisi",
  4. "desc": "piaoliang de keai de xiaogege111",
  5. "age": 15,
  6. "tags":"shuaige"
  7. }
  8. {
  9. "_index" : "bobotest",
  10. "_type" : "_doc",
  11. "_id" : "5",
  12. "_version" : 2, #版本号加1
  13. "_seq_no" : 17,
  14. "_primary_term" : 1,
  15. "found" : true,
  16. "_source" : {
  17. "name" : "lisi",
  18. "desc" : "piaoliang de keai de xiaogege111",
  19. "age" : 15,
  20. "tags" : "shuaige"
  21. }
  22. }

image.png
验证
先创建filed=test1,然后修改_version=1 filed=test2 后修改_version=2 filed=test3

  1. #创建document
  2. PUT /bobotest/_doc/7/
  3. {
  4. "filed": "test1"
  5. }
  6. {
  7. "_index" : "bobotest",
  8. "_type" : "_doc",
  9. "_id" : "7",
  10. "_version" : 1,
  11. "result" : "created",
  12. "_shards" : {
  13. "total" : 2,
  14. "successful" : 1,
  15. "failed" : 0
  16. },
  17. "_seq_no" : 19,
  18. "_primary_term" : 1
  19. }
  20. #修改if_seq_no=19&if_primary_term=1 "filed": "test3"
  21. PUT /bobotest/_doc/7?if_seq_no=19&if_primary_term=1
  22. {
  23. "filed": "test3"
  24. }
  25. #修改if_seq_no=20&if_primary_term=1 "filed": "test3"
  26. PUT /bobotest/_doc/7?if_seq_no=20&if_primary_term=1
  27. {
  28. "filed": "test4"
  29. }
  30. 正确顺序: test1 -->test3-->test4

并发时

  1. test4test3同时更新
  2. test1 -->test3
  3. PUT /bobotest/_doc/7?if_seq_no=21&if_primary_term=1 #后改的先到
  4. {
  5. "filed": "test4"
  6. }
  7. PUT /bobotest/_doc/7?if_seq_no=21&if_primary_term=1 #先改的后到
  8. {
  9. "filed": "test6"
  10. }
  11. #产生错误,抛弃
  12. {
  13. "error" : {
  14. "root_cause" : [
  15. {
  16. "type" : "version_conflict_engine_exception",
  17. "reason" : "[7]: version conflict, required seqNo [22], primary term [1]. current document has seqNo [23] and primary term [1]",
  18. "index_uuid" : "tdMcqHK5ReOYmOAxPWoqUQ",
  19. "shard" : "0",
  20. "index" : "bobotest"
  21. }
  22. ],
  23. "type" : "version_conflict_engine_exception",
  24. "reason" : "[7]: version conflict, required seqNo [22], primary term [1]. current document has seqNo [23] and primary term [1]",
  25. "index_uuid" : "tdMcqHK5ReOYmOAxPWoqUQ",
  26. "shard" : "0",
  27. "index" : "bobotest"
  28. },
  29. "status" : 409
  30. }
  31. #重新get if_seq_no和_primary_term的信息。
  32. GET /bobotest/_doc/7
  33. {
  34. "_index" : "bobotest",
  35. "_type" : "_doc",
  36. "_id" : "7",
  37. "_version" : 5,
  38. "_seq_no" : 23,
  39. "_primary_term" : 1,
  40. "found" : true,
  41. "_source" : {
  42. "filed" : "test4"
  43. }
  44. }
  45. #带上_seq_no=23和_primary_term=1进行修改
  46. PUT /bobotest/_doc/7?if_seq_no=23&if_primary_term=1
  47. {
  48. "filed": "test6"
  49. }
  50. {
  51. "_index" : "bobotest",
  52. "_type" : "_doc",
  53. "_id" : "7",
  54. "_version" : 6,
  55. "result" : "updated",
  56. "_shards" : {
  57. "total" : 2,
  58. "successful" : 1,
  59. "failed" : 0
  60. },
  61. "_seq_no" : 24,
  62. "_primary_term" : 1
  63. }

4、external version并发版本控制

https://www.elastic.co/guide/en/elasticsearch/reference/7.1/docs-index_.html#_version_types
在es 7.9版本,index的内部版本并发控制改为_seq_no和_primary_term
但是如果使用external 版本控制,还是使用原先的方式_version &version_type=external
_version 必须>内部_version 的版本号

  1. 1)创建索引
  2. PUT /liang/_doc/1
  3. {
  4. "filed": "test1"
  5. }
  6. {
  7. "_index" : "liang",
  8. "_type" : "_doc",
  9. "_id" : "1",
  10. "_version" : 1,
  11. "result" : "created",
  12. "_shards" : {
  13. "total" : 2,
  14. "successful" : 1,
  15. "failed" : 0
  16. },
  17. "_seq_no" : 0,
  18. "_primary_term" : 1
  19. }
  20. (2)带入版本进行修改_version 必须>内部_version 的版本号
  21. PUT /liang/_doc/1?version=2&version_type=external
  22. {
  23. "filed": "test2"
  24. }
  25. {
  26. "_index" : "liang",
  27. "_type" : "_doc",
  28. "_id" : "1",
  29. "_version" : 2,
  30. "result" : "updated",
  31. "_shards" : {
  32. "total" : 2,
  33. "successful" : 1,
  34. "failed" : 0
  35. },
  36. "_seq_no" : 1,
  37. "_primary_term" : 1
  38. }
  39. (3)使用客户端1更新此version=2版本的数据
  40. PUT /liang/_doc/1?version=2&version_type=external
  41. {
  42. "filed": "test2"
  43. }
  44. {
  45. "_index" : "liang",
  46. "_type" : "_doc",
  47. "_id" : "1",
  48. "_version" : 3,
  49. "result" : "updated",
  50. "_shards" : {
  51. "total" : 2,
  52. "successful" : 1,
  53. "failed" : 0
  54. },
  55. "_seq_no" : 2,
  56. "_primary_term" : 1
  57. }
  58. 4)使用客户端2更新version=2版本的数据(由于两个客户端同时更新,所以版本号一致)
  59. PUT /liang/_doc/1?version=2&version_type=external
  60. {
  61. "filed": "test3"
  62. }
  63. {
  64. "error" : {
  65. "root_cause" : [
  66. {
  67. "type" : "version_conflict_engine_exception",
  68. "reason" : "[1]: version conflict, current version [3] is higher or equal to the one provided [2]",
  69. "index_uuid" : "Vs-63nbZT8qDPo2MCJ43xg",
  70. "shard" : "0",
  71. "index" : "liang"
  72. }
  73. ],
  74. "type" : "version_conflict_engine_exception",
  75. "reason" : "[1]: version conflict, current version [3] is higher or equal to the one provided [2]",
  76. "index_uuid" : "Vs-63nbZT8qDPo2MCJ43xg",
  77. "shard" : "0",
  78. "index" : "liang"
  79. },
  80. "status" : 409
  81. }
  82. 5)出现错误,重新get ,进行更新
  83. GET /liang/_doc/1
  84. {
  85. "_index" : "liang",
  86. "_type" : "_doc",
  87. "_id" : "1",
  88. "_version" : 3,
  89. "_seq_no" : 2,
  90. "_primary_term" : 1,
  91. "found" : true,
  92. "_source" : {
  93. "filed" : "test3"
  94. }
  95. }
  96. version=4&version_type=externalversion必须要比_version
  97. PUT /liang/_doc/1?version=4&version_type=external
  98. {
  99. "filed": "test3"
  100. }
  101. {
  102. "_index" : "liang",
  103. "_type" : "_doc",
  104. "_id" : "1",
  105. "_version" : 4,
  106. "result" : "updated",
  107. "_shards" : {
  108. "total" : 2,
  109. "successful" : 1,
  110. "failed" : 0
  111. },
  112. "_seq_no" : 3,
  113. "_primary_term" : 1
  114. }