面试题答案
一键面试-
使用 ElasticSearch 更新 API 实现业务逻辑
- ElasticSearch 的更新 API 支持使用脚本(Scripting)来实现复杂的更新操作。假设商品文档在索引
ecommerce
中,类型为product
,文档 ID 为{product_id}
。 - 可以使用如下的更新请求:
POST /ecommerce/product/{product_id}/_update { "script": { "source": "if (ctx._source.stock >= params.quantity) { ctx._source.stock -= params.quantity; ctx._source.purchase_time = new Date(); return true; } else { return false; }", "lang": "painless", "params": { "quantity": 1 // 购买数量,这里假设购买 1 个商品,实际根据业务调整 } }, "upsert": {} }
- 解释:
script
部分包含更新逻辑。ctx._source
表示当前文档的源数据。首先检查库存ctx._source.stock
是否大于等于购买数量params.quantity
,如果满足条件,则减少库存并记录当前购买时间ctx._source.purchase_time = new Date()
,最后返回true
表示更新成功;否则返回false
表示库存不足更新失败。lang
指定脚本语言为 Painless,这是 ElasticSearch 内置的脚本语言。params
用于传递参数,这里传递购买数量。upsert
部分在文档不存在时会创建一个新文档,这里为空,因为假设商品文档已经存在。
- ElasticSearch 的更新 API 支持使用脚本(Scripting)来实现复杂的更新操作。假设商品文档在索引
-
处理并发操作的数据一致性问题
- 乐观并发控制:
- ElasticSearch 支持乐观并发控制。每次文档更新时,ElasticSearch 会检查文档的版本号。如果版本号与预期不符,说明文档在读取和更新之间被其他操作修改过,更新请求会失败。可以在更新请求中带上版本号参数来实现乐观并发控制。例如:
POST /ecommerce/product/{product_id}/_update?if_seq_no={seq_no}&if_primary_term={primary_term} { "script": { "source": "if (ctx._source.stock >= params.quantity) { ctx._source.stock -= params.quantity; ctx._source.purchase_time = new Date(); return true; } else { return false; }", "lang": "painless", "params": { "quantity": 1 } }, "upsert": {} }
- 其中
{seq_no}
和{primary_term}
可以通过之前获取文档时得到,在更新时带上这两个参数,ElasticSearch 会验证文档版本,如果不一致则更新失败,客户端可以根据情况进行重试。
- 使用分布式锁:
- 可以借助分布式锁(如 Redis 实现的分布式锁)来处理并发。在进行商品购买操作前,先获取分布式锁。只有获取到锁的客户端才能进行库存更新和记录购买时间的操作,操作完成后释放锁。这样可以避免多个客户端同时更新库存导致的数据不一致问题。具体实现步骤如下:
- 使用 Redis 的
SETNX
(SET if Not eXists)命令尝试获取锁,例如SETNX lock:product:{product_id} value
,其中lock:product:{product_id}
是锁的键,value
可以是任意唯一值(如当前时间戳),用于标识获取锁的客户端。如果SETNX
返回1
,表示获取锁成功;返回0
表示锁已被其他客户端持有,获取锁失败。 - 获取锁成功的客户端执行 ElasticSearch 的更新操作。
- 操作完成后,使用 Redis 的
DEL
命令释放锁,即DEL lock:product:{product_id}
。
- 使用 Redis 的
- 可以借助分布式锁(如 Redis 实现的分布式锁)来处理并发。在进行商品购买操作前,先获取分布式锁。只有获取到锁的客户端才能进行库存更新和记录购买时间的操作,操作完成后释放锁。这样可以避免多个客户端同时更新库存导致的数据不一致问题。具体实现步骤如下:
- 乐观并发控制:
通过上述方法,可以有效地使用 ElasticSearch 更新 API 实现原子性更新库存和记录购买时间的业务逻辑,并通过乐观并发控制或分布式锁来处理并发操作带来的数据一致性问题。