当前位置:首页 > 技术 > 正文内容

Elasticsearch文档并发更新冲突解决方案

访客 技术 2026年6月30日 1

1. 乐观锁机制实现

分布式环境中ES的异步并发特性导致文档复制请求乱序到达,可能引发新版本被旧版本覆盖的问题。通过版本号控制可确保操作顺序:

// 连接配置示例
TransportClient esClient = null;

@Before
public void initConnection() {
    Settings config = Settings.builder()
        .put("cluster.name", "es_cluster").build();
    try {
        esClient = new PreBuiltTransportClient(config)
            .addTransportAddress(new InetSocketTransportAddress(
                InetAddress.getByName("es-node1"), 9300));
    } catch (Exception e) { e.printStackTrace(); }
}

// 并发更新测试
@Test
public void concurrentUpdateTest() throws InterruptedException {
    ExecutorService pool = Executors.newFixedThreadPool(4);
    for (int i = 0; i < 8; i++) {
        pool.execute(new UpdateWorker()); 
    }
    Thread.sleep(15000);
    pool.shutdown();
}

class UpdateWorker implements Runnable {
    public void run() {
        try {
            IndexRequest initReq = new IndexRequest("products", "item", "101")
                .source(XContentFactory.jsonBuilder()
                    .startObject()
                    .field("sku", "P101")
                    .endObject());
                    
            UpdateRequest updateReq = new UpdateRequest("products", "item", "101")
                .doc(XContentFactory.jsonBuilder()
                    .startObject()
                    .field("thread_id", Thread.currentThread().getId())
                    .endObject())
                .upsert(initReq);
                
            esClient.update(updateReq).get();
        } catch (Exception e) { e.printStackTrace(); }
    }
}

@After
public void closeClient() { esClient.close(); }

ES通过_version确保操作顺序,当旧版本后到达时自动忽略:

PUT /inventory/items/201
{ "name": "T-shirt", "stock": 50 }

带版本更新:

PUT /inventory/items/201?version=1
{ "name": "T-shirt", "stock": 45 }

版本冲突时将返回409状态码。

2. 外部版本控制

使用version_type=external时,仅当提供版本号大于当前版本才允许更新:

PUT /orders/details/305?version=10&version_type=external
{ "status": "shipped" }

若提供版本号小于当前版本将操作失败。

3. 冲突重试机制

多用户场景下使用retry_on_conflict参数自动重试:

POST /logs/access/1/_update?retry_on_conflict=3
{
   "script": "ctx._source.visit_count+=1",
   "upsert": { "visit_count": 1 }
}

设置retry_on_conflict=3表示失败时最多重试3次。

4. 悲观锁实践

通过全局锁限制并发:

PUT /system/locks/global/_create
{}

文档级锁使用Groovy脚本:

// lock_script.groovy
if (ctx._source.lock_owner != owner_id) { 
    assert false 
} 
ctx.op = 'noop'

共享/排他锁实现:

// shared_lock.groovy
if (ctx._source.lock_mode == 'exclusive') {
    assert false
} else {
    ctx._source.lock_counter++
}

释放锁:

// unlock_script.groovy
if (ctx._source.lock_mode == "shared") {
    ctx._source.lock_counter--
};
if (ctx._source.lock_counter == 0) { 
    ctx.op = 'delete' 
}

相关文章

Linux crontab 详解

1) crontab 是什么cron 是 Linux 的定时任务守护进程;crontab 是用来编辑/查看“按时间周期执行命令”的表(cron table)。常见两类:用户 crontab:每个用户一份(crontab -e 编辑)系统级 crontab / cron.d:可指定执行用户(/etc/crontab、/etc/cron.d/*)2) crontab 时间...

富文本里可以允许的 HTML 属性

一、所有标签默认允许的安全属性(极少)class        (可选)id           (通常建议禁用)title️ 注意:id 容易被滥用做锚点注入,很多系统直接禁用class 允许的话最好只允许固定前缀(如 editor-*)二、a 标签允许属性<a href="" t...

Mac 安装 Node.js 指南

方法一:通过官网安装包(最简单,适合初学者)如果你只是想快速安装并开始使用,这是最直接的方法。访问 Node.js 官网。页面会显示两个版本:LTS (Recommended For Most Users):长期支持版,最稳定。建议选这个。Current:最新特性版,包含最新功能但可能不够稳定。下载 .pkg 安装包并运行。按照安装向导点击“下一步”即可完成。方法二:使用 Homebrew 安装(...

Dom\HTML_NO_DEFAULT_NS 的副作用:自动加闭合标签

在使用Dom\HTMLDocument时,Dom\HTML_NO_DEFAULT_NS 将禁止在解析过程中设置元素的命名空间, 此设置是为了与DOMDocument向后兼容而存在的。当使用它时,已知的一个副作用就是:自动加闭合标签例如 </img> 为什么会这样?当你使用:Dom\HTML_NO_DEFAULT_NS文档会变成 无命名空间模式,此时内部更接近 XML...

Laravel 事件和监听器创建

在 Laravel 中,使用 Artisan 命令创建 Events(事件) 和 Listeners(监听器) 是非常高效的。你可以通过以下几种方式来实现:1. 手动创建单个 Event如果你只想创建一个事件类,可以使用 make:event 命令:Bashphp artisan make:event UserRegistered执行后,文件将生成在 app/Even...

自定义域名解析神器 dnsmasq

什么是 dnsmasq?dnsmasq 是一个轻量级、功能强大的网络服务工具,专为小型和中等规模网络设计。它是一个综合的网络基础设施解决方案[1]。dnsmasq 能做什么?功能说明应用场景DNS 转发与缓存将 DNS 查询转发到上游服务器(ISP、Google DNS 等),并在本地缓存结果加快 DNS 查询速度,减少外部 DNS 流量本地 DNS解析本地网络设备的主机名,无需编辑&n...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。