愚者求师之过,智者从师之长。
Elasticsearch

Elasticsearch

ES 调优帖:Gateway 批量写入性能优化实践

ElasticsearchINFINI Labs 小助手 发表了文章 • 0 个评论 • 1378 次浏览 • 5 天前 • 来自相关话题

背景:bulk 优化的应用

在 ES 的写入优化里,bulk 操作被广泛地用于批量处理数据。bulk 操作允许用户一次提交多个数据操作,如索引、更新、删除等,从而提高数据处理效率。bulk 操作的实现原理是,将数据操作请求打包成 HTTP 请求,并批量提交给 Elasticsearch 服务器。这样,Elasticsearch 服务器就可以一次处理多个数据操作,从而提高处理效率。

这种优化的核心价值在于减少了网络往返的次数和连接建立的开销。每一次单独的写入操作都需要经历完整的请求-响应周期,而批量写入则是将多个操作打包在一起,用一次通信完成原本需要多次交互的工作。这不仅仅节省了时间,更重要的是释放了系统资源,让服务器能够专注于真正的数据处理,而不是频繁的协议握手和状态维护。

这样的批量请求的确是可以优化写入请求的效率,让 ES 集群获得更多的资源去做写入请求的集中处理。但是除了客户端与 ES 集群的通讯效率优化,还有其他中间过程能优化么?

Gateway 的优化点

bulk 的优化理念是将日常零散的写入需求做集中化的处理,尽量减低日常请求的损耗,完成资源最大化的利用。简而言之就是“好钢用在刀刃上”。

但是 ES 在收到 bulk 写入请求后,也是需要协调节点根据文档的 id 计算所属的分片来将数据分发到对应的数据节点的。这个过程也是有一定损耗的,如果 bulk 请求中数据分布的很散,每个分片都需要进行写入,原本 bulk 集中写入的需求优势则还是没有得到最理想化的提升。

gateway 的写入加速则对 bulk 的优化理念的最大化补全。

gateway 可以本地计算每个索引文档对应后端 Elasticsearch 集群的目标存放位置,从而能够精准的进行写入请求定位

在一批 bulk 请求中,可能存在多个后端节点的数据,bulk_reshuffle 过滤器用来将正常的 bulk 请求打散,按照目标节点或者分片进行拆分重新组装,避免 Elasticsearch 节点收到请求之后再次进行请求分发, 从而降低 Elasticsearch 集群间的流量和负载,也能避免单个节点成为热点瓶颈,确保各个数据节点的处理均衡,从而提升集群总体的索引吞吐能力。

整理的优化思路如下图:

优化实践

那我们来实践一下,看看 gateway 能提升多少的写入。

这里我们分 2 个测试场景:

  1. 基础集中写入测试,不带文档 id,直接批量写入。这个场景更像是日志或者监控数据采集的场景。
  2. 带文档 id 的写入测试,更偏向搜索场景或者大数据批同步的场景。

2 个场景都进行直接写入 ES 和 gateway 转发 ES 的效率比对。

测试材料除了需要备一个网关和一套 es 外,其余的内容如下:

测试索引 mapping 一致,名称区分:

PUT gateway_bulk_test
{
  "settings": {
    "number_of_shards": 6,
    "number_of_replicas": 0
  },
  "mappings": {
    "properties": {
      "timestamp": {
        "type": "date",
        "format": "strict_date_optional_time"
      },
      "field1": {
        "type": "keyword"
      },
      "field2": {
        "type": "keyword"
      },
      "field3": {
        "type": "keyword"
      },
      "field4": {
        "type": "integer"
      },
      "field5": {
        "type": "keyword"
      },
      "field6": {
        "type": "float"
      }
    }
  }
}

PUT bulk_test
{
  "settings": {
    "number_of_shards": 6,
    "number_of_replicas": 0
  },
  "mappings": {
    "properties": {
      "timestamp": {
        "type": "date",
        "format": "strict_date_optional_time"
      },
      "field1": {
        "type": "keyword"
      },
      "field2": {
        "type": "keyword"
      },
      "field3": {
        "type": "keyword"
      },
      "field4": {
        "type": "integer"
      },
      "field5": {
        "type": "keyword"
      },
      "field6": {
        "type": "float"
      }
    }
  }
}

gateway 的配置文件如下:

path.data: data
path.logs: log

entry:
  - name: my_es_entry
    enabled: true
    router: my_router
    max_concurrency: 200000
    network:
      binding: 0.0.0.0:8000

flow:
  - name: async_bulk
    filter:
      - bulk_reshuffle:
          when:
            contains:
              _ctx.request.path: /_bulk
          elasticsearch: prod
          level: node
          partition_size: 1
          fix_null_id: true
      - elasticsearch:
          elasticsearch: prod #elasticsearch configure reference name
          max_connection_per_node: 1000 #max tcp connection to upstream, default for all nodes
          max_response_size: -1 #default for all nodes
          balancer: weight
          refresh: # refresh upstream nodes list, need to enable this feature to use elasticsearch nodes auto discovery
            enabled: true
            interval: 60s
          filter:
            roles:
              exclude:
                - master

router:
  - name: my_router
    default_flow: async_bulk

elasticsearch:
  - name: prod
    enabled: true
    endpoints:
      - https://127.0.0.1:9221
      - https://127.0.0.1:9222
      - https://127.0.0.1:9223
    basic_auth:
      username: admin
      password: admin

pipeline:
  - name: bulk_request_ingest
    auto_start: true
    keep_running: true
    retry_delay_in_ms: 1000
    processor:
      - bulk_indexing:
          max_connection_per_node: 100
          num_of_slices: 3
          max_worker_size: 30
          idle_timeout_in_seconds: 10
          bulk:
            compress: false
            batch_size_in_mb: 10
            batch_size_in_docs: 10000
          consumer:
            fetch_max_messages: 100
          queue_selector:
            labels:
              type: bulk_reshuffle

测试脚本如下:

#!/usr/bin/env python3
"""
ES Bulk写入性能测试脚本

"""

import hashlib
import json
import random
import string
import time
from typing import List, Dict, Any

import requests
from concurrent.futures import ThreadPoolExecutor
from datetime import datetime
import urllib3

# 禁用SSL警告
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

class ESBulkTester:
    def __init__(self):
        # 配置变量 - 可修改
        self.es_configs = [
            {
                "name": "ES直连",
                "url": "https://127.0.0.1:9221",
                "index": "bulk_test",
                "username": "admin",  # 修改为实际用户名
                "password": "admin",  # 修改为实际密码
                "verify_ssl": False  # HTTPS需要SSL验证
            },
            {
                "name": "Gateway代理",
                "url": "http://localhost:8000",
                "index": "gateway_bulk_test",
                "username": None,  # 无需认证
                "password": None,
                "verify_ssl": False
            }
        ]
        self.batch_size = 10000  # 每次bulk写入条数
        self.log_interval = 100000  # 每多少次bulk写入输出日志

        # ID生成规则配置 - 前2位后5位
        self.id_prefix_start = 1
        self.id_prefix_end = 999      # 前3位: 01-999
        self.id_suffix_start = 1
        self.id_suffix_end = 9999   # 后4位: 0001-9999

        # 当前ID计数器
        self.current_prefix = self.id_prefix_start
        self.current_suffix = self.id_suffix_start

    def generate_id(self) -> str:
        """生成固定规则的ID - 前2位后5位"""
        id_str = f"{self.current_prefix:02d}{self.current_suffix:05d}"

        # 更新计数器
        self.current_suffix += 1
        if self.current_suffix > self.id_suffix_end:
            self.current_suffix = self.id_suffix_start
            self.current_prefix += 1
            if self.current_prefix > self.id_prefix_end:
                self.current_prefix = self.id_prefix_start

        return id_str

    def generate_random_hash(self, length: int = 32) -> str:
        """生成随机hash值"""
        random_string = ''.join(random.choices(string.ascii_letters + string.digits, k=length))
        return hashlib.md5(random_string.encode()).hexdigest()

    def generate_document(self) -> Dict[str, Any]:
        """生成随机文档内容"""
        return {
            "timestamp": datetime.now().isoformat(),
            "field1": self.generate_random_hash(),
            "field2": self.generate_random_hash(),
            "field3": self.generate_random_hash(),
            "field4": random.randint(1, 1000),
            "field5": random.choice(["A", "B", "C", "D"]),
            "field6": random.uniform(0.1, 100.0)
        }

    def create_bulk_payload(self, index_name: str) -> str:
        """创建bulk写入payload"""
        bulk_data = []

        for _ in range(self.batch_size):
            #doc_id = self.generate_id()
            doc = self.generate_document()

            # 添加index操作
            bulk_data.append(json.dumps({
                "index": {
                    "_index": index_name,
            #        "_id": doc_id
                }
            }))
            bulk_data.append(json.dumps(doc))

        return "\n".join(bulk_data) + "\n"

    def bulk_index(self, config: Dict[str, Any], payload: str) -> bool:
        """执行bulk写入"""
        url = f"{config['url']}/_bulk"
        headers = {
            "Content-Type": "application/x-ndjson"
        }

        # 设置认证信息
        auth = None
        if config.get('username') and config.get('password'):
            auth = (config['username'], config['password'])

        try:
            response = requests.post(
                url,
                data=payload,
                headers=headers,
                auth=auth,
                verify=config.get('verify_ssl', True),
                timeout=30
            )
            return response.status_code == 200
        except Exception as e:
            print(f"Bulk写入失败: {e}")
            return False

    def refresh_index(self, config: Dict[str, Any]) -> bool:
        """刷新索引"""
        url = f"{config['url']}/{config['index']}/_refresh"

        # 设置认证信息
        auth = None
        if config.get('username') and config.get('password'):
            auth = (config['username'], config['password'])

        try:
            response = requests.post(
                url,
                auth=auth,
                verify=config.get('verify_ssl', True),
                timeout=10
            )
            success = response.status_code == 200
            print(f"索引刷新{'成功' if success else '失败'}: {config['index']}")
            return success
        except Exception as e:
            print(f"索引刷新失败: {e}")
            return False

    def run_test(self, config: Dict[str, Any], round_num: int, total_iterations: int = 100000):
        """运行性能测试"""
        test_name = f"{config['name']}-第{round_num}轮"
        print(f"\n开始测试: {test_name}")
        print(f"ES地址: {config['url']}")
        print(f"索引名称: {config['index']}")
        print(f"认证: {'是' if config.get('username') else '否'}")
        print(f"每次bulk写入: {self.batch_size}条")
        print(f"总计划写入: {total_iterations * self.batch_size}条")
        print("-" * 50)

        start_time = time.time()
        success_count = 0
        error_count = 0

        for i in range(1, total_iterations + 1):
            payload = self.create_bulk_payload(config['index'])

            if self.bulk_index(config, payload):
                success_count += 1
            else:
                error_count += 1

            # 每N次输出日志
            if i % self.log_interval == 0:
                elapsed_time = time.time() - start_time
                rate = i / elapsed_time if elapsed_time > 0 else 0
                print(f"已完成 {i:,} 次bulk写入, 耗时: {elapsed_time:.2f}秒, 速率: {rate:.2f} bulk/秒")

        end_time = time.time()
        total_time = end_time - start_time
        total_docs = total_iterations * self.batch_size

        print(f"\n{test_name} 测试完成!")
        print(f"总耗时: {total_time:.2f}秒")
        print(f"成功bulk写入: {success_count:,}次")
        print(f"失败bulk写入: {error_count:,}次")
        print(f"总文档数: {total_docs:,}条")
        print(f"平均速率: {success_count/total_time:.2f} bulk/秒")
        print(f"文档写入速率: {total_docs/total_time:.2f} docs/秒")
        print("=" * 60)

        return {
            "test_name": test_name,
            "config_name": config['name'],
            "round": round_num,
            "es_url": config['url'],
            "index": config['index'],
            "total_time": total_time,
            "success_count": success_count,
            "error_count": error_count,
            "total_docs": total_docs,
            "bulk_rate": success_count/total_time,
            "doc_rate": total_docs/total_time
        }

    def run_comparison_test(self, total_iterations: int = 10000):
        """运行双地址对比测试"""
        print("ES Bulk写入性能测试开始")
        print(f"测试时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
        print("=" * 60)

        results = []
        rounds = 2  # 每个地址测试2轮

        # 循环测试所有配置
        for config in self.es_configs:
            print(f"\n开始测试配置: {config['name']}")
            print("*" * 40)

            for round_num in range(1, rounds + 1):
                # 运行测试
                result = self.run_test(config, round_num, total_iterations)
                results.append(result)

                # 每轮结束后刷新索引
                print(f"\n第{round_num}轮测试完成,执行索引刷新...")
                self.refresh_index(config)

                # 重置ID计数器
                if round_num == 1:
                    # 第1轮:使用初始ID范围(新增数据)
                    print("第1轮:新增数据模式")
                else:
                    # 第2轮:重复使用相同ID(更新数据模式)
                    print("第2轮:数据更新模式,复用第1轮ID")
                    self.current_prefix = self.id_prefix_start
                    self.current_suffix = self.id_suffix_start

                print(f"{config['name']} 第{round_num}轮测试结束\n")

        # 输出对比结果
        print("\n性能对比结果:")
        print("=" * 80)

        # 按配置分组显示结果
        config_results = {}
        for result in results:
            config_name = result['config_name']
            if config_name not in config_results:
                config_results[config_name] = []
            config_results[config_name].append(result)

        for config_name, rounds_data in config_results.items():
            print(f"\n{config_name}:")
            total_time = 0
            total_bulk_rate = 0
            total_doc_rate = 0

            for round_data in rounds_data:
                print(f"  第{round_data['round']}轮:")
                print(f"    耗时: {round_data['total_time']:.2f}秒")
                print(f"    Bulk速率: {round_data['bulk_rate']:.2f} bulk/秒")
                print(f"    文档速率: {round_data['doc_rate']:.2f} docs/秒")
                print(f"    成功率: {round_data['success_count']/(round_data['success_count']+round_data['error_count'])*100:.2f}%")

                total_time += round_data['total_time']
                total_bulk_rate += round_data['bulk_rate']
                total_doc_rate += round_data['doc_rate']

            avg_bulk_rate = total_bulk_rate / len(rounds_data)
            avg_doc_rate = total_doc_rate / len(rounds_data)

            print(f"  平均性能:")
            print(f"    总耗时: {total_time:.2f}秒")
            print(f"    平均Bulk速率: {avg_bulk_rate:.2f} bulk/秒")
            print(f"    平均文档速率: {avg_doc_rate:.2f} docs/秒")

        # 整体对比
        if len(config_results) >= 2:
            config_names = list(config_results.keys())
            config1_avg = sum([r['bulk_rate'] for r in config_results[config_names[0]]]) / len(config_results[config_names[0]])
            config2_avg = sum([r['bulk_rate'] for r in config_results[config_names[1]]]) / len(config_results[config_names[1]])

            if config1_avg > config2_avg:
                faster = config_names[0]
                rate_diff = config1_avg - config2_avg
            else:
                faster = config_names[1]
                rate_diff = config2_avg - config1_avg

            print(f"\n整体性能对比:")
            print(f"{faster} 平均性能更好,bulk速率高 {rate_diff:.2f} bulk/秒")
            print(f"性能提升: {(rate_diff/min(config1_avg, config2_avg)*100):.1f}%")

def main():
    """主函数"""
    tester = ESBulkTester()

    # 运行测试(每次bulk 1万条,300次bulk = 300万条文档)
    tester.run_comparison_test(total_iterations=300)

if __name__ == "__main__":
    main()

1. 日志场景:不带 id 写入

测试条件:

  1. bulk 写入数据不带文档 id
  2. 每批次 bulk 10000 条数据,总共写入 30w 数据

这里把

反馈结果:

性能对比结果:
================================================================================

ES直连:
  第1轮:
    耗时: 152.29秒
    Bulk速率: 1.97 bulk/秒
    文档速率: 19699.59 docs/秒
    成功率: 100.00%
  平均性能:
    总耗时: 152.29秒
    平均Bulk速率: 1.97 bulk/秒
    平均文档速率: 19699.59 docs/秒

Gateway代理:
  第1轮:
    耗时: 115.63秒
    Bulk速率: 2.59 bulk/秒
    文档速率: 25944.35 docs/秒
    成功率: 100.00%
  平均性能:
    总耗时: 115.63秒
    平均Bulk速率: 2.59 bulk/秒
    平均文档速率: 25944.35 docs/秒

整体性能对比:
Gateway代理 平均性能更好,bulk速率高 0.62 bulk/秒
性能提升: 31.7%

2. 业务场景:带文档 id 的写入

测试条件:

  1. bulk 写入数据带有文档 id,两次测试写入的文档 id 生成规则一致且重复。
  2. 每批次 bulk 10000 条数据,总共写入 30w 数据

这里把 py 脚本中 第 99 行 和 第 107 行的注释打开。

反馈结果:

性能对比结果:
================================================================================

ES直连:
  第1轮:
    耗时: 155.30秒
    Bulk速率: 1.93 bulk/秒
    文档速率: 19317.39 docs/秒
    成功率: 100.00%
  平均性能:
    总耗时: 155.30秒
    平均Bulk速率: 1.93 bulk/秒
    平均文档速率: 19317.39 docs/秒

Gateway代理:
  第1轮:
    耗时: 116.73秒
    Bulk速率: 2.57 bulk/秒
    文档速率: 25700.06 docs/秒
    成功率: 100.00%
  平均性能:
    总耗时: 116.73秒
    平均Bulk速率: 2.57 bulk/秒
    平均文档速率: 25700.06 docs/秒

整体性能对比:
Gateway代理 平均性能更好,bulk速率高 0.64 bulk/秒
性能提升: 33.0%

小结

不管是日志场景还是业务价值更重要的大数据或者搜索数据同步场景, gateway 的写入加速都能平稳的节省 25%-30% 的写入耗时。

关于极限网关(INFINI Gateway)

INFINI Gateway 是一个开源的面向搜索场景的高性能数据网关,所有请求都经过网关处理后再转发到后端的搜索业务集群。基于 INFINI Gateway,可以实现索引级别的限速限流、常见查询的缓存加速、查询请求的审计、查询结果的动态修改等等。

官网文档:https://docs.infinilabs.com/gateway
开源地址:https://github.com/infinilabs/gateway

作者:金多安,极限科技(INFINI Labs)搜索运维专家,Elastic 认证专家,搜索客社区日报责任编辑。一直从事与搜索运维相关的工作,日常会去挖掘 ES / Lucene 方向的搜索技术原理,保持搜索相关技术发展的关注。
原文:https://infinilabs.cn/blog/2025/gateway-bulk-write-performance-optimization/

elasticsearcg索引配置不变,doc数量不变却越写越慢

Elasticsearchkin122 回复了问题 • 2 人关注 • 3 个回复 • 3921 次浏览 • 2025-07-30 08:47 • 来自相关话题

【搜索客社区日报】第2055期 (2025-06-16)

社区日报Muses 发表了文章 • 0 个评论 • 2179 次浏览 • 2025-06-17 17:41 • 来自相关话题

1、Easysearch 索引备份之 Clone API https://infinilabs.cn/blog/202 ... -api/ 2、私有知识库 Coco AI 实战(一):Coco Server Linux 平台部署 https://infinilabs.cn/blog/202 ... on-1/、 3、风口|继MoE、MCP与A2A之后,下一个模型协作风口是MoA https://mp.weixin.qq.com/s/_yv9gdBKv1yDK0rQNtbbiQ 4、干货:手把手搭建ElasticSearch日志监控告警 https://mp.weixin.qq.com/s/JH2AIAnxdFSPhsG7h-9y_g 5、搭建持久化的 INFINI Console 与 Easysearch 容器环境 https://infinilabs.cn/blog/202 ... cker/ 编辑:Muse 更多资讯:http://news.searchkit.cn

【搜索客社区日报】第2035期 (2025-05-12)

社区日报Muses 发表了文章 • 0 个评论 • 4175 次浏览 • 2025-05-12 11:29 • 来自相关话题

活动推荐🔥:【5月15日 北京】本次 Workshop 活动将围绕 “搜索服务统一治理” “流量管控” “服务编排” 三大核心板块展开,深入探讨如何通过 INFINI Labs 产品为企业提供高效、灵活的搜索基础设施管理方案。欢迎大家免费报名参加。 https://hdxu.cn/128g7 1、Elasticsearch中的三种分页策略深度解析:原理、使用及对比 https://blog.csdn.net/qq_26664 ... 98228 2、Easysearch 基础运维扫盲指南:从 HTTP 到 HTTPS、认证与安全访问全解析 https://mp.weixin.qq.com/s/HR7E7HAfS4ntpSkD_r5_Zw 3、MySQL数据实时接入Easysearch,零代码迁移全流程 https://mp.weixin.qq.com/s/bVGf8v6RAQljficJrjEISw 4、字节跳动开源了一款 Deep Research 项目 https://mp.weixin.qq.com/s/ejE6bfR_lFQutPy-u_pzmQ 5、最强中文TTS接入MCP-Server,效果再次封神! https://mp.weixin.qq.com/s/ivjDIwYXIqxyV3kOvJ2VhQ 编辑:Muse 更多资讯:http://news.searchkit.cn

【第 8 期】搜索客 Meetup | Elasticsearch 的一些“双刃剑”特性

活动searchkit 发表了文章 • 0 个评论 • 3517 次浏览 • 2025-03-13 17:54 • 来自相关话题

本次活动由 搜索客社区、极限科技(INFINI Labs) 联合举办,活动邀请到 INFINI Labs 搜索运维专家 金端 来分享 Elasticsearch 中一些典型的“双刃剑”特性,以及如何在实际使用中权衡和应对。欢迎预约直播观看 ~

活动主题:Elasticsearch 的一些“双刃剑”特性
活动时间:2025 年 03 月 26 日 19:00-20:00(周三)
活动形式:微信视频号(极限实验室)直播
报名方式:关注或扫码海报中的二维码进行预约

嘉宾介绍

金端,极限科技(INFINI Labs)搜索运维专家,Elasticsearch 官方认证工程师,搜索客社区日报编辑。在 ES 运维使用方面具有丰富的实战经验。对 ES/lucene 搜索分析方向保持学习和关注。

主题摘要

Elasticsearch 的许多特性确实是一把“双刃剑”,它们在提供强大功能的同时,也带来了潜在的使用瓶颈和运维挑战。分享主要讨论一些典型的“双刃剑”特性,以及如何在实际使用中权衡和应对。

参与有奖

本次直播活动将设有福袋抽奖环节,参与就有机会获得 INFINI Labs 周边纪念品,包括 T 恤、鸭舌帽、咖啡杯、指甲刀套件、精品围巾等等(图片仅供参考,款式、颜色与尺码随机)。

活动交流

本活动设有 Meetup 技术交流群,可添加小助手微信拉群,与更多小伙伴一起学习交流。

![](https://infinilabs.cn/img/company/INFINILabs-wechat.jpg)

Meetup 讲师招募

搜索客社区 Meetup 的成功举办,离不开社区小伙伴的热情参与。目前社区讲师招募计划也在持续进行中,我们诚挚邀请各位技术大咖、行业精英踊跃提交演讲议题,与大家分享您的经验。

讲师报名链接:http://cfp.searchkit.cn
或扫描下方二维码,立刻报名成为讲师!

![](https://infinilabs.cn/img/blog/banner/meetup/searchkit-lecturer-recruiting-qrcode.jpg)

Meetup 活动聚焦 AI 与搜索领域的最新动态,以及数据实时搜索分析、向量检索、技术实践与案例分析、日志分析、安全等领域的深度探讨。

我们热切期待您的精彩分享!

往期回顾

关于 搜索客(SearchKit)社区

搜索客社区由 Elasticsearch 中文社区进行全新的品牌升级,以新的 Slogan:“搜索人自己的社区” 为宣言。汇集搜索领域最新动态、精选干货文章、精华讨论、文档资料、翻译与版本发布等,为广大搜索领域从业者提供更为丰富便捷的学习和交流平台。

社区官网:https://searchkit.cn

【搜索客社区日报】第1998期 (2025-03-07)

社区日报Fred2000 发表了文章 • 0 个评论 • 2211 次浏览 • 2025-03-07 10:33 • 来自相关话题

1.基于 Qwen2.5-14B + Elasticsearch RAG 的大数据知识库智能问答系统 https://mp.weixin.qq.com/s/eS45qqzXs9WzXmWMurNwvQ 2.实测 Manus:首个真干活 AI,中国造(附50个用例 + 拆解) https://mp.weixin.qq.com/s/P47F8KE7SPRdUpODcnKKhQ 3.Manus工作原理揭秘:解构下一代AI Agent的多智能体架构 https://mp.weixin.qq.com/s/Hr5Ljp7BMsYA0CqU1YI1CA 4.INFINI Labs 产品更新 | Easysearch 增加异步搜索等新特性 https://infinilabs.cn/blog/2025/release-20250228/ 5.Easysearch 节点磁盘不足应对方法 https://infinilabs.cn/blog/202 ... odes/ 编辑:Fred 更多资讯:http://news.searchkit.cn

十亿级订单系统的数据库查询性能优化之路

默认分类京东云开发者 发表了文章 • 0 个评论 • 3617 次浏览 • 2024-12-11 16:43 • 来自相关话题

作者:京东零售 崔健

0.前言

  • 系统概要:BIP采购系统用于京东采销部门向供应商采购商品,并且提供了多种创建采购单的方式以及采购单审批、回告、下传回传等业务功能

  • 系统价值:向供应商采购商品增加库存,满足库存周转及客户订单的销售,供应链最重要的第一环节

1.背景

采购系统在经历了多年的迭代后,在数据库查询层面面临巨大的性能挑战。核心根因主要有以下几方面:

  • 复杂查询多,历史上通过MySQL和JED承载了过多的检索过滤条件,时至今日很难推动接口使用方改变调用方式

  • 数据量大,随着业务的持续发展,带来了海量的数据增长(日均150万单左右,订单主表/子表/渠道表/扩展表分别都是:6.5亿行,订单明细表/分配表:9.2亿行,日志表:60亿行)

  • 数据模型复杂,订单完整数据分布在20+张表,经常需要多表join

引入的主要问题有:

  • 业务层面:

    • 订单列表页查询/导出体验差,性能非常依赖输入条件,尤其是在面对订单数据倾斜的时候,部分用户无法查询/导出超过半个月以上的订单

    • 查询条件不合理,1.归档筛选条件,技术词汇透传到业务,导致相同周期的单子无法一键查询/导出,需要切换“是否归档”查询全部;2.无法区分“需要仓库收货”类的单子,大部分业务同事主要关注这类单子的履约情况
  • 技术层面:

    • 慢SQL多,各种多表关联复杂条件查询导致,索引、SQL已经优化道了瓶颈,经常出现数据库负载被拉高

    • 大表多,难在数据库上做DDL,可能会引起核心写库负载升高、主从延迟等问题

    • 模型复杂,开发、迭代成本高,查询索引字段散落在多个表中,导致查询性能下降

2.目标

业务层面:提升核心查询/导出体验,加强查询性能,优化不合理的查询条件

技术层面:1.减少慢SQL,降低数据库负载,提高系统稳定性;2.降低单表数据量级;3.简化数据模型

3.挑战

提升海量数据、复杂场景下的查询性能!

  • 采购订单系统 VS C端销售订单系统复杂度对比:
对比项 采购订单系统 C端订单销售系统
分库逻辑 使用采购单号分库 按用户pin分库分表
查询场景 面向采销、接口人、供应商、仓储运营提供包括采销员、单号、SKU、供应商、部门、配送中心、库房等多场景复杂查询 主要是按用户pin进行订单查询
单据所属人 采购单生成后,采销可以进行单据转移 订单生成后订单所属人不变
数据倾斜 单一采销或供应商存在大量采购单,并且自动补货会自动创建采购单 C端一个用户pin下订单数量有限

4.方案

思路

在这里插入图片描述

优化前

在这里插入图片描述



优化后

在这里插入图片描述

4.1 降低查询数据量

4.1.1 前期调研

基于历史数据、业务调研分析,采购订单只有8%的订单属于“需要实际送货至京东库房”的范围,也就是拥有完整订单履约流程、业务核心关注时效的。其余订单属于通过客户订单驱动,在采购系统的生命周期只有创建记录

在这里插入图片描述

基于以上结论,在与产品达成共识后,提出新的业务领域概念:“入库订单” ,在查询时单独异构这部分订单数据(前期也曾考虑过,直接从写入层面拆分入库订单,但是因为开发成本、改动范围被pass了)。异构这部分数据实际也参考了操作系统、中间件的核心优化思路,缓存访问频次高的热数据

4.1.2 入库订单异构

执行流程

在这里插入图片描述



  • “入库”订单数据打标

    • 增量订单在创建订单完成时写入;存量订单通过离线表推数

    • 需要订单创建模块先完成改造上线,再同步历史,保证数据不丢

    • 如果在【数据解析模块】处理binlog时无法及时从JimKV获取到订单标识,会补偿反查数据库并回写JimKV,提升其他表的binlog处理效率
  • binlog监听

    • 基于公司的【数据订阅】任务,通过消费JMQ实现。其中订阅任务基于订单号进行MQ数据分区,并且在消费端配置不允许消息重试,防止消息时序错乱

    • 其中,根据订单号进行各个表的MQ数据分区,第一版设计可能会引起热分区,导致消费速率变慢,基于这个问题识别到热分区主要是由于频繁更新订单明细数据导致(订单(1)->明细(N)),于是将明细相关表基于自身id进行分区,其他订单纬度表还是基于订单号。这样既不影响订单数据更新的先后顺序,也不会造成热分区、还可以保证明细数据的准确性
  • 数据同步

    • 增量数据同步可以采用源库的增量binlog进行解析即可,存量数据通过申请新库/表,进行DTS的存量+增量同步写入,完成binlog生产

    • 以上是在上线前的临时链路,上线后需要切换到源库同步binlog的增量订阅任务,此时依赖“位点回拨”+“数据可重入”。位点回拨基于订阅任务的binlog时间戳,数据可重入依赖上文提到的MQ消费有序以及SQL覆盖写
  • 数据校对

    • 以表为纬度,优先统计总数,再随机抽样明细进行比对

    • 目前入库订单量为稳定在5000万,全部实时订单量级6.5亿,降低92%

4.2 提升复杂查询能力

4.2.1 数据准备

  • 考虑到异构“入库”订单到JED,虽然数据查询时效性可以有一定保障,但是在复杂查询能力以及识别“非入库”订单还没有支持

  • 其中,“非入库”订单业务对于订单数据时效性要求并不高(1.订单创建源于客户订单;2.没有履约流程;3.无需手动操作订单关键节点)

  • 所以,考虑将这部分查询能力转移到ES上

ES数据异构过程

在这里插入图片描述



  • 首先,同步到ES的数据的由“实时+归档”订单组成,其中合计20亿订单,顺带优化了先前归档ES大索引(所有订单放在同一个索引)的问题,改成基于“月份”存储订单,之所以改成月份是因为根据条件查询分两种:1.一定会有查询时间范围(最多3个月);2.指定单号查询,这种会优先检索单号对应的订单创建时间,再路由到指定索引

  • 其次,简化了归档程序流程,历史方案是程序中直接写入【归档JED+归档ES】,现在优化成只写入JED,ES数据通过【数据解析模块】完成,简化归档程序的同时,提高了归档能力的时效性

  • 再次,因为ES是存储全量订单,需要支持复杂条件的查询,所以在订单没有物理删除的前提下,【数据解析模块】会过滤所有delete语句,保证全量订单数据的完整性

  • 接着,为了提升同步到ES数据的吞吐,在MQ消费端,主要做了两方面优化:1.会根据表和具体操作进行binlog的请求合并;2.降低对于ES内部refresh机制的依赖,将2分钟内更新到ES的数据缓存到JimKV,更新前从缓存中获取

  • 最后,上文提到,同步到入库JED,有的表是根据订单号,有的表是根据自身id。那么ES这里,因为NoSQL的设计,和线程并发的问题,为了防止数据错误,只能将所有表数据根据单号路由到相同的MQ分区

4.2.2 查询调度策略设计

优化前,所有的查询请求都会直接落到数据库进行查询,可以高效查询完全取决于用户的筛选条件是否可以精准缩小数据查询范围

优化后,新增动态路由层

  • 离线计算T-1的采销/供应商的订单数据倾斜,将数据倾斜情况推送到JimDB集群

  • 根据登陆用户、数据延迟要求、查询数据范围,自动调度查询的数据集群,实现高性能的查询请求

查询调度

在这里插入图片描述

5.ES主备机制&数据监控

1.主/备ES可以通过DUCC开关,实现动态切换,提升数据可靠性

2.结合公司的业务监控,完成订单数据延迟监控(数据同步模块写入时间-订单创建时间)

3.开启消息队列积压告警

5.1 ES集群主/备机制

1:1ES集群进行互备,应急预案快速切换,保证高可用

在这里插入图片描述

5.2 数据监控

在这里插入图片描述

6.灰度上线

  • 第一步,优先上线数据模块,耗费较多时间的原因:1.整体数据量级以及历史数据复杂度的问题;2.数据同步链路比较长,中间环节多

  • 第二步,预发环境验证,流量回放并没有做到长周期的完全自动化,根因:1.项目周期相对紧张;2.新老集群的数据还是有一些区别,回放脚本不够完善

  • 第三步,用户功能灰度,主要是借助JDOS的负载均衡策略结合用户erp完成

  • 第四部,对外接口灰度,通过控制新代码灰度容器个数,逐步放量

在这里插入图片描述

7.成果

平稳切换,无线上问题

指标 具体提升
采购列表查询(ms) 1、TP999:4817 优化到 2872,提升40.37% 2、超管、部门管理员由无法查询超过一周范围的订单,优化为可以在2秒内查询3个月的订单 3、页面删除“是否归档”查询条件,简化业务操作 4、页面新增“是否入库”查询条件,聚焦核心业务数据
仓储运营列表(ms) TP999:9009 优化到 6545,提升27.34%
采购统计查询(ms) TP999:13219 优化到 1546,提升88.3%
慢SQL指标(天纬度) 1、1s-2s慢SQL数:820->72,降低91% 2、2s-5s慢SQL数:276->26,降低90% 3、5s以上慢SQL数:343->6,降低98%

8.待办

  • 主动监控层面,新增按照天纬度进行数据比对、异常告警的能力,提高问题发现率

  • 优化数据模型,对历史无用订单表进行精简,降低开发、运维成本,提升需求迭代效率

  • 精简存储集群

    • 逐步下线其他非核心业务存储集群,减少外部依赖,提高系统容错度

    • 目前全量订单ES集群已经可以支持多场景的外部查询,未来考虑是否可以逐步下线入库订单JED
  • 识别数据库隐患,基于慢日志监控,重新梳理引入模块,逐步优化,持续降低数据库负载

  • MySQL减负,探索其他优化方案,减少数据量存储,提升数据灵活性。优先从业务层面出发,识别库里进行中的僵尸订单的根因,进行分类,强制结束

  • 降级方案,当数据同步或者数据库存在异常时,可以做到秒级无感切换,提升业务可用率

9.写在最后

  • 为什么没考虑Doris?因为ES是团队应用相对成熟的中间件,处于学习、开发成本考虑

  • 未来入库的JED相关表是否可以下掉,用ES完全替代?目前看可以,当初设计冗余入库JED也是出于对于ES不确定性以及数据延迟的角度考虑,而且历史的一部分查询就落在了异构的全量实时订单JED上。现在,JED官方也不是很推荐非route key的查询。最后,现阶段因为降低了数据量和拆分了业务场景,入库JED的查询性能还是非常不错的

  • 因为项目排期、个人能力的因素,在方案设计上会有考虑不周的场景,本期只是优化了最核心的业务、技术痛点,未来还有很大持续优化的空间。中间件的使用并不是可以优化数据库性能的银弹,最核心的还是要结合业务以及系统历史背景,在不断纠结当中寻找balance

【字节跳动】 深圳/上海招聘Elasticsearch研发工程师

回复

求职招聘tinycols 发起了问题 • 1 人关注 • 0 个回复 • 3469 次浏览 • 2024-12-05 16:57 • 来自相关话题

极限科技(INFINI Labs)招聘:搜索运维工程师(Elasticsearch/Easysearch)【北京/全职】

求职招聘INFINI Labs 小助手 发表了文章 • 0 个评论 • 6484 次浏览 • 2024-09-28 11:00 • 来自相关话题

20240928-180457.png

我们是国内搜索型数据库产品厂商第一梯队的杰出代表,随着业务的快速发展,现开放岗位:搜索运维工程师( Elasticsearch/Easysearch ),如果有兴趣,请直接拉到文末,扫描二维码或将简历投递至 hello@infini.ltd。

如果您还不了解 极限科技(INFINI Labs)是谁,在做什么,需要什么样的小伙伴,那么请看下文:

我们是谁

INFINI Labs

极限科技,全称极限数据(北京)科技有限公司,是一家专注于实时搜索与数据分析的软件公司。旗下品牌极限实验室(INFINI Labs)致力于打造极致易用的数据探索与分析体验。

极限科技是一支年轻的团队,采用天然分布式的方式来进行远程协作,员工分布在全球各地,希望通过努力成为中国乃至全球企业大数据实时搜索分析产品的首选,为中国技术品牌输出添砖加瓦。

官网:https://infinilabs.cn

我们在做什么

极限科技(INFINI Labs)正在致力于以下几个核心方向:

1、开发近实时搜索引擎 INFINI Easysearch

INFINI Easysearch 是一个分布式的搜索型数据库,实现非结构化数据检索、全文检索、向量检索、地理位置信息查询、组合索引查询、多语种支持、聚合分析等。Easysearch 可以完美替代 Elasticsearch,同时添加和完善多项企业级功能。Easysearch 助您拥有简洁、高效、易用的搜索体验。详情参见:https://infinilabs.cn

2、打造下一代实时搜索引擎 INFINI Pizza

INFINI Pizza 是一个分布式混合搜索数据库系统。我们的使命是充分利用现代硬件和人工智能的潜力,为企业提供量身定制的实时智能搜索体验。我们致力于满足具有挑战性的环境中高并发和高吞吐量的需求,同时提供无缝高效的搜索功能。详情参见:https://pizza.rs

3、积极参与全球开源生态建设

通过开源项目和社区贡献,推动全球开源技术的发展,提升中国在全球开源领域的影响力。

4、提供专业服务

为客户提供包括搜索技术支持、迁移服务、定制解决方案和培训在内的全方位服务。

5、提供国产化搜索解决方案

针对中国市场的特殊需求,提供符合国产化标准的搜索产品和解决方案,帮助客户解决使用 Elasticsearch 时遇到的挑战。

极限科技(INFINI Labs)通过这些努力,旨在成为全球领先的实时搜索和数据分析解决方案提供商。

我们期待有才华、有激情的你加入我们,一起探索数据搜索的未来,共同创造无限可能!

在招岗位介绍

岗位名称

搜索运维工程师(Elasticsearch/Easysearch)

岗位职责

  1. 负责客户现场的 Elasticsearch/Easysearch/OpenSearch 搜索引擎集群的日常维护、监控和优化,确保集群的高可用性和性能稳定;
  2. 协助客户进行搜索引擎集群的部署、配置及版本升级;
  3. 排查和解决 Elasticsearch/Easysearch/OpenSearch 集群中的各种技术问题,及时响应并处理集群异常;
  4. 根据业务需求设计和实施搜索索引的调优、数据迁移和扩展方案;
  5. 负责与客户沟通,提供技术支持及相关培训,确保客户需求得到有效满足;
  6. 制定并实施搜索引擎的备份、恢复和安全策略,保障数据安全;
  7. 与内部研发团队和外部客户进行协作,推动集群性能改进和功能优化。

岗位要求

  1. 全日制本科及以上学历,5 年以上运维工作经验;
  2. 拥有 Elasticsearch/Easysearch/OpenSearch 使用经验,熟悉搜索引擎的原理、架构和相关生态工具(如 Logstash、Kibana 等);
  3. 熟悉 Linux 操作系统的使用及常见性能调优方法;
  4. 熟练掌握 Shell 或 Python 等至少一种脚本语言,能够编写自动化运维脚本;
  5. 具有优秀的问题分析与解决能力,能够快速应对突发情况;
  6. 具备良好的沟通能力和团队合作精神,能够接受 客户驻场工作;
  7. 全职,北京地区,需具备在北京长期工作的条件;

优先考虑

  • 计算机科学、信息技术或相关专业;
  • 具备丰富的大规模分布式系统运维经验;
  • 熟悉 Elasticsearch/Easysearch/OpenSearch 分片、路由、查询优化等高级功能;
  • 拥有 Elastic Certified Engineer 认证;
  • 具备大规模搜索引擎集群设计、扩展和调优经验;
  • 熟悉其他搜索引擎技术(如 Solr、Lucene)者优先 ;
  • 熟悉大数据处理相关技术(比如: Kafka 、Flink 等)者优先。

福利待遇

  • 月薪: 15K - 25K,具体根据能力而定,试用期为 3-6 个月;
  • 福利:五险一金/双休/国内法定假日/带薪年假等;

简历投递

简历投递:hello@infini.ltd(邮件标题请备注姓名+求职岗位+来自搜索客社区)
微信联系:INFINI-Labs(加微请备注求职岗位+来自搜索客社区)

欢迎有兴趣的小伙伴联系或推荐,期待您的加入!

联系我们

Elastic 宣布修改开源协议为 AGPL:Elasticsearch 再次成为开源软件

Elasticsearchsearchkit 发表了文章 • 0 个评论 • 7098 次浏览 • 2024-08-30 11:26 • 来自相关话题

今日快讯!就在刚刚,开源搜索领域行业巨头 Elastic 官方博客发表了一篇最新公告《Elasticsearch is Open Source, Again》,Elastic 创始人& CTO Shay Banon 宣布 Elasticsearch 和 Kibana 许可证协议修改为 AGPL。

original-elastic-logos.png

以下为搜索客社区从 Elastic 官方博客翻译的原文内容:


Elasticsearch 再次成为开源软件

[D.N.A] Elasticsearch 和 Kibana 现在可以再次被称为开源软件了。这句话让我感到无比的兴奋。真的忍不住跳起来庆祝!我们所有在 Elastic 的人都很高兴。开源精神是我的DNA,也是 Elastic 的DNA。能够再次称 Elasticsearch 为开源软件,真的是一种纯粹的快乐。

[LOVE.] 简而言之,我们将在接下来的几周内,除了 ELv2 和 SSPL 之外,增加 AGPL 作为另一个许可选项。在更改许可后,我们从未停止过像一个开源社区一样相信和行动。但通过使用 AGPL 这一获得开放源码促进会(OSI)批准的许可,消除了人们可能存在的任何疑问或混淆。

[Not Like Us] 我们在 Elastic 从未停止过对开源的信仰。我个人对开源的信仰也从未动摇,至今已有 25 年了。那么为什么三年前我们要做出改变呢?我们遇到了与 AWS 相关的问题,以及他们的服务引发的市场混乱。在尝试了所有能想到的其他选项后,我们更改了许可协议,明知道这会导致 Elasticsearch 被分叉成另一个名称并走上不同的发展轨迹。这是一个漫长的故事。

[Like That] 好消息是,虽然过程痛苦,但结果奏效了。三年后,亚马逊已经完全投入到了他们的分叉项目中,市场的混乱(大部分)得到了缓解,我们与 AWS 的合作伙伴关系比以往更强。我们甚至被评为 AWS 的年度合作伙伴。我一直希望时间能过去得足够久,以至于我们可以安全地回到开源项目的状态——现在终于到了。

[All The Stars] 我们希望尽可能简化用户的使用体验。我们有用户非常喜欢 ELv2(一个受 BSD 启发的许可)。我们也有用户已经批准使用 SSPL(通过 MongoDB 使用)。这就是为什么我们只是增加了一个选项,而不是移除任何东西。如果你已经在使用并喜欢 Elasticsearch,请继续使用,没有任何变化。对于其他人,现在你也可以选择使用 AGPL。

[LOYALTY.] 我们选择 AGPL 而不是其他许可,是因为我们希望通过与 OSI 的合作,能在开源许可领域创造更多的选项。随着我们更改许可以来的发展(例如 Grafana 从 Apache2 转移到 AGPL),也许 AGPL 已经足够适用于像我们这样的基础设施软件了。我们致力于找到最合适的解决方案。

[euphoria] 我非常高兴能够再次称 Elasticsearch 为开源软件。

[Alright] 任何改变都可能引发混淆,当然也可能引来一些网络喷子。(网络喷子总是存在的,对吧?)让我们愉快地回答一些可能出现的问题吧。我可以想象到的一些问题如下,但我们会继续补充。

“更改许可是个错误,Elastic 现在在回撤”:我们在三年前更改许可时消除了很多市场混乱。由于我们的行动,很多事情已经改变。现在是一个完全不同的市场环境。我们不生活在过去。我们希望为用户打造一个更好的未来。正是因为我们当时采取了行动,现在我们才有能力采取新的行动。

“AGPL 不是真正的开源许可,X 才是”:AGPL 是获得 OSI 批准的许可,并且被广泛采用。例如,MongoDB 曾经使用 AGPL,Grafana 现在也是 AGPL。这表明 AGPL 并不影响使用或流行度。我们选择 AGPL 是因为我们认为这是与 OSI 一起为世界开辟更多开源道路的最佳方式,而不是减少开源。

“Elastic 更改许可是因为他们表现不好”:我要说的是,我今天对 Elastic 的未来依然充满期待。我为我们的产品和团队的执行力感到无比自豪。我们发布了无状态的 Elasticsearch ES|QL 和大量用于 GenAI 用例的向量数据库/混合搜索改进。我们在日志记录和可观察性方面大力投入 OTel。我们的安全产品 SIEM 不断添加令人惊叹的功能,并且是市场上增长最快的产品之一。用户的反应让我们感到非常谦卑。股市总有起伏,但我可以向你保证,我们始终着眼于长远发展,而这次的变更就是其中的一部分。

如果我们看到更多问题,会在上面继续添加,以期减少混淆。

[HUMBLE.] 为未来而构建真是令人兴奋。Elasticsearch 回归开源。万岁!这真是一件美妙的事情。今天真是美好的一天。

Forever :elasticheart: Open Source

Shay 2024-08-30


原文地址:https://www.elastic.co/blog/elasticsearch-is-open-source-again/

社区热评

Elasticsearch 再次回归开源的消息迅速引发了技术社区的广泛关注。这不仅是 Elastic 对自身开源信念的重申,也是其在激烈市场竞争中精心策划的一次战略调整。

三年前,Elastic 因与 AWS 的市场竞争而选择更改许可协议,这一决定在当时引发了不小的争议。尽管如此,事实证明,这一策略有效地减少了市场上的混淆,也为 Elastic 与 AWS 的合作奠定了更坚实的基础。如今,Elastic 再度选择开源,并新增 AGPL 作为许可选项,这一举措无疑展现了 Elastic 在市场中更加成熟的定位和对未来发展的自信。

这一变化不仅仅是一个公司的商业决策,更是开源生态系统的一次重要信号。Elastic 的回归开源,传递出一个明确的信息:即使在商业竞争中,开源仍然是企业实现长远发展的重要路径。随着这一决定的落地,其他软件公司可能也会重新审视自身的许可策略,推动更多开源项目的发展与创新。

此外,Elastic 选择 AGPL 作为新许可选项,也显示出其对开源生态未来走向的深刻洞察。AGPL 的引入,表明 Elastic 希望在开源社区中保持灵活性和多样性,同时推动整个行业向更加开放和透明的方向迈进。

总体而言,Elastic 重返开源的举动,不仅意在巩固其在开源社区中的地位,也为行业树立了一个新的标杆。这一事件无疑将成为开源软件发展史上的重要篇章,未来可能会激发更多企业重新考虑其开源战略,进而推动整个技术行业的进一步繁荣与进步。

让我们拭目以待!

Elasticsearch 磁盘空间异常:一次成功的故障排除案例分享

ElasticsearchINFINI Labs 小助手 发表了文章 • 0 个评论 • 4698 次浏览 • 2024-08-09 00:18 • 来自相关话题

故障现象

近日有客户找到我们,说有个 ES 集群节点,磁盘利用率达到了 82% ,而其节点才 63% ,想处理下这个节点,降低节点的磁盘利用率。

起初以为是没有打开自动平衡导致的,经查询,数据还是比较平衡的。 利用率较高的是 76 节点,如果 76 节点的分片比其他节点多,好像还比较合乎逻辑,但它反而比其他节点少了 12-15 个分片。那是 76 节点上的分片比较大?

索引情况

图中都是较大的索引,1 个索引 25TB 左右,共 160 个分片。

分片大小

节点 64 节点 77 节点 75 问题节点 76 可以看出分片大小没有出现较大的倾斜,分片大小和数据平衡的原因都被排除。

换个方向思考,节点 76 比其他节点多使用了磁盘空间 8 个 TB 左右,集群最大分片大小约 140GB ,8000/140=57 ,即节点 76 至少要比其他节点多 57 个分片才行,啊这...

会不会有其他的文件占用了磁盘空间?

我们登录到节点主机,排查是否有其他文件占用了磁盘空间。

结果:客户的数据路径是单独的数据磁盘,并没有其他文件,都是 ES 集群索引占用的空间。

现象总结

分片大小差不多的情况下,节点 76 的分片数还比别的节点还少 10 个左右,它的磁盘空间反而多占用了 8TB 。

这是不是太奇怪了?事出反常必有妖,继续往下查。

原因定位

通过进一步排查,我们发现节点 76 上有一批索引目录,在其他的节点上没有,而且也不在 GET \_cat/indices?v 命令的结果中。说明这些目录都是 dangling 索引占用的。

dangling 索引产生的原因

当 Elasticsearch 节点脱机时,如果删除的索引数量超过 Cluster.indes.tombstones.size,就会发生这种情况。

解决方案

通过命令删除 dangling 索引:

DELETE /\_dangling/<index-uuid>?accept_data_loss=true

最后

这次的分享就到这里了,欢迎与我一起交流 ES 的各种问题和解决方案。

关于极限科技(INFINI Labs)

INFINI Labs

极限科技,全称极限数据(北京)科技有限公司,是一家专注于实时搜索与数据分析的软件公司。旗下品牌极限实验室(INFINI Labs)致力于打造极致易用的数据探索与分析体验。

极限科技是一支年轻的团队,采用天然分布式的方式来进行远程协作,员工分布在全球各地,希望通过努力成为中国乃至全球企业大数据实时搜索分析产品的首选,为中国技术品牌输出添砖加瓦。

官网:https://infinilabs.cn

【第2期】2024 搜索客 Meetup | Elasticsearch 的代码结构和写入查询流程的解读

活动searchkit 发表了文章 • 0 个评论 • 3647 次浏览 • 2024-08-06 11:47 • 来自相关话题

本次活动由 搜索客社区、极限科技(INFINI Labs)联合举办,活动主题将深入探讨 Elasticsearch 的两个核心方面:代码结构以及写入和查询的关键流程。本次活动将为 Elasticsearch 初学者和有经验的用户提供宝贵的见解,欢迎大家报名参加、交流学习。

活动主题:Elasticsearch 的代码结构和写入查询流程的解读
活动时间:2024 年 8 月 14 日 19:00-20:00(周三)
活动形式:微信视频号(极限实验室)直播
报名方式:关注或扫码海报中的二维码进行预约

嘉宾介绍

张磊,极限科技搜索引擎研发负责人,对 Elasticsearch 和 Lucene 源码比较熟悉,目前主要负责公司的 Easysearch 产品的研发以及客户服务工作。

主题摘要

本次分享将探讨 Elasticsearch 的代码结构及其写入和查询流程。内容包括:项目架构、核心模块、插件系统,以及文档索引和查询的各个阶段与分布式查询协调。

活动亮点

  1. 深入解析 Elasticsearch 代码结构

    • 项目的整体结构:了解 Elasticsearch 项目的组织方式。
    • 核心模块及其职责:学习 Elasticsearch 的核心模块及其在系统中的具体角色。
    • 插件系统的设计:探索 Elasticsearch 灵活的插件系统设计及其扩展方式。
  2. 详细解读 Elasticsearch 写入和查询流程

    • 文档索引过程的各个阶段:跟随文档从初始接收至最终存储的索引过程。
    • 查询解析和执行的步骤:理解 Elasticsearch 中查询解析和执行的各个步骤。
    • 分布式查询的协调过程:学习 Elasticsearch 如何在分布式架构中协调查询,以提供高效且准确的搜索结果。

参与有奖

直播中将设有福袋抽奖环节,参与就有机会获得 INFINI Labs 周边纪念品,包括 T 恤、鸭舌帽、咖啡杯、指甲刀套件等等(图片仅供参考,款式、颜色与尺码随机)。

活动交流

活动交流群二维码 7 天内(8 月 12 日前)有效,如过期请添加小助手微信拉群。

本次 Meetup 是深入了解 Elasticsearch 内部工作机制、提升使用技能的绝佳机会。不要错过!

Meetup 讲师招募

搜索客社区 Meetup 的成功举办,离不开社区小伙伴的热情参与。目前社区讲师招募计划也在持续进行中,我们诚挚邀请各位技术大咖、行业精英踊跃提交演讲议题,与大家分享您的经验。

讲师报名链接:http://cfp.searchkit.cn
或扫描下方二维码,立刻报名成为讲师!

Meetup 活动聚焦 AI 与搜索领域的最新动态,以及数据实时搜索分析、向量检索、技术实践与案例分析、日志分析、安全等领域的深度探讨。

我们热切期待您的精彩分享!

往期回顾

【第 1 期】2024 搜索客 Meetup | Easysearch 结合大模型实现 RAG

关于 搜索客(SearchKit)社区

搜索客社区由 Elasticsearch 中文社区进行全新的品牌升级,以新的 Slogan:“搜索人自己的社区” 为宣言。汇集搜索领域最新动态、精选干货文章、精华讨论、文档资料、翻译与版本发布等,为广大搜索领域从业者提供更为丰富便捷的学习和交流平台。社区官网:https://searchkit.cn

Easysearch、Elasticsearch、Amazon OpenSearch 快照兼容对比

EasysearchINFINI Labs 小助手 发表了文章 • 2 个评论 • 3577 次浏览 • 2024-07-29 11:54 • 来自相关话题

在当今的数据驱动时代,搜索引擎的快照功能在数据保护和灾难恢复中至关重要。本文将对 Easysearch、Elasticsearch 和 Amazon OpenSearch 的快照兼容性进行比较,分析它们在快照创建、恢复、存储格式和跨平台兼容性等方面的特点,帮助大家更好地理解这些搜索引擎的差异,从而选择最适合自己需求的解决方案。

启动集群

Easysearch

服务器一般情况下默认参数都是很低的,而 Easysearch/Elasticsearch 是内存大户,所以就需要进行系统调优。

sysctl -w vm.max_map_count=262144

vm.max_map_count 是一个 Linux 内核参数,用于控制单个进程可以拥有的最大内存映射区域(VMA,Virtual Memory Areas)的数量。内存映射区域是指通过内存映射文件或匿名内存映射创建的虚拟内存区域。

这个参数在一些应用程序中非常重要,尤其是那些需要大量内存映射的应用程序,比如 Elasticsearch。Elasticsearch 使用内存映射文件来索引和搜索数据,这可能需要大量的内存映射区域。如果 vm.max_map_count 设置得太低,Elasticsearch 可能无法正常工作,并会出现错误信息。

调整 vm.max_map_count 参数的一些常见原因:

  1. 支持大型数据集: 应用程序(如 Elasticsearch)在处理大型数据集时可能需要大量内存映射区域。增加 vm.max_map_count 可以确保这些应用程序有足够的内存映射区域来处理数据。

  2. 防止内存错误: 如果 vm.max_map_count 设置得太低,当应用程序尝试创建超过限制的内存映射时,会出现错误,导致应用程序崩溃或无法正常工作。

  3. 优化性能: 适当地设置 vm.max_map_count 可以优化应用程序的性能,确保内存映射操作顺利进行。

检查当前的 vm.max_map_count 值:

sysctl vm.max_map_count

或者查看 /proc/sys/vm/max_map_count 文件:

cat /proc/sys/vm/max_map_count

Elasticsearch 官方建议将 vm.max_map_count 设置为至少 262144。对于其他应用程序。

Easysearch 具体安装步骤见 INFINI Easysearch 尝鲜 Hands on

Amazon OpenSearch

使用 Amazon Web Services 控制台进行创建。

Elasticsearch

使用如下 docker compose 部署一个三节点的 ES 集群:

version: "2.2"
services:
  es01:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.10.2
    container_name: es01
    environment:
      - node.name=es01
      - cluster.name=es-docker-cluster
      - discovery.seed_hosts=es02,es03
      - cluster.initial_master_nodes=es01,es02,es03
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - data01:/usr/share/elasticsearch/data
    ports:
      - 9200:9200
    networks:
      - elastic
  es02:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.10.2
    container_name: es02
    environment:
      - node.name=es02
      - cluster.name=es-docker-cluster
      - discovery.seed_hosts=es01,es03
      - cluster.initial_master_nodes=es01,es02,es03
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - data02:/usr/share/elasticsearch/data
    networks:
      - elastic
  es03:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.10.2
    container_name: es03
    environment:
      - node.name=es03
      - cluster.name=es-docker-cluster
      - discovery.seed_hosts=es01,es02
      - cluster.initial_master_nodes=es01,es02,es03
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - data03:/usr/share/elasticsearch/data
    networks:
      - elastic

volumes:
  data01:
    driver: local
  data02:
    driver: local
  data03:
    driver: local

networks:
  elastic:
    driver: bridge

由于这个 docker compose 没有关于 kibana 的配置,所以我们还是用 Console 添加原生的 Elasticsearch 集群!

集群信息

快照还原的步骤

快照前的准备

插件安装

本次测试选择把索引快照备份到 Amazon S3,所以需要使用 S3 repository plugin,这个插件添加了对使用 Amazon S3 作为快照/恢复存储库的支持。

Easysearch 和 OpenSearch 集群自带了这个插件,所以无需额外安装。

对于自己部署的三节点 Elasticsearch 则需要进入每一个节点运行安装命令然后再重启集群,建议使用自动化运维工具来做这步,安装命令如下:

sudo bin/elasticsearch-plugin install repository-s3

如果不再需要这个插件,可以这样删除。

sudo bin/elasticsearch-plugin remove repository-s3

由于需要和 Amazon Web Services 打交道,所以我们需要设置 IAM 凭证,这个插件可以从 EC2 IAM instance profile,ECS task role 以及 EKS 的 Service account 读取相应的凭证。

对于托管的 Amazon OpenSearch 来说,我们无法在托管的 EC2 上绑定我们的凭证,所以需要新建一个 OpenSearchSnapshotRole,然后通过当前的用户把这个角色传递给服务,也就是我们说的 IAM:PassRole。

创建 OpenSearchSnapshotRole,策略如下:

{
  "Version": "2012-10-17",
  "Statement": [{
      "Action": [
        "s3:ListBucket"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::bucket-name"
      ]
    },
    {
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::bucket-name/*"
      ]
    }
  ]
}

信任关系如下:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "es.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

然后在我们的 IAM user 上加上 PassRole 的权限,这样我们就可以把 OpenSearchSnapshotRole 传递给 OpenSearch 集群。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "iam:PassRole",
      "Resource": "arn:aws:iam::123456789012:role/OpenSearchSnapshotRole"
    }
  ]
}

注册存储库

在源集群执行注册

PUT /_snapshot/snapshot-repo-name
{
  "type": "s3",
  "settings": {
    "bucket": "<bucket-name>",
    "base_path": "<bucket-prefix>",

在目标集群同样执行这个语句,为了防止覆盖源集群存储库的数据,将 "readonly": true 添加到"settings" PUT 请求中,这样就只有一个集群具有对存储库的写入权限。

PUT /_snapshot/snapshot-repo-name
{
  "type": "s3",
  "settings": {
    "bucket": "<bucket-name>",
    "base_path": "<bucket-prefix>",
    "readonly": true,

对于 OpenSearch 来说,还需要执行 passrole,所以还需要添加role_arn这个字段,由于 IAM:PassRole 需要对 HTTP 请求做 signV4 日签名,所以这部常常使用 Postman 来完成。把角色传递过去之后,接下来的快照还原操作就可以在 OpenSearch Dashboard 中进行操作了。

需要注意的是,需要在 auth 这里输入 AccessKey,SecretKey,AWS Region,Service Name(es)来做 SignV4 的签名。

请求体如下:

{
  "type": "s3",
  "settings": {
    "bucket": "<bucket-name>",
    "base_path": "<bucket-prefix>",
    "readonly": true,
    "role_arn": "arn:aws:iam::123456789012:role/OpenSearchSnapshotRole"
  }
}
  • 查看所有注册的存储库
    • GET _snapshot:这个命令返回所有已注册的快照存储库列表及其基本信息。
GET _snapshot
{
  "es_repository": {
    "type": "s3",
    "settings": {
      "bucket": "your-s3-bucket-name",
      "region": "your-s3-bucket-region"
    }
  }
}
  • 查看特定存储库的详细信息GET _snapshot/es_repository:这个命令返回名为es_repository的存储库的详细配置信息,包括存储桶名称、区域和其他设置。
GET _snapshot/es_repository
{
  "es_repository": {
    "type": "s3",
    "settings": {
      "bucket": "your-s3-bucket-name",
      "region": "your-s3-bucket-region",
      "access_key": "your-access-key",
      "secret_key": "your-secret-key"
    }
  }
}
  • 查看特定存储库中的快照GET _cat/snapshots/es_repository?v:这个命令返回es_repository存储库中的所有快照及其详细信息,包括快照 ID、状态、开始时间、结束时间、持续时间、包含的索引数量、成功和失败的分片数量等。
GET _cat/snapshots/es_repository?v
id                     status start_epoch start_time end_epoch end_time duration indices successful_shards failed_shards total_shards
snapshot_1             SUCCESS 1628884800 08:00:00   1628888400 09:00:00 1h       3       10                0             10
snapshot_2             SUCCESS 1628971200 08:00:00   1628974800 09:00:00 1h       3       10                0             10

创建索引快照

# PUT _snapshot/my_repository/<my_snapshot_{now/d}>
PUT _snapshot/my_repository/my_snapshot
{
  "indices": "my-index,logs-my_app-default",
}

根据快照的大小不同,完成快照可能需要一些时间。默认情况下,create snapshot API 只会异步启动快照过程,该过程在后台运行。要更改为同步调用,可以将 wait_for_completion 查询参数设置为 true

PUT _snapshot/my_repository/my_snapshot?wait_for_completion=true

另外还可以使用 clone snapshot API 克隆现有的快照。要监控当前正在运行的快照,可以使用带有 _current 请求路径参数的 get snapshot API。

GET _snapshot/my_repository/_current

如果要获取参与当前运行快照的每个分片的完整详细信息,可以使用 get snapshot status API。

GET _snapshot/_status

成功创建快照之后,就可以在 S3 上看到备份的数据块文件,这个是正确的快照层级结构:

需要注意的是, "base_path": ""这里最好不要加/,虽然不影响同集群迁移,这个会为我们在不同厂商的搜索引擎中迁移遇到问题,可能是这样的,所以需要注意。

所以在 Open Search 中还原 Elasticsearch 就遇到了这个问题:

{
  "error": {
    "root_cause": [
      {
        "type": "snapshot_missing_exception",
        "reason": "[easy_repository:2/-jOQ0oucQDGF3hJMNz-vKQ] is missing"
      }
    ],
    "type": "snapshot_missing_exception",
    "reason": "[easy_repository:2/-jOQ0oucQDGF3hJMNz-vKQ] is missing",
    "caused_by": {
      "type": "no_such_file_exception",
      "reason": "Blob object [11111/indices/7fv2zAi4Rt203JfsczUrBg/meta-YGnzxZABRBxW-2vqcmci.dat] not found: The specified key does not exist. (Service: S3, Status Code: 404, Request ID: R71DDHX4XXM0434T, Extended Request ID: d9M/HWvPvMFdPhB6KX+wYCW3ZFqeFo9EoscWPkulOXWa+TnovAE5PlemtuVzKXjlC+rrgskXAus=)"
    }
  },
  "status": 404
}

恢复索引快照

POST _snapshot/my_repository/my_snapshot_2099.05.06/_restore
{
  "indices": "my-index,logs-my_app-default",
}

各个集群的还原

  1. Elasticsearch 7.10.2 的快照可以还原到 Easysearch 和 Amazon OpenSearch

  2. 从 Easysearch 1.8.2 还原到 Elasticsearch 7.10.2 报错如下:
{
  "error": {
    "root_cause": [
      {
        "type": "snapshot_restore_exception",
        "reason": "[s3_repository:1/a2qV4NYIReqvgW6BX_nxxw] cannot restore index [my_indexs] because it cannot be upgraded"
      }
    ],
    "type": "snapshot_restore_exception",
    "reason": "[s3_repository:1/a2qV4NYIReqvgW6BX_nxxw] cannot restore index [my_indexs] because it cannot be upgraded",
    "caused_by": {
      "type": "illegal_state_exception",
      "reason": "The index [[my_indexs/ALlTCIr0RJqtP06ouQmf0g]] was created with version [1.8.2] but the minimum compatible version is [6.0.0-beta1]. It should be re-indexed in Elasticsearch 6.x before upgrading to 7.10.2."
    }
  },
  "status": 500
}
  1. 从 Amazon OpenSearch 2.1.3 还原到 Elasticsearch 7.10.2 报错如下(无论是否开启兼容模式):
{
  "error": {
    "root_cause": [
      {
        "type": "snapshot_restore_exception",
        "reason": "[aos:2/D-oyYSscSdCbZFcmPZa_yg] the snapshot was created with Elasticsearch version [36.34.78-beta2] which is higher than the version of this node [7.10.2]"
      }
    ],
    "type": "snapshot_restore_exception",
    "reason": "[aos:2/D-oyYSscSdCbZFcmPZa_yg] the snapshot was created with Elasticsearch version [36.34.78-beta2] which is higher than the version of this node [7.10.2]"
  },
  "status": 500
}
  1. 从 Easysearch 1.8.2 还原到 Amazon OpenSearch2.13 报错如下(无论是否开启兼容模式):
{
  "error": {
    "root_cause": [
      {
        "type": "snapshot_restore_exception",
        "reason": "[easy_repository:2/LE18AWHlRJu9rpz9BJatUQ] cannot restore index [my_indexs] because it cannot be upgraded"
      }
    ],
    "type": "snapshot_restore_exception",
    "reason": "[easy_repository:2/LE18AWHlRJu9rpz9BJatUQ] cannot restore index [my_indexs] because it cannot be upgraded",
    "caused_by": {
      "type": "illegal_state_exception",
      "reason": "The index [[my_indexs/VHOo7yfDTRa48uhQvquFzQ]] was created with version [1.8.2] but the minimum compatible version is OpenSearch 1.0.0 (or Elasticsearch 7.0.0). It should be re-indexed in OpenSearch 1.x (or Elasticsearch 7.x) before upgrading to 2.13.0."
    }
  },
  "status": 500
}
  1. Amazon OpenSearch 还原到 Easysearch 同样失败
{
  "error": {
    "root_cause": [
      {
        "type": "snapshot_restore_exception",
        "reason": "[aoss:2/D-oyYSscSdCbZFcmPZa_yg] cannot restore index [aos] because it cannot be upgraded"
      }
    ],
    "type": "snapshot_restore_exception",
    "reason": "[aoss:2/D-oyYSscSdCbZFcmPZa_yg] cannot restore index [aos] because it cannot be upgraded",
    "caused_by": {
      "type": "illegal_state_exception",
      "reason": "The index [[aos/864WjTAXQCaxJ829V5ktaw]] was created with version [36.34.78-beta2] but the minimum compatible version is [6.0.0]. It should be re-indexed in Easysearch 6.x before upgrading to 1.8.2."
    }
  },
  "status": 500
}
  1. Elasticsearch 8.14.3 迁移到 Amazon OpenSearch 或者 Elasticsearch 都是有这个报错:
{
  "error": {
    "root_cause": [
      {
        "type": "parsing_exception",
        "reason": "Failed to parse object: unknown field [uuid] found",
        "line": 1,
        "col": 25
      }
    ],
    "type": "repository_exception",
    "reason": "[snap] Unexpected exception when loading repository data",
    "caused_by": {
      "type": "parsing_exception",
      "reason": "Failed to parse object: unknown field [uuid] found",
      "line": 1,
      "col": 25
    }
  },
  "status": 500
}

这是由于 Elasticsearch 8 在创建快照的时候会默认加上一个 UUID 的字段,所以我们低版本的 Easysearch、Amazon OpenSearch 中会找不到这个字段,在执行GET _cat/snapshots/snap?v的时候就报错,及时在注册存储库的时候显示加上 UUID 的字段也无事无补。

{
  "snapshot-repo-name": {
    "type": "s3",
    "uuid": "qlJ0uqErRmW6aww2Fyt4Fg",
    "settings": {
    "bucket": "<bucket-name>",
    "base_path": "<bucket-prefix>",
    }
  },

以下是兼容性对比,每行第一列代表源集群,第一行代表目标集群:

快照兼容对比 Easysearch 1.8.2 Elasticsearch 7.10.2 OpenSearch 2.13
Easysearch 1.8.2 兼容 不兼容 不兼容
Elasticsearch 7.10.2 兼容 兼容 兼容
OpenSearch 2.13 不兼容 不兼容 兼容

Elasticsearch 的兼容列表官方的列表如下:

参考文献

  1. 开始使用 Elastic Stack 和 Docker Compose:第 1 部分
    https://www.elastic.co/cn/blog/getting-started-with-the-elastic-stack-and-docker-compose

  2. Docker Compose 部署多节点 Elasticsearch
    https://www.elastic.co/guide/en/elasticsearch/reference/7.10/docker.html#docker-compose-file

  3. repository-s3 教程
    https://www.elastic.co/guide/en/elasticsearch/reference/8.14/repository-s3.html
    https://www.elastic.co/guide/en/elasticsearch/plugins/7.10/repository-s3.html

  4. snapshot-restore
    https://www.elastic.co/guide/en/elasticsearch/reference/7.10/snapshot-restore.html

  5. 在亚马逊 OpenSearch 服务中创建索引快照
    https://docs.amazonaws.cn/zh_cn/opensearch-service/latest/developerguide/managedomains-snapshots.html#managedomains-snapshot-restore

  6. 教程:迁移至 Amazon OpenSearch Service
    https://docs.amazonaws.cn/zh_cn/opensearch-service/latest/developerguide/migration.html

关于 Easysearch 有奖征文活动

黑神话悟空

无论你是 Easysearch 的老用户,还是第一次听说这个名字,只要你对 INFINI Labs 旗下的 Easysearch 产品感兴趣,或者是希望了解 Easysearch,都可以参加这次活动。

详情查看:Easysearch 征文活动

作者:韩旭,亚马逊云技术支持,亚马逊云科技技领云博主,目前专注于云计算开发和大数据领域。

原文:https://infinilabs.cn/blog/2024/comparison-of-snapshot-compatibility-between-easysearch-elasticsearch-and-opensearch/

从 OpenAI 停服看中国市场:国产替代崛起的机遇与挑战

EasysearchINFINI Labs 小助手 发表了文章 • 0 个评论 • 3611 次浏览 • 2024-07-05 11:50 • 来自相关话题

INFINI Easysearch

一、OpenAI 停服事件背景

OpenAI 自 2020 年推出 GPT-3 以来,在全球范围内引起了极大的反响。其强大的自然语言处理能力使其成为许多企业和开发者的首选工具。然而,2024 年 6 月 25 日,许多中国用户收到了一封来自 OpenAI 的邮件,邮件中明确表示,自 2024 年 7 月 9 日起,OpenAI 将停止对中国内地和香港地区提供 API 服务。

INFINI Easysearch

这一事件引发了国内开发者和企业的广泛讨论,特别是在人工智能技术应用逐渐深入的背景下,OpenAI 的停服无疑会对中国市场产生一定的影响。在 AI 技术迅猛发展的当下,许多中国企业和开发者依赖 OpenAI 的 API 进行各种应用的开发。尤其是在大模型技术领域,不少初创公司通过“套壳”OpenAI 技术快速推向市场。所谓“OpenAI 套壳”,是指一些公司仅对 OpenAI 的技术进行表面包装和小改动,而未进行深度创新 。OpenAI CEO 山姆·奥特曼曾明确指出,简单包装 OpenAI 技术的公司难以长久生存。此次 API 服务的终止,意味着这些企业需要寻找新的技术支持,或者在短时间内加速自主研发 。

二、国产替代的挑战与机遇

OpenAI 停止对中国提供 API 服务将对国内 AI 行业带来短期冲击,但从长远来看,这也可能成为推动国内 AI 技术自主创新和研发的契机。国内企业将被迫加大自主研发力度,减少对外部技术的依赖,从而推动国产 AI 技术的发展 。虽然目前国内大模型企业在技术上与 OpenAI 存在一定差距,但已有不少公司在不断赶超。例如,百度的文心大模型、科大讯飞的星火大模型以及清华智谱的 ChatGLM 基础模型,都在性能上逐渐逼近甚至超过了 GPT-4 。从现状来看,国内大模型厂商已经逐步进入了性能提升的关键期,应用场景从办公、生活拓展到医疗、工业、教育等领域。

三、Elasticsearch 国产化替代的需求

INFINI Easysearch

Elasticsearch(简称 ES)作为一种开源的分布式搜索和分析引擎,以其强大的搜索能力和高效的数据处理能力,广泛应用于各种大数据和搜索相关业务场景。然而,随着国际政治环境的变化和技术壁垒的加剧,依赖国外技术的风险日益凸显。在这种背景下,推动 Elasticsearch 的国产化替代至关重要,既能保障国家信息安全,也能促进国内技术自主创新和产业发展。

首先,依赖国外技术可能带来技术封锁风险,一旦国外企业因政治或经济原因停止服务,中国企业的业务连续性和数据安全性将受到威胁。推动国产化替代有助于规避这些风险,保障数据安全和业务的稳定运行。国外搜索引擎和数据库系统通常为西方市场优化,未必适合中国市场。例如,Elasticsearch 在处理中文信息时需要额外的插件和调整,而国产替代方案可以更好地适应本地化需求,同时确保数据存储和处理符合国家法律法规。

其次,推动 Elasticsearch 的国产化替代有助于激发国内企业的创新活力,减少对国外技术的依赖,提升在搜索和大数据领域的核心竞争力。采用国产替代方案不仅能够降低企业的技术成本,还能构建自主的技术生态系统,减少对外部的依赖。与此同时国产化替代也有助于提升国内技术人才水平,通过自主研发和技术创新培养出高水平的技术人才,推动技术创新和产业升级。

在性能和安全方面,Elasticsearch 在数据保护和性能方面存在不足。开源版本不具备数据保护功能,用户必须付费获得相关的安全功能。2021 年 Elastic 公司将其开源软件许可证变更为双授权许可,可能带来安全风险。此外,Elasticsearch 在数据读写性能和集群扩展上也存在技术挑战,进一步推动了国产替代的需求。

四、Easysearch:国产替代的优秀范例

INFINI Easysearch

在 OpenAI 退出中国市场的背景下,国产技术的重要性日益凸显。作为国产搜索引擎技术的代表,Easysearch 展示了强大的替代潜力。

Easysearch 是一款基于国内自主研发的高性能搜索引擎,其核心引擎基于开源的 Apache Lucene。与 Elasticsearch 相比,Easysearch 不仅提供了相当的功能,还进行了更具针对性的优化。

  • 轻量级:Easysearch 的安装包小于 50MB,部署安装简单,适合企业快速上手。

  • 跨平台支持:Easysearch 支持主流操作系统和 CPU 架构,兼容国产信创环境,确保多样化环境下的稳定运行。

  • 高性能:Easysearch 针对不同的使用场景进行了优化,以更低的硬件成本提供更高的服务性能,从而实现降本增效。

  • 安全增强:Easysearch 默认提供完整的企业级安全功能,支持 LDAP/AD 集成,能够对索引、文档和字段级别进行粒度化权限管控,确保数据的安全性和隐私性。

  • 稳定可靠:Easysearch 修复了大量内核问题,解决了内存泄露、集群卡顿和查询缓慢等问题,经过严苛的业务环境考验,保证了其稳定性和可靠性。

  • 简单易用:Easysearch 提供了企业级管理后台,运营标准化和自动化,使用户能够通过简单的页面操作实现专家级的运维管理工作。

Easysearch 特别注重数据安全和隐私保护,所有数据都在国内处理和存储,符合数据主权要求。这对关注数据安全和隐私的企业尤为重要,能够有效保障数据的安全性和合规性。

Easysearch 致力于构建一个开放的技术生态,通过丰富的开发者资源和支持,为国内开发者提供了一个强大的技术平台。

  • 兼容性:Easysearch 兼容 Elasticsearch 的语法,支持 Elasticsearch 原有的 Query DSL 和 SQL 语法,并且兼容现有的 Elasticsearch SDK。这样,企业和开发者可以平滑地迁移到 Easysearch,无需修改现有代码。

  • 中文适配:Easysearch 在功能上进行了中文适配,能够更好地支持中文搜索和分析,满足本地化需求。

  • 功能增强:Easysearch 不断完善和增强企业级功能,使其在搜索业务场景中保持简洁与易用性,同时提升功能的丰富度和深度。

  • 信创适配:Easysearch 支持信创环境,确保在国产环境中也能平稳运行和使用。

  • 平滑迁移:Easysearch 基于网关实现了无缝的跨版本迁移与升级,用户可以随时安全回退,确保系统的持续稳定性。

Easysearch 作为国产搜索引擎技术的代表,展示了国产替代的强大潜力。通过自主研发和技术创新,Easysearch 不仅提供了强大的功能和性能,还确保了数据安全和隐私保护。它为国内企业和开发者提供了一个可靠的技术平台,推动了国产技术的发展和应用。未来,随着更多国产技术的崛起,中国将在全球技术领域占据更加重要的地位。

五、结束语

随着 OpenAI 服务在国内的终止,中国 AI 市场迎来了自主创新的机遇。国内企业如百度、科大讯飞等正加速自主研发,缩小技术差距。同时,在搜索引擎领域,极限科技推出 Easysearch 搜索引擎为 Elasticsearch 国产替代提供了新的选择。展望未来,国产技术的持续创新将助力中国在全球技术领域占据更重要的地位。

关于极限科技(INFINI Labs)

INFINI Labs

极限科技,全称极限数据(北京)科技有限公司,是一家专注于实时搜索与数据分析的软件公司。旗下品牌极限实验室(INFINI Labs)致力于打造极致易用的数据探索与分析体验。

极限科技是一支年轻的团队,采用天然分布式的方式来进行远程协作,员工分布在全球各地,希望通过努力成为中国乃至全球企业大数据实时搜索分析产品的首选,为中国技术品牌输出添砖加瓦。

官网:https://www.infinilabs.cn

联系我们

作者:Muses

原文:https://infinilabs.cn/blog/2024/from-openai-service-discontinuation-to-the-chinese-market-opportunities-and-challenges-of-domestic-replacement-rising/

【搜索客社区日报】第1853期 (2024-07-05)

社区日报Fred2000 发表了文章 • 0 个评论 • 2627 次浏览 • 2024-07-05 09:26 • 来自相关话题

Gitee 两大指标超越 GitHub,携手中国开源共绘新篇章 https://mp.weixin.qq.com/s/J92AOb9HGQDb4FqqJUPGhQ 前沿重器[51] | 聊聊搜索系统4:query理解 https://mp.weixin.qq.com/s/R4njGbiz_yT0wqN4by0uDg Elasticsearch 是什么?工作原理是怎么样的? https://mp.weixin.qq.com/s/UXzFg6LbHCifeObiLsXAMA INFINI Easysearch 尝鲜 Hands on https://mp.weixin.qq.com/s/OLdD3KkgXK5Q4e2RDzMD8Q 编辑:Fred  更多资讯:http://news.searchkit.cn
Gitee 两大指标超越 GitHub,携手中国开源共绘新篇章 https://mp.weixin.qq.com/s/J92AOb9HGQDb4FqqJUPGhQ 前沿重器[51] | 聊聊搜索系统4:query理解 https://mp.weixin.qq.com/s/R4njGbiz_yT0wqN4by0uDg Elasticsearch 是什么?工作原理是怎么样的? https://mp.weixin.qq.com/s/UXzFg6LbHCifeObiLsXAMA INFINI Easysearch 尝鲜 Hands on https://mp.weixin.qq.com/s/OLdD3KkgXK5Q4e2RDzMD8Q 编辑:Fred  更多资讯:http://news.searchkit.cn

【 INFINI Workshop 北京站】1月18日一起动手实验玩转 Easysearch

活动liaosy 发表了文章 • 0 个评论 • 3163 次浏览 • 2023-12-15 16:22 • 来自相关话题

与 INFINI Labs 的技术专家面对面,第一时间了解极限实验室的发布最新产品和功能特性,通过动手实战,快速掌握最前沿的搜索技术,并用于实际项目中。欢迎大家扫描海报二维码免费报名参加。

活动时间:2024-01-18 13:30~17:30

活动地点:北京市海淀区 Wework 辉煌时代大厦 3 楼 3E 会议室

分享议题

  • Easysearch 总体介绍及搭建实战
  • 基于 INFINI Console 实现跨版本、跨引擎统一管控
  • Elasticsearch -> Easysearch 在线迁移实操

参会提示

  • 请务必自备电脑(Windows 系统环境请提前安装好 Linux 虚拟机)
  • 请提前在 INFINI Labs 官网下载对应平台最新安装包(INFINI Easysearch、INFINI Gateway、INFINI Console)
  • 下载地址:https://www.infinilabs.com/download
  • 如有任何疑问可添加 INFINI Labs 小助手(微信号: INFINI-Labs)进行联系

20231214-095304-qrcode.jpeg

elasticsearcg索引配置不变,doc数量不变却越写越慢

回复

Elasticsearchkin122 回复了问题 • 2 人关注 • 3 个回复 • 3921 次浏览 • 2025-07-30 08:47 • 来自相关话题

【字节跳动】 深圳/上海招聘Elasticsearch研发工程师

回复

求职招聘tinycols 发起了问题 • 1 人关注 • 0 个回复 • 3469 次浏览 • 2024-12-05 16:57 • 来自相关话题

3月26日 OpenSearch Community Meeting 视频回放

回复

OpenSearchCharele 回复了问题 • 2 人关注 • 1 个回复 • 5384 次浏览 • 2024-04-05 16:58 • 来自相关话题

ElasticSearch自动补全,中文不准确的问题,请大家帮我看一下

回复

ElasticsearchGod_lockin 回复了问题 • 2 人关注 • 1 个回复 • 3815 次浏览 • 2023-11-21 22:17 • 来自相关话题

ES 调优帖:Gateway 批量写入性能优化实践

ElasticsearchINFINI Labs 小助手 发表了文章 • 0 个评论 • 1378 次浏览 • 5 天前 • 来自相关话题

背景:bulk 优化的应用

在 ES 的写入优化里,bulk 操作被广泛地用于批量处理数据。bulk 操作允许用户一次提交多个数据操作,如索引、更新、删除等,从而提高数据处理效率。bulk 操作的实现原理是,将数据操作请求打包成 HTTP 请求,并批量提交给 Elasticsearch 服务器。这样,Elasticsearch 服务器就可以一次处理多个数据操作,从而提高处理效率。

这种优化的核心价值在于减少了网络往返的次数和连接建立的开销。每一次单独的写入操作都需要经历完整的请求-响应周期,而批量写入则是将多个操作打包在一起,用一次通信完成原本需要多次交互的工作。这不仅仅节省了时间,更重要的是释放了系统资源,让服务器能够专注于真正的数据处理,而不是频繁的协议握手和状态维护。

这样的批量请求的确是可以优化写入请求的效率,让 ES 集群获得更多的资源去做写入请求的集中处理。但是除了客户端与 ES 集群的通讯效率优化,还有其他中间过程能优化么?

Gateway 的优化点

bulk 的优化理念是将日常零散的写入需求做集中化的处理,尽量减低日常请求的损耗,完成资源最大化的利用。简而言之就是“好钢用在刀刃上”。

但是 ES 在收到 bulk 写入请求后,也是需要协调节点根据文档的 id 计算所属的分片来将数据分发到对应的数据节点的。这个过程也是有一定损耗的,如果 bulk 请求中数据分布的很散,每个分片都需要进行写入,原本 bulk 集中写入的需求优势则还是没有得到最理想化的提升。

gateway 的写入加速则对 bulk 的优化理念的最大化补全。

gateway 可以本地计算每个索引文档对应后端 Elasticsearch 集群的目标存放位置,从而能够精准的进行写入请求定位

在一批 bulk 请求中,可能存在多个后端节点的数据,bulk_reshuffle 过滤器用来将正常的 bulk 请求打散,按照目标节点或者分片进行拆分重新组装,避免 Elasticsearch 节点收到请求之后再次进行请求分发, 从而降低 Elasticsearch 集群间的流量和负载,也能避免单个节点成为热点瓶颈,确保各个数据节点的处理均衡,从而提升集群总体的索引吞吐能力。

整理的优化思路如下图:

优化实践

那我们来实践一下,看看 gateway 能提升多少的写入。

这里我们分 2 个测试场景:

  1. 基础集中写入测试,不带文档 id,直接批量写入。这个场景更像是日志或者监控数据采集的场景。
  2. 带文档 id 的写入测试,更偏向搜索场景或者大数据批同步的场景。

2 个场景都进行直接写入 ES 和 gateway 转发 ES 的效率比对。

测试材料除了需要备一个网关和一套 es 外,其余的内容如下:

测试索引 mapping 一致,名称区分:

PUT gateway_bulk_test
{
  "settings": {
    "number_of_shards": 6,
    "number_of_replicas": 0
  },
  "mappings": {
    "properties": {
      "timestamp": {
        "type": "date",
        "format": "strict_date_optional_time"
      },
      "field1": {
        "type": "keyword"
      },
      "field2": {
        "type": "keyword"
      },
      "field3": {
        "type": "keyword"
      },
      "field4": {
        "type": "integer"
      },
      "field5": {
        "type": "keyword"
      },
      "field6": {
        "type": "float"
      }
    }
  }
}

PUT bulk_test
{
  "settings": {
    "number_of_shards": 6,
    "number_of_replicas": 0
  },
  "mappings": {
    "properties": {
      "timestamp": {
        "type": "date",
        "format": "strict_date_optional_time"
      },
      "field1": {
        "type": "keyword"
      },
      "field2": {
        "type": "keyword"
      },
      "field3": {
        "type": "keyword"
      },
      "field4": {
        "type": "integer"
      },
      "field5": {
        "type": "keyword"
      },
      "field6": {
        "type": "float"
      }
    }
  }
}

gateway 的配置文件如下:

path.data: data
path.logs: log

entry:
  - name: my_es_entry
    enabled: true
    router: my_router
    max_concurrency: 200000
    network:
      binding: 0.0.0.0:8000

flow:
  - name: async_bulk
    filter:
      - bulk_reshuffle:
          when:
            contains:
              _ctx.request.path: /_bulk
          elasticsearch: prod
          level: node
          partition_size: 1
          fix_null_id: true
      - elasticsearch:
          elasticsearch: prod #elasticsearch configure reference name
          max_connection_per_node: 1000 #max tcp connection to upstream, default for all nodes
          max_response_size: -1 #default for all nodes
          balancer: weight
          refresh: # refresh upstream nodes list, need to enable this feature to use elasticsearch nodes auto discovery
            enabled: true
            interval: 60s
          filter:
            roles:
              exclude:
                - master

router:
  - name: my_router
    default_flow: async_bulk

elasticsearch:
  - name: prod
    enabled: true
    endpoints:
      - https://127.0.0.1:9221
      - https://127.0.0.1:9222
      - https://127.0.0.1:9223
    basic_auth:
      username: admin
      password: admin

pipeline:
  - name: bulk_request_ingest
    auto_start: true
    keep_running: true
    retry_delay_in_ms: 1000
    processor:
      - bulk_indexing:
          max_connection_per_node: 100
          num_of_slices: 3
          max_worker_size: 30
          idle_timeout_in_seconds: 10
          bulk:
            compress: false
            batch_size_in_mb: 10
            batch_size_in_docs: 10000
          consumer:
            fetch_max_messages: 100
          queue_selector:
            labels:
              type: bulk_reshuffle

测试脚本如下:

#!/usr/bin/env python3
"""
ES Bulk写入性能测试脚本

"""

import hashlib
import json
import random
import string
import time
from typing import List, Dict, Any

import requests
from concurrent.futures import ThreadPoolExecutor
from datetime import datetime
import urllib3

# 禁用SSL警告
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)

class ESBulkTester:
    def __init__(self):
        # 配置变量 - 可修改
        self.es_configs = [
            {
                "name": "ES直连",
                "url": "https://127.0.0.1:9221",
                "index": "bulk_test",
                "username": "admin",  # 修改为实际用户名
                "password": "admin",  # 修改为实际密码
                "verify_ssl": False  # HTTPS需要SSL验证
            },
            {
                "name": "Gateway代理",
                "url": "http://localhost:8000",
                "index": "gateway_bulk_test",
                "username": None,  # 无需认证
                "password": None,
                "verify_ssl": False
            }
        ]
        self.batch_size = 10000  # 每次bulk写入条数
        self.log_interval = 100000  # 每多少次bulk写入输出日志

        # ID生成规则配置 - 前2位后5位
        self.id_prefix_start = 1
        self.id_prefix_end = 999      # 前3位: 01-999
        self.id_suffix_start = 1
        self.id_suffix_end = 9999   # 后4位: 0001-9999

        # 当前ID计数器
        self.current_prefix = self.id_prefix_start
        self.current_suffix = self.id_suffix_start

    def generate_id(self) -> str:
        """生成固定规则的ID - 前2位后5位"""
        id_str = f"{self.current_prefix:02d}{self.current_suffix:05d}"

        # 更新计数器
        self.current_suffix += 1
        if self.current_suffix > self.id_suffix_end:
            self.current_suffix = self.id_suffix_start
            self.current_prefix += 1
            if self.current_prefix > self.id_prefix_end:
                self.current_prefix = self.id_prefix_start

        return id_str

    def generate_random_hash(self, length: int = 32) -> str:
        """生成随机hash值"""
        random_string = ''.join(random.choices(string.ascii_letters + string.digits, k=length))
        return hashlib.md5(random_string.encode()).hexdigest()

    def generate_document(self) -> Dict[str, Any]:
        """生成随机文档内容"""
        return {
            "timestamp": datetime.now().isoformat(),
            "field1": self.generate_random_hash(),
            "field2": self.generate_random_hash(),
            "field3": self.generate_random_hash(),
            "field4": random.randint(1, 1000),
            "field5": random.choice(["A", "B", "C", "D"]),
            "field6": random.uniform(0.1, 100.0)
        }

    def create_bulk_payload(self, index_name: str) -> str:
        """创建bulk写入payload"""
        bulk_data = []

        for _ in range(self.batch_size):
            #doc_id = self.generate_id()
            doc = self.generate_document()

            # 添加index操作
            bulk_data.append(json.dumps({
                "index": {
                    "_index": index_name,
            #        "_id": doc_id
                }
            }))
            bulk_data.append(json.dumps(doc))

        return "\n".join(bulk_data) + "\n"

    def bulk_index(self, config: Dict[str, Any], payload: str) -> bool:
        """执行bulk写入"""
        url = f"{config['url']}/_bulk"
        headers = {
            "Content-Type": "application/x-ndjson"
        }

        # 设置认证信息
        auth = None
        if config.get('username') and config.get('password'):
            auth = (config['username'], config['password'])

        try:
            response = requests.post(
                url,
                data=payload,
                headers=headers,
                auth=auth,
                verify=config.get('verify_ssl', True),
                timeout=30
            )
            return response.status_code == 200
        except Exception as e:
            print(f"Bulk写入失败: {e}")
            return False

    def refresh_index(self, config: Dict[str, Any]) -> bool:
        """刷新索引"""
        url = f"{config['url']}/{config['index']}/_refresh"

        # 设置认证信息
        auth = None
        if config.get('username') and config.get('password'):
            auth = (config['username'], config['password'])

        try:
            response = requests.post(
                url,
                auth=auth,
                verify=config.get('verify_ssl', True),
                timeout=10
            )
            success = response.status_code == 200
            print(f"索引刷新{'成功' if success else '失败'}: {config['index']}")
            return success
        except Exception as e:
            print(f"索引刷新失败: {e}")
            return False

    def run_test(self, config: Dict[str, Any], round_num: int, total_iterations: int = 100000):
        """运行性能测试"""
        test_name = f"{config['name']}-第{round_num}轮"
        print(f"\n开始测试: {test_name}")
        print(f"ES地址: {config['url']}")
        print(f"索引名称: {config['index']}")
        print(f"认证: {'是' if config.get('username') else '否'}")
        print(f"每次bulk写入: {self.batch_size}条")
        print(f"总计划写入: {total_iterations * self.batch_size}条")
        print("-" * 50)

        start_time = time.time()
        success_count = 0
        error_count = 0

        for i in range(1, total_iterations + 1):
            payload = self.create_bulk_payload(config['index'])

            if self.bulk_index(config, payload):
                success_count += 1
            else:
                error_count += 1

            # 每N次输出日志
            if i % self.log_interval == 0:
                elapsed_time = time.time() - start_time
                rate = i / elapsed_time if elapsed_time > 0 else 0
                print(f"已完成 {i:,} 次bulk写入, 耗时: {elapsed_time:.2f}秒, 速率: {rate:.2f} bulk/秒")

        end_time = time.time()
        total_time = end_time - start_time
        total_docs = total_iterations * self.batch_size

        print(f"\n{test_name} 测试完成!")
        print(f"总耗时: {total_time:.2f}秒")
        print(f"成功bulk写入: {success_count:,}次")
        print(f"失败bulk写入: {error_count:,}次")
        print(f"总文档数: {total_docs:,}条")
        print(f"平均速率: {success_count/total_time:.2f} bulk/秒")
        print(f"文档写入速率: {total_docs/total_time:.2f} docs/秒")
        print("=" * 60)

        return {
            "test_name": test_name,
            "config_name": config['name'],
            "round": round_num,
            "es_url": config['url'],
            "index": config['index'],
            "total_time": total_time,
            "success_count": success_count,
            "error_count": error_count,
            "total_docs": total_docs,
            "bulk_rate": success_count/total_time,
            "doc_rate": total_docs/total_time
        }

    def run_comparison_test(self, total_iterations: int = 10000):
        """运行双地址对比测试"""
        print("ES Bulk写入性能测试开始")
        print(f"测试时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
        print("=" * 60)

        results = []
        rounds = 2  # 每个地址测试2轮

        # 循环测试所有配置
        for config in self.es_configs:
            print(f"\n开始测试配置: {config['name']}")
            print("*" * 40)

            for round_num in range(1, rounds + 1):
                # 运行测试
                result = self.run_test(config, round_num, total_iterations)
                results.append(result)

                # 每轮结束后刷新索引
                print(f"\n第{round_num}轮测试完成,执行索引刷新...")
                self.refresh_index(config)

                # 重置ID计数器
                if round_num == 1:
                    # 第1轮:使用初始ID范围(新增数据)
                    print("第1轮:新增数据模式")
                else:
                    # 第2轮:重复使用相同ID(更新数据模式)
                    print("第2轮:数据更新模式,复用第1轮ID")
                    self.current_prefix = self.id_prefix_start
                    self.current_suffix = self.id_suffix_start

                print(f"{config['name']} 第{round_num}轮测试结束\n")

        # 输出对比结果
        print("\n性能对比结果:")
        print("=" * 80)

        # 按配置分组显示结果
        config_results = {}
        for result in results:
            config_name = result['config_name']
            if config_name not in config_results:
                config_results[config_name] = []
            config_results[config_name].append(result)

        for config_name, rounds_data in config_results.items():
            print(f"\n{config_name}:")
            total_time = 0
            total_bulk_rate = 0
            total_doc_rate = 0

            for round_data in rounds_data:
                print(f"  第{round_data['round']}轮:")
                print(f"    耗时: {round_data['total_time']:.2f}秒")
                print(f"    Bulk速率: {round_data['bulk_rate']:.2f} bulk/秒")
                print(f"    文档速率: {round_data['doc_rate']:.2f} docs/秒")
                print(f"    成功率: {round_data['success_count']/(round_data['success_count']+round_data['error_count'])*100:.2f}%")

                total_time += round_data['total_time']
                total_bulk_rate += round_data['bulk_rate']
                total_doc_rate += round_data['doc_rate']

            avg_bulk_rate = total_bulk_rate / len(rounds_data)
            avg_doc_rate = total_doc_rate / len(rounds_data)

            print(f"  平均性能:")
            print(f"    总耗时: {total_time:.2f}秒")
            print(f"    平均Bulk速率: {avg_bulk_rate:.2f} bulk/秒")
            print(f"    平均文档速率: {avg_doc_rate:.2f} docs/秒")

        # 整体对比
        if len(config_results) >= 2:
            config_names = list(config_results.keys())
            config1_avg = sum([r['bulk_rate'] for r in config_results[config_names[0]]]) / len(config_results[config_names[0]])
            config2_avg = sum([r['bulk_rate'] for r in config_results[config_names[1]]]) / len(config_results[config_names[1]])

            if config1_avg > config2_avg:
                faster = config_names[0]
                rate_diff = config1_avg - config2_avg
            else:
                faster = config_names[1]
                rate_diff = config2_avg - config1_avg

            print(f"\n整体性能对比:")
            print(f"{faster} 平均性能更好,bulk速率高 {rate_diff:.2f} bulk/秒")
            print(f"性能提升: {(rate_diff/min(config1_avg, config2_avg)*100):.1f}%")

def main():
    """主函数"""
    tester = ESBulkTester()

    # 运行测试(每次bulk 1万条,300次bulk = 300万条文档)
    tester.run_comparison_test(total_iterations=300)

if __name__ == "__main__":
    main()

1. 日志场景:不带 id 写入

测试条件:

  1. bulk 写入数据不带文档 id
  2. 每批次 bulk 10000 条数据,总共写入 30w 数据

这里把

反馈结果:

性能对比结果:
================================================================================

ES直连:
  第1轮:
    耗时: 152.29秒
    Bulk速率: 1.97 bulk/秒
    文档速率: 19699.59 docs/秒
    成功率: 100.00%
  平均性能:
    总耗时: 152.29秒
    平均Bulk速率: 1.97 bulk/秒
    平均文档速率: 19699.59 docs/秒

Gateway代理:
  第1轮:
    耗时: 115.63秒
    Bulk速率: 2.59 bulk/秒
    文档速率: 25944.35 docs/秒
    成功率: 100.00%
  平均性能:
    总耗时: 115.63秒
    平均Bulk速率: 2.59 bulk/秒
    平均文档速率: 25944.35 docs/秒

整体性能对比:
Gateway代理 平均性能更好,bulk速率高 0.62 bulk/秒
性能提升: 31.7%

2. 业务场景:带文档 id 的写入

测试条件:

  1. bulk 写入数据带有文档 id,两次测试写入的文档 id 生成规则一致且重复。
  2. 每批次 bulk 10000 条数据,总共写入 30w 数据

这里把 py 脚本中 第 99 行 和 第 107 行的注释打开。

反馈结果:

性能对比结果:
================================================================================

ES直连:
  第1轮:
    耗时: 155.30秒
    Bulk速率: 1.93 bulk/秒
    文档速率: 19317.39 docs/秒
    成功率: 100.00%
  平均性能:
    总耗时: 155.30秒
    平均Bulk速率: 1.93 bulk/秒
    平均文档速率: 19317.39 docs/秒

Gateway代理:
  第1轮:
    耗时: 116.73秒
    Bulk速率: 2.57 bulk/秒
    文档速率: 25700.06 docs/秒
    成功率: 100.00%
  平均性能:
    总耗时: 116.73秒
    平均Bulk速率: 2.57 bulk/秒
    平均文档速率: 25700.06 docs/秒

整体性能对比:
Gateway代理 平均性能更好,bulk速率高 0.64 bulk/秒
性能提升: 33.0%

小结

不管是日志场景还是业务价值更重要的大数据或者搜索数据同步场景, gateway 的写入加速都能平稳的节省 25%-30% 的写入耗时。

关于极限网关(INFINI Gateway)

INFINI Gateway 是一个开源的面向搜索场景的高性能数据网关,所有请求都经过网关处理后再转发到后端的搜索业务集群。基于 INFINI Gateway,可以实现索引级别的限速限流、常见查询的缓存加速、查询请求的审计、查询结果的动态修改等等。

官网文档:https://docs.infinilabs.com/gateway
开源地址:https://github.com/infinilabs/gateway

作者:金多安,极限科技(INFINI Labs)搜索运维专家,Elastic 认证专家,搜索客社区日报责任编辑。一直从事与搜索运维相关的工作,日常会去挖掘 ES / Lucene 方向的搜索技术原理,保持搜索相关技术发展的关注。
原文:https://infinilabs.cn/blog/2025/gateway-bulk-write-performance-optimization/

【搜索客社区日报】第2055期 (2025-06-16)

社区日报Muses 发表了文章 • 0 个评论 • 2179 次浏览 • 2025-06-17 17:41 • 来自相关话题

1、Easysearch 索引备份之 Clone API https://infinilabs.cn/blog/202 ... -api/ 2、私有知识库 Coco AI 实战(一):Coco Server Linux 平台部署 https://infinilabs.cn/blog/202 ... on-1/、 3、风口|继MoE、MCP与A2A之后,下一个模型协作风口是MoA https://mp.weixin.qq.com/s/_yv9gdBKv1yDK0rQNtbbiQ 4、干货:手把手搭建ElasticSearch日志监控告警 https://mp.weixin.qq.com/s/JH2AIAnxdFSPhsG7h-9y_g 5、搭建持久化的 INFINI Console 与 Easysearch 容器环境 https://infinilabs.cn/blog/202 ... cker/ 编辑:Muse 更多资讯:http://news.searchkit.cn

【搜索客社区日报】第2035期 (2025-05-12)

社区日报Muses 发表了文章 • 0 个评论 • 4175 次浏览 • 2025-05-12 11:29 • 来自相关话题

活动推荐🔥:【5月15日 北京】本次 Workshop 活动将围绕 “搜索服务统一治理” “流量管控” “服务编排” 三大核心板块展开,深入探讨如何通过 INFINI Labs 产品为企业提供高效、灵活的搜索基础设施管理方案。欢迎大家免费报名参加。 https://hdxu.cn/128g7 1、Elasticsearch中的三种分页策略深度解析:原理、使用及对比 https://blog.csdn.net/qq_26664 ... 98228 2、Easysearch 基础运维扫盲指南:从 HTTP 到 HTTPS、认证与安全访问全解析 https://mp.weixin.qq.com/s/HR7E7HAfS4ntpSkD_r5_Zw 3、MySQL数据实时接入Easysearch,零代码迁移全流程 https://mp.weixin.qq.com/s/bVGf8v6RAQljficJrjEISw 4、字节跳动开源了一款 Deep Research 项目 https://mp.weixin.qq.com/s/ejE6bfR_lFQutPy-u_pzmQ 5、最强中文TTS接入MCP-Server,效果再次封神! https://mp.weixin.qq.com/s/ivjDIwYXIqxyV3kOvJ2VhQ 编辑:Muse 更多资讯:http://news.searchkit.cn

【第 8 期】搜索客 Meetup | Elasticsearch 的一些“双刃剑”特性

活动searchkit 发表了文章 • 0 个评论 • 3517 次浏览 • 2025-03-13 17:54 • 来自相关话题

本次活动由 搜索客社区、极限科技(INFINI Labs) 联合举办,活动邀请到 INFINI Labs 搜索运维专家 金端 来分享 Elasticsearch 中一些典型的“双刃剑”特性,以及如何在实际使用中权衡和应对。欢迎预约直播观看 ~

活动主题:Elasticsearch 的一些“双刃剑”特性
活动时间:2025 年 03 月 26 日 19:00-20:00(周三)
活动形式:微信视频号(极限实验室)直播
报名方式:关注或扫码海报中的二维码进行预约

嘉宾介绍

金端,极限科技(INFINI Labs)搜索运维专家,Elasticsearch 官方认证工程师,搜索客社区日报编辑。在 ES 运维使用方面具有丰富的实战经验。对 ES/lucene 搜索分析方向保持学习和关注。

主题摘要

Elasticsearch 的许多特性确实是一把“双刃剑”,它们在提供强大功能的同时,也带来了潜在的使用瓶颈和运维挑战。分享主要讨论一些典型的“双刃剑”特性,以及如何在实际使用中权衡和应对。

参与有奖

本次直播活动将设有福袋抽奖环节,参与就有机会获得 INFINI Labs 周边纪念品,包括 T 恤、鸭舌帽、咖啡杯、指甲刀套件、精品围巾等等(图片仅供参考,款式、颜色与尺码随机)。

活动交流

本活动设有 Meetup 技术交流群,可添加小助手微信拉群,与更多小伙伴一起学习交流。

![](https://infinilabs.cn/img/company/INFINILabs-wechat.jpg)

Meetup 讲师招募

搜索客社区 Meetup 的成功举办,离不开社区小伙伴的热情参与。目前社区讲师招募计划也在持续进行中,我们诚挚邀请各位技术大咖、行业精英踊跃提交演讲议题,与大家分享您的经验。

讲师报名链接:http://cfp.searchkit.cn
或扫描下方二维码,立刻报名成为讲师!

![](https://infinilabs.cn/img/blog/banner/meetup/searchkit-lecturer-recruiting-qrcode.jpg)

Meetup 活动聚焦 AI 与搜索领域的最新动态,以及数据实时搜索分析、向量检索、技术实践与案例分析、日志分析、安全等领域的深度探讨。

我们热切期待您的精彩分享!

往期回顾

关于 搜索客(SearchKit)社区

搜索客社区由 Elasticsearch 中文社区进行全新的品牌升级,以新的 Slogan:“搜索人自己的社区” 为宣言。汇集搜索领域最新动态、精选干货文章、精华讨论、文档资料、翻译与版本发布等,为广大搜索领域从业者提供更为丰富便捷的学习和交流平台。

社区官网:https://searchkit.cn

【搜索客社区日报】第1998期 (2025-03-07)

社区日报Fred2000 发表了文章 • 0 个评论 • 2211 次浏览 • 2025-03-07 10:33 • 来自相关话题

1.基于 Qwen2.5-14B + Elasticsearch RAG 的大数据知识库智能问答系统 https://mp.weixin.qq.com/s/eS45qqzXs9WzXmWMurNwvQ 2.实测 Manus:首个真干活 AI,中国造(附50个用例 + 拆解) https://mp.weixin.qq.com/s/P47F8KE7SPRdUpODcnKKhQ 3.Manus工作原理揭秘:解构下一代AI Agent的多智能体架构 https://mp.weixin.qq.com/s/Hr5Ljp7BMsYA0CqU1YI1CA 4.INFINI Labs 产品更新 | Easysearch 增加异步搜索等新特性 https://infinilabs.cn/blog/2025/release-20250228/ 5.Easysearch 节点磁盘不足应对方法 https://infinilabs.cn/blog/202 ... odes/ 编辑:Fred 更多资讯:http://news.searchkit.cn

十亿级订单系统的数据库查询性能优化之路

默认分类京东云开发者 发表了文章 • 0 个评论 • 3617 次浏览 • 2024-12-11 16:43 • 来自相关话题

作者:京东零售 崔健

0.前言

  • 系统概要:BIP采购系统用于京东采销部门向供应商采购商品,并且提供了多种创建采购单的方式以及采购单审批、回告、下传回传等业务功能

  • 系统价值:向供应商采购商品增加库存,满足库存周转及客户订单的销售,供应链最重要的第一环节

1.背景

采购系统在经历了多年的迭代后,在数据库查询层面面临巨大的性能挑战。核心根因主要有以下几方面:

  • 复杂查询多,历史上通过MySQL和JED承载了过多的检索过滤条件,时至今日很难推动接口使用方改变调用方式

  • 数据量大,随着业务的持续发展,带来了海量的数据增长(日均150万单左右,订单主表/子表/渠道表/扩展表分别都是:6.5亿行,订单明细表/分配表:9.2亿行,日志表:60亿行)

  • 数据模型复杂,订单完整数据分布在20+张表,经常需要多表join

引入的主要问题有:

  • 业务层面:

    • 订单列表页查询/导出体验差,性能非常依赖输入条件,尤其是在面对订单数据倾斜的时候,部分用户无法查询/导出超过半个月以上的订单

    • 查询条件不合理,1.归档筛选条件,技术词汇透传到业务,导致相同周期的单子无法一键查询/导出,需要切换“是否归档”查询全部;2.无法区分“需要仓库收货”类的单子,大部分业务同事主要关注这类单子的履约情况
  • 技术层面:

    • 慢SQL多,各种多表关联复杂条件查询导致,索引、SQL已经优化道了瓶颈,经常出现数据库负载被拉高

    • 大表多,难在数据库上做DDL,可能会引起核心写库负载升高、主从延迟等问题

    • 模型复杂,开发、迭代成本高,查询索引字段散落在多个表中,导致查询性能下降

2.目标

业务层面:提升核心查询/导出体验,加强查询性能,优化不合理的查询条件

技术层面:1.减少慢SQL,降低数据库负载,提高系统稳定性;2.降低单表数据量级;3.简化数据模型

3.挑战

提升海量数据、复杂场景下的查询性能!

  • 采购订单系统 VS C端销售订单系统复杂度对比:
对比项 采购订单系统 C端订单销售系统
分库逻辑 使用采购单号分库 按用户pin分库分表
查询场景 面向采销、接口人、供应商、仓储运营提供包括采销员、单号、SKU、供应商、部门、配送中心、库房等多场景复杂查询 主要是按用户pin进行订单查询
单据所属人 采购单生成后,采销可以进行单据转移 订单生成后订单所属人不变
数据倾斜 单一采销或供应商存在大量采购单,并且自动补货会自动创建采购单 C端一个用户pin下订单数量有限

4.方案

思路

在这里插入图片描述

优化前

在这里插入图片描述



优化后

在这里插入图片描述

4.1 降低查询数据量

4.1.1 前期调研

基于历史数据、业务调研分析,采购订单只有8%的订单属于“需要实际送货至京东库房”的范围,也就是拥有完整订单履约流程、业务核心关注时效的。其余订单属于通过客户订单驱动,在采购系统的生命周期只有创建记录

在这里插入图片描述

基于以上结论,在与产品达成共识后,提出新的业务领域概念:“入库订单” ,在查询时单独异构这部分订单数据(前期也曾考虑过,直接从写入层面拆分入库订单,但是因为开发成本、改动范围被pass了)。异构这部分数据实际也参考了操作系统、中间件的核心优化思路,缓存访问频次高的热数据

4.1.2 入库订单异构

执行流程

在这里插入图片描述



  • “入库”订单数据打标

    • 增量订单在创建订单完成时写入;存量订单通过离线表推数

    • 需要订单创建模块先完成改造上线,再同步历史,保证数据不丢

    • 如果在【数据解析模块】处理binlog时无法及时从JimKV获取到订单标识,会补偿反查数据库并回写JimKV,提升其他表的binlog处理效率
  • binlog监听

    • 基于公司的【数据订阅】任务,通过消费JMQ实现。其中订阅任务基于订单号进行MQ数据分区,并且在消费端配置不允许消息重试,防止消息时序错乱

    • 其中,根据订单号进行各个表的MQ数据分区,第一版设计可能会引起热分区,导致消费速率变慢,基于这个问题识别到热分区主要是由于频繁更新订单明细数据导致(订单(1)->明细(N)),于是将明细相关表基于自身id进行分区,其他订单纬度表还是基于订单号。这样既不影响订单数据更新的先后顺序,也不会造成热分区、还可以保证明细数据的准确性
  • 数据同步

    • 增量数据同步可以采用源库的增量binlog进行解析即可,存量数据通过申请新库/表,进行DTS的存量+增量同步写入,完成binlog生产

    • 以上是在上线前的临时链路,上线后需要切换到源库同步binlog的增量订阅任务,此时依赖“位点回拨”+“数据可重入”。位点回拨基于订阅任务的binlog时间戳,数据可重入依赖上文提到的MQ消费有序以及SQL覆盖写
  • 数据校对

    • 以表为纬度,优先统计总数,再随机抽样明细进行比对

    • 目前入库订单量为稳定在5000万,全部实时订单量级6.5亿,降低92%

4.2 提升复杂查询能力

4.2.1 数据准备

  • 考虑到异构“入库”订单到JED,虽然数据查询时效性可以有一定保障,但是在复杂查询能力以及识别“非入库”订单还没有支持

  • 其中,“非入库”订单业务对于订单数据时效性要求并不高(1.订单创建源于客户订单;2.没有履约流程;3.无需手动操作订单关键节点)

  • 所以,考虑将这部分查询能力转移到ES上

ES数据异构过程

在这里插入图片描述



  • 首先,同步到ES的数据的由“实时+归档”订单组成,其中合计20亿订单,顺带优化了先前归档ES大索引(所有订单放在同一个索引)的问题,改成基于“月份”存储订单,之所以改成月份是因为根据条件查询分两种:1.一定会有查询时间范围(最多3个月);2.指定单号查询,这种会优先检索单号对应的订单创建时间,再路由到指定索引

  • 其次,简化了归档程序流程,历史方案是程序中直接写入【归档JED+归档ES】,现在优化成只写入JED,ES数据通过【数据解析模块】完成,简化归档程序的同时,提高了归档能力的时效性

  • 再次,因为ES是存储全量订单,需要支持复杂条件的查询,所以在订单没有物理删除的前提下,【数据解析模块】会过滤所有delete语句,保证全量订单数据的完整性

  • 接着,为了提升同步到ES数据的吞吐,在MQ消费端,主要做了两方面优化:1.会根据表和具体操作进行binlog的请求合并;2.降低对于ES内部refresh机制的依赖,将2分钟内更新到ES的数据缓存到JimKV,更新前从缓存中获取

  • 最后,上文提到,同步到入库JED,有的表是根据订单号,有的表是根据自身id。那么ES这里,因为NoSQL的设计,和线程并发的问题,为了防止数据错误,只能将所有表数据根据单号路由到相同的MQ分区

4.2.2 查询调度策略设计

优化前,所有的查询请求都会直接落到数据库进行查询,可以高效查询完全取决于用户的筛选条件是否可以精准缩小数据查询范围

优化后,新增动态路由层

  • 离线计算T-1的采销/供应商的订单数据倾斜,将数据倾斜情况推送到JimDB集群

  • 根据登陆用户、数据延迟要求、查询数据范围,自动调度查询的数据集群,实现高性能的查询请求

查询调度

在这里插入图片描述

5.ES主备机制&数据监控

1.主/备ES可以通过DUCC开关,实现动态切换,提升数据可靠性

2.结合公司的业务监控,完成订单数据延迟监控(数据同步模块写入时间-订单创建时间)

3.开启消息队列积压告警

5.1 ES集群主/备机制

1:1ES集群进行互备,应急预案快速切换,保证高可用

在这里插入图片描述

5.2 数据监控

在这里插入图片描述

6.灰度上线

  • 第一步,优先上线数据模块,耗费较多时间的原因:1.整体数据量级以及历史数据复杂度的问题;2.数据同步链路比较长,中间环节多

  • 第二步,预发环境验证,流量回放并没有做到长周期的完全自动化,根因:1.项目周期相对紧张;2.新老集群的数据还是有一些区别,回放脚本不够完善

  • 第三步,用户功能灰度,主要是借助JDOS的负载均衡策略结合用户erp完成

  • 第四部,对外接口灰度,通过控制新代码灰度容器个数,逐步放量

在这里插入图片描述

7.成果

平稳切换,无线上问题

指标 具体提升
采购列表查询(ms) 1、TP999:4817 优化到 2872,提升40.37% 2、超管、部门管理员由无法查询超过一周范围的订单,优化为可以在2秒内查询3个月的订单 3、页面删除“是否归档”查询条件,简化业务操作 4、页面新增“是否入库”查询条件,聚焦核心业务数据
仓储运营列表(ms) TP999:9009 优化到 6545,提升27.34%
采购统计查询(ms) TP999:13219 优化到 1546,提升88.3%
慢SQL指标(天纬度) 1、1s-2s慢SQL数:820->72,降低91% 2、2s-5s慢SQL数:276->26,降低90% 3、5s以上慢SQL数:343->6,降低98%

8.待办

  • 主动监控层面,新增按照天纬度进行数据比对、异常告警的能力,提高问题发现率

  • 优化数据模型,对历史无用订单表进行精简,降低开发、运维成本,提升需求迭代效率

  • 精简存储集群

    • 逐步下线其他非核心业务存储集群,减少外部依赖,提高系统容错度

    • 目前全量订单ES集群已经可以支持多场景的外部查询,未来考虑是否可以逐步下线入库订单JED
  • 识别数据库隐患,基于慢日志监控,重新梳理引入模块,逐步优化,持续降低数据库负载

  • MySQL减负,探索其他优化方案,减少数据量存储,提升数据灵活性。优先从业务层面出发,识别库里进行中的僵尸订单的根因,进行分类,强制结束

  • 降级方案,当数据同步或者数据库存在异常时,可以做到秒级无感切换,提升业务可用率

9.写在最后

  • 为什么没考虑Doris?因为ES是团队应用相对成熟的中间件,处于学习、开发成本考虑

  • 未来入库的JED相关表是否可以下掉,用ES完全替代?目前看可以,当初设计冗余入库JED也是出于对于ES不确定性以及数据延迟的角度考虑,而且历史的一部分查询就落在了异构的全量实时订单JED上。现在,JED官方也不是很推荐非route key的查询。最后,现阶段因为降低了数据量和拆分了业务场景,入库JED的查询性能还是非常不错的

  • 因为项目排期、个人能力的因素,在方案设计上会有考虑不周的场景,本期只是优化了最核心的业务、技术痛点,未来还有很大持续优化的空间。中间件的使用并不是可以优化数据库性能的银弹,最核心的还是要结合业务以及系统历史背景,在不断纠结当中寻找balance

极限科技(INFINI Labs)招聘:搜索运维工程师(Elasticsearch/Easysearch)【北京/全职】

求职招聘INFINI Labs 小助手 发表了文章 • 0 个评论 • 6484 次浏览 • 2024-09-28 11:00 • 来自相关话题

20240928-180457.png

我们是国内搜索型数据库产品厂商第一梯队的杰出代表,随着业务的快速发展,现开放岗位:搜索运维工程师( Elasticsearch/Easysearch ),如果有兴趣,请直接拉到文末,扫描二维码或将简历投递至 hello@infini.ltd。

如果您还不了解 极限科技(INFINI Labs)是谁,在做什么,需要什么样的小伙伴,那么请看下文:

我们是谁

INFINI Labs

极限科技,全称极限数据(北京)科技有限公司,是一家专注于实时搜索与数据分析的软件公司。旗下品牌极限实验室(INFINI Labs)致力于打造极致易用的数据探索与分析体验。

极限科技是一支年轻的团队,采用天然分布式的方式来进行远程协作,员工分布在全球各地,希望通过努力成为中国乃至全球企业大数据实时搜索分析产品的首选,为中国技术品牌输出添砖加瓦。

官网:https://infinilabs.cn

我们在做什么

极限科技(INFINI Labs)正在致力于以下几个核心方向:

1、开发近实时搜索引擎 INFINI Easysearch

INFINI Easysearch 是一个分布式的搜索型数据库,实现非结构化数据检索、全文检索、向量检索、地理位置信息查询、组合索引查询、多语种支持、聚合分析等。Easysearch 可以完美替代 Elasticsearch,同时添加和完善多项企业级功能。Easysearch 助您拥有简洁、高效、易用的搜索体验。详情参见:https://infinilabs.cn

2、打造下一代实时搜索引擎 INFINI Pizza

INFINI Pizza 是一个分布式混合搜索数据库系统。我们的使命是充分利用现代硬件和人工智能的潜力,为企业提供量身定制的实时智能搜索体验。我们致力于满足具有挑战性的环境中高并发和高吞吐量的需求,同时提供无缝高效的搜索功能。详情参见:https://pizza.rs

3、积极参与全球开源生态建设

通过开源项目和社区贡献,推动全球开源技术的发展,提升中国在全球开源领域的影响力。

4、提供专业服务

为客户提供包括搜索技术支持、迁移服务、定制解决方案和培训在内的全方位服务。

5、提供国产化搜索解决方案

针对中国市场的特殊需求,提供符合国产化标准的搜索产品和解决方案,帮助客户解决使用 Elasticsearch 时遇到的挑战。

极限科技(INFINI Labs)通过这些努力,旨在成为全球领先的实时搜索和数据分析解决方案提供商。

我们期待有才华、有激情的你加入我们,一起探索数据搜索的未来,共同创造无限可能!

在招岗位介绍

岗位名称

搜索运维工程师(Elasticsearch/Easysearch)

岗位职责

  1. 负责客户现场的 Elasticsearch/Easysearch/OpenSearch 搜索引擎集群的日常维护、监控和优化,确保集群的高可用性和性能稳定;
  2. 协助客户进行搜索引擎集群的部署、配置及版本升级;
  3. 排查和解决 Elasticsearch/Easysearch/OpenSearch 集群中的各种技术问题,及时响应并处理集群异常;
  4. 根据业务需求设计和实施搜索索引的调优、数据迁移和扩展方案;
  5. 负责与客户沟通,提供技术支持及相关培训,确保客户需求得到有效满足;
  6. 制定并实施搜索引擎的备份、恢复和安全策略,保障数据安全;
  7. 与内部研发团队和外部客户进行协作,推动集群性能改进和功能优化。

岗位要求

  1. 全日制本科及以上学历,5 年以上运维工作经验;
  2. 拥有 Elasticsearch/Easysearch/OpenSearch 使用经验,熟悉搜索引擎的原理、架构和相关生态工具(如 Logstash、Kibana 等);
  3. 熟悉 Linux 操作系统的使用及常见性能调优方法;
  4. 熟练掌握 Shell 或 Python 等至少一种脚本语言,能够编写自动化运维脚本;
  5. 具有优秀的问题分析与解决能力,能够快速应对突发情况;
  6. 具备良好的沟通能力和团队合作精神,能够接受 客户驻场工作;
  7. 全职,北京地区,需具备在北京长期工作的条件;

优先考虑

  • 计算机科学、信息技术或相关专业;
  • 具备丰富的大规模分布式系统运维经验;
  • 熟悉 Elasticsearch/Easysearch/OpenSearch 分片、路由、查询优化等高级功能;
  • 拥有 Elastic Certified Engineer 认证;
  • 具备大规模搜索引擎集群设计、扩展和调优经验;
  • 熟悉其他搜索引擎技术(如 Solr、Lucene)者优先 ;
  • 熟悉大数据处理相关技术(比如: Kafka 、Flink 等)者优先。

福利待遇

  • 月薪: 15K - 25K,具体根据能力而定,试用期为 3-6 个月;
  • 福利:五险一金/双休/国内法定假日/带薪年假等;

简历投递

简历投递:hello@infini.ltd(邮件标题请备注姓名+求职岗位+来自搜索客社区)
微信联系:INFINI-Labs(加微请备注求职岗位+来自搜索客社区)

欢迎有兴趣的小伙伴联系或推荐,期待您的加入!

联系我们

Elastic 宣布修改开源协议为 AGPL:Elasticsearch 再次成为开源软件

Elasticsearchsearchkit 发表了文章 • 0 个评论 • 7098 次浏览 • 2024-08-30 11:26 • 来自相关话题

今日快讯!就在刚刚,开源搜索领域行业巨头 Elastic 官方博客发表了一篇最新公告《Elasticsearch is Open Source, Again》,Elastic 创始人& CTO Shay Banon 宣布 Elasticsearch 和 Kibana 许可证协议修改为 AGPL。

original-elastic-logos.png

以下为搜索客社区从 Elastic 官方博客翻译的原文内容:


Elasticsearch 再次成为开源软件

[D.N.A] Elasticsearch 和 Kibana 现在可以再次被称为开源软件了。这句话让我感到无比的兴奋。真的忍不住跳起来庆祝!我们所有在 Elastic 的人都很高兴。开源精神是我的DNA,也是 Elastic 的DNA。能够再次称 Elasticsearch 为开源软件,真的是一种纯粹的快乐。

[LOVE.] 简而言之,我们将在接下来的几周内,除了 ELv2 和 SSPL 之外,增加 AGPL 作为另一个许可选项。在更改许可后,我们从未停止过像一个开源社区一样相信和行动。但通过使用 AGPL 这一获得开放源码促进会(OSI)批准的许可,消除了人们可能存在的任何疑问或混淆。

[Not Like Us] 我们在 Elastic 从未停止过对开源的信仰。我个人对开源的信仰也从未动摇,至今已有 25 年了。那么为什么三年前我们要做出改变呢?我们遇到了与 AWS 相关的问题,以及他们的服务引发的市场混乱。在尝试了所有能想到的其他选项后,我们更改了许可协议,明知道这会导致 Elasticsearch 被分叉成另一个名称并走上不同的发展轨迹。这是一个漫长的故事。

[Like That] 好消息是,虽然过程痛苦,但结果奏效了。三年后,亚马逊已经完全投入到了他们的分叉项目中,市场的混乱(大部分)得到了缓解,我们与 AWS 的合作伙伴关系比以往更强。我们甚至被评为 AWS 的年度合作伙伴。我一直希望时间能过去得足够久,以至于我们可以安全地回到开源项目的状态——现在终于到了。

[All The Stars] 我们希望尽可能简化用户的使用体验。我们有用户非常喜欢 ELv2(一个受 BSD 启发的许可)。我们也有用户已经批准使用 SSPL(通过 MongoDB 使用)。这就是为什么我们只是增加了一个选项,而不是移除任何东西。如果你已经在使用并喜欢 Elasticsearch,请继续使用,没有任何变化。对于其他人,现在你也可以选择使用 AGPL。

[LOYALTY.] 我们选择 AGPL 而不是其他许可,是因为我们希望通过与 OSI 的合作,能在开源许可领域创造更多的选项。随着我们更改许可以来的发展(例如 Grafana 从 Apache2 转移到 AGPL),也许 AGPL 已经足够适用于像我们这样的基础设施软件了。我们致力于找到最合适的解决方案。

[euphoria] 我非常高兴能够再次称 Elasticsearch 为开源软件。

[Alright] 任何改变都可能引发混淆,当然也可能引来一些网络喷子。(网络喷子总是存在的,对吧?)让我们愉快地回答一些可能出现的问题吧。我可以想象到的一些问题如下,但我们会继续补充。

“更改许可是个错误,Elastic 现在在回撤”:我们在三年前更改许可时消除了很多市场混乱。由于我们的行动,很多事情已经改变。现在是一个完全不同的市场环境。我们不生活在过去。我们希望为用户打造一个更好的未来。正是因为我们当时采取了行动,现在我们才有能力采取新的行动。

“AGPL 不是真正的开源许可,X 才是”:AGPL 是获得 OSI 批准的许可,并且被广泛采用。例如,MongoDB 曾经使用 AGPL,Grafana 现在也是 AGPL。这表明 AGPL 并不影响使用或流行度。我们选择 AGPL 是因为我们认为这是与 OSI 一起为世界开辟更多开源道路的最佳方式,而不是减少开源。

“Elastic 更改许可是因为他们表现不好”:我要说的是,我今天对 Elastic 的未来依然充满期待。我为我们的产品和团队的执行力感到无比自豪。我们发布了无状态的 Elasticsearch ES|QL 和大量用于 GenAI 用例的向量数据库/混合搜索改进。我们在日志记录和可观察性方面大力投入 OTel。我们的安全产品 SIEM 不断添加令人惊叹的功能,并且是市场上增长最快的产品之一。用户的反应让我们感到非常谦卑。股市总有起伏,但我可以向你保证,我们始终着眼于长远发展,而这次的变更就是其中的一部分。

如果我们看到更多问题,会在上面继续添加,以期减少混淆。

[HUMBLE.] 为未来而构建真是令人兴奋。Elasticsearch 回归开源。万岁!这真是一件美妙的事情。今天真是美好的一天。

Forever :elasticheart: Open Source

Shay 2024-08-30


原文地址:https://www.elastic.co/blog/elasticsearch-is-open-source-again/

社区热评

Elasticsearch 再次回归开源的消息迅速引发了技术社区的广泛关注。这不仅是 Elastic 对自身开源信念的重申,也是其在激烈市场竞争中精心策划的一次战略调整。

三年前,Elastic 因与 AWS 的市场竞争而选择更改许可协议,这一决定在当时引发了不小的争议。尽管如此,事实证明,这一策略有效地减少了市场上的混淆,也为 Elastic 与 AWS 的合作奠定了更坚实的基础。如今,Elastic 再度选择开源,并新增 AGPL 作为许可选项,这一举措无疑展现了 Elastic 在市场中更加成熟的定位和对未来发展的自信。

这一变化不仅仅是一个公司的商业决策,更是开源生态系统的一次重要信号。Elastic 的回归开源,传递出一个明确的信息:即使在商业竞争中,开源仍然是企业实现长远发展的重要路径。随着这一决定的落地,其他软件公司可能也会重新审视自身的许可策略,推动更多开源项目的发展与创新。

此外,Elastic 选择 AGPL 作为新许可选项,也显示出其对开源生态未来走向的深刻洞察。AGPL 的引入,表明 Elastic 希望在开源社区中保持灵活性和多样性,同时推动整个行业向更加开放和透明的方向迈进。

总体而言,Elastic 重返开源的举动,不仅意在巩固其在开源社区中的地位,也为行业树立了一个新的标杆。这一事件无疑将成为开源软件发展史上的重要篇章,未来可能会激发更多企业重新考虑其开源战略,进而推动整个技术行业的进一步繁荣与进步。

让我们拭目以待!

Elasticsearch 磁盘空间异常:一次成功的故障排除案例分享

ElasticsearchINFINI Labs 小助手 发表了文章 • 0 个评论 • 4698 次浏览 • 2024-08-09 00:18 • 来自相关话题

故障现象

近日有客户找到我们,说有个 ES 集群节点,磁盘利用率达到了 82% ,而其节点才 63% ,想处理下这个节点,降低节点的磁盘利用率。

起初以为是没有打开自动平衡导致的,经查询,数据还是比较平衡的。 利用率较高的是 76 节点,如果 76 节点的分片比其他节点多,好像还比较合乎逻辑,但它反而比其他节点少了 12-15 个分片。那是 76 节点上的分片比较大?

索引情况

图中都是较大的索引,1 个索引 25TB 左右,共 160 个分片。

分片大小

节点 64 节点 77 节点 75 问题节点 76 可以看出分片大小没有出现较大的倾斜,分片大小和数据平衡的原因都被排除。

换个方向思考,节点 76 比其他节点多使用了磁盘空间 8 个 TB 左右,集群最大分片大小约 140GB ,8000/140=57 ,即节点 76 至少要比其他节点多 57 个分片才行,啊这...

会不会有其他的文件占用了磁盘空间?

我们登录到节点主机,排查是否有其他文件占用了磁盘空间。

结果:客户的数据路径是单独的数据磁盘,并没有其他文件,都是 ES 集群索引占用的空间。

现象总结

分片大小差不多的情况下,节点 76 的分片数还比别的节点还少 10 个左右,它的磁盘空间反而多占用了 8TB 。

这是不是太奇怪了?事出反常必有妖,继续往下查。

原因定位

通过进一步排查,我们发现节点 76 上有一批索引目录,在其他的节点上没有,而且也不在 GET \_cat/indices?v 命令的结果中。说明这些目录都是 dangling 索引占用的。

dangling 索引产生的原因

当 Elasticsearch 节点脱机时,如果删除的索引数量超过 Cluster.indes.tombstones.size,就会发生这种情况。

解决方案

通过命令删除 dangling 索引:

DELETE /\_dangling/<index-uuid>?accept_data_loss=true

最后

这次的分享就到这里了,欢迎与我一起交流 ES 的各种问题和解决方案。

关于极限科技(INFINI Labs)

INFINI Labs

极限科技,全称极限数据(北京)科技有限公司,是一家专注于实时搜索与数据分析的软件公司。旗下品牌极限实验室(INFINI Labs)致力于打造极致易用的数据探索与分析体验。

极限科技是一支年轻的团队,采用天然分布式的方式来进行远程协作,员工分布在全球各地,希望通过努力成为中国乃至全球企业大数据实时搜索分析产品的首选,为中国技术品牌输出添砖加瓦。

官网:https://infinilabs.cn

【第2期】2024 搜索客 Meetup | Elasticsearch 的代码结构和写入查询流程的解读

活动searchkit 发表了文章 • 0 个评论 • 3647 次浏览 • 2024-08-06 11:47 • 来自相关话题

本次活动由 搜索客社区、极限科技(INFINI Labs)联合举办,活动主题将深入探讨 Elasticsearch 的两个核心方面:代码结构以及写入和查询的关键流程。本次活动将为 Elasticsearch 初学者和有经验的用户提供宝贵的见解,欢迎大家报名参加、交流学习。

活动主题:Elasticsearch 的代码结构和写入查询流程的解读
活动时间:2024 年 8 月 14 日 19:00-20:00(周三)
活动形式:微信视频号(极限实验室)直播
报名方式:关注或扫码海报中的二维码进行预约

嘉宾介绍

张磊,极限科技搜索引擎研发负责人,对 Elasticsearch 和 Lucene 源码比较熟悉,目前主要负责公司的 Easysearch 产品的研发以及客户服务工作。

主题摘要

本次分享将探讨 Elasticsearch 的代码结构及其写入和查询流程。内容包括:项目架构、核心模块、插件系统,以及文档索引和查询的各个阶段与分布式查询协调。

活动亮点

  1. 深入解析 Elasticsearch 代码结构

    • 项目的整体结构:了解 Elasticsearch 项目的组织方式。
    • 核心模块及其职责:学习 Elasticsearch 的核心模块及其在系统中的具体角色。
    • 插件系统的设计:探索 Elasticsearch 灵活的插件系统设计及其扩展方式。
  2. 详细解读 Elasticsearch 写入和查询流程

    • 文档索引过程的各个阶段:跟随文档从初始接收至最终存储的索引过程。
    • 查询解析和执行的步骤:理解 Elasticsearch 中查询解析和执行的各个步骤。
    • 分布式查询的协调过程:学习 Elasticsearch 如何在分布式架构中协调查询,以提供高效且准确的搜索结果。

参与有奖

直播中将设有福袋抽奖环节,参与就有机会获得 INFINI Labs 周边纪念品,包括 T 恤、鸭舌帽、咖啡杯、指甲刀套件等等(图片仅供参考,款式、颜色与尺码随机)。

活动交流

活动交流群二维码 7 天内(8 月 12 日前)有效,如过期请添加小助手微信拉群。

本次 Meetup 是深入了解 Elasticsearch 内部工作机制、提升使用技能的绝佳机会。不要错过!

Meetup 讲师招募

搜索客社区 Meetup 的成功举办,离不开社区小伙伴的热情参与。目前社区讲师招募计划也在持续进行中,我们诚挚邀请各位技术大咖、行业精英踊跃提交演讲议题,与大家分享您的经验。

讲师报名链接:http://cfp.searchkit.cn
或扫描下方二维码,立刻报名成为讲师!

Meetup 活动聚焦 AI 与搜索领域的最新动态,以及数据实时搜索分析、向量检索、技术实践与案例分析、日志分析、安全等领域的深度探讨。

我们热切期待您的精彩分享!

往期回顾

【第 1 期】2024 搜索客 Meetup | Easysearch 结合大模型实现 RAG

关于 搜索客(SearchKit)社区

搜索客社区由 Elasticsearch 中文社区进行全新的品牌升级,以新的 Slogan:“搜索人自己的社区” 为宣言。汇集搜索领域最新动态、精选干货文章、精华讨论、文档资料、翻译与版本发布等,为广大搜索领域从业者提供更为丰富便捷的学习和交流平台。社区官网:https://searchkit.cn

Easysearch、Elasticsearch、Amazon OpenSearch 快照兼容对比

EasysearchINFINI Labs 小助手 发表了文章 • 2 个评论 • 3577 次浏览 • 2024-07-29 11:54 • 来自相关话题

在当今的数据驱动时代,搜索引擎的快照功能在数据保护和灾难恢复中至关重要。本文将对 Easysearch、Elasticsearch 和 Amazon OpenSearch 的快照兼容性进行比较,分析它们在快照创建、恢复、存储格式和跨平台兼容性等方面的特点,帮助大家更好地理解这些搜索引擎的差异,从而选择最适合自己需求的解决方案。

启动集群

Easysearch

服务器一般情况下默认参数都是很低的,而 Easysearch/Elasticsearch 是内存大户,所以就需要进行系统调优。

sysctl -w vm.max_map_count=262144

vm.max_map_count 是一个 Linux 内核参数,用于控制单个进程可以拥有的最大内存映射区域(VMA,Virtual Memory Areas)的数量。内存映射区域是指通过内存映射文件或匿名内存映射创建的虚拟内存区域。

这个参数在一些应用程序中非常重要,尤其是那些需要大量内存映射的应用程序,比如 Elasticsearch。Elasticsearch 使用内存映射文件来索引和搜索数据,这可能需要大量的内存映射区域。如果 vm.max_map_count 设置得太低,Elasticsearch 可能无法正常工作,并会出现错误信息。

调整 vm.max_map_count 参数的一些常见原因:

  1. 支持大型数据集: 应用程序(如 Elasticsearch)在处理大型数据集时可能需要大量内存映射区域。增加 vm.max_map_count 可以确保这些应用程序有足够的内存映射区域来处理数据。

  2. 防止内存错误: 如果 vm.max_map_count 设置得太低,当应用程序尝试创建超过限制的内存映射时,会出现错误,导致应用程序崩溃或无法正常工作。

  3. 优化性能: 适当地设置 vm.max_map_count 可以优化应用程序的性能,确保内存映射操作顺利进行。

检查当前的 vm.max_map_count 值:

sysctl vm.max_map_count

或者查看 /proc/sys/vm/max_map_count 文件:

cat /proc/sys/vm/max_map_count

Elasticsearch 官方建议将 vm.max_map_count 设置为至少 262144。对于其他应用程序。

Easysearch 具体安装步骤见 INFINI Easysearch 尝鲜 Hands on

Amazon OpenSearch

使用 Amazon Web Services 控制台进行创建。

Elasticsearch

使用如下 docker compose 部署一个三节点的 ES 集群:

version: "2.2"
services:
  es01:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.10.2
    container_name: es01
    environment:
      - node.name=es01
      - cluster.name=es-docker-cluster
      - discovery.seed_hosts=es02,es03
      - cluster.initial_master_nodes=es01,es02,es03
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - data01:/usr/share/elasticsearch/data
    ports:
      - 9200:9200
    networks:
      - elastic
  es02:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.10.2
    container_name: es02
    environment:
      - node.name=es02
      - cluster.name=es-docker-cluster
      - discovery.seed_hosts=es01,es03
      - cluster.initial_master_nodes=es01,es02,es03
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - data02:/usr/share/elasticsearch/data
    networks:
      - elastic
  es03:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.10.2
    container_name: es03
    environment:
      - node.name=es03
      - cluster.name=es-docker-cluster
      - discovery.seed_hosts=es01,es02
      - cluster.initial_master_nodes=es01,es02,es03
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - data03:/usr/share/elasticsearch/data
    networks:
      - elastic

volumes:
  data01:
    driver: local
  data02:
    driver: local
  data03:
    driver: local

networks:
  elastic:
    driver: bridge

由于这个 docker compose 没有关于 kibana 的配置,所以我们还是用 Console 添加原生的 Elasticsearch 集群!

集群信息

快照还原的步骤

快照前的准备

插件安装

本次测试选择把索引快照备份到 Amazon S3,所以需要使用 S3 repository plugin,这个插件添加了对使用 Amazon S3 作为快照/恢复存储库的支持。

Easysearch 和 OpenSearch 集群自带了这个插件,所以无需额外安装。

对于自己部署的三节点 Elasticsearch 则需要进入每一个节点运行安装命令然后再重启集群,建议使用自动化运维工具来做这步,安装命令如下:

sudo bin/elasticsearch-plugin install repository-s3

如果不再需要这个插件,可以这样删除。

sudo bin/elasticsearch-plugin remove repository-s3

由于需要和 Amazon Web Services 打交道,所以我们需要设置 IAM 凭证,这个插件可以从 EC2 IAM instance profile,ECS task role 以及 EKS 的 Service account 读取相应的凭证。

对于托管的 Amazon OpenSearch 来说,我们无法在托管的 EC2 上绑定我们的凭证,所以需要新建一个 OpenSearchSnapshotRole,然后通过当前的用户把这个角色传递给服务,也就是我们说的 IAM:PassRole。

创建 OpenSearchSnapshotRole,策略如下:

{
  "Version": "2012-10-17",
  "Statement": [{
      "Action": [
        "s3:ListBucket"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::bucket-name"
      ]
    },
    {
      "Action": [
        "s3:GetObject",
        "s3:PutObject",
        "s3:DeleteObject"
      ],
      "Effect": "Allow",
      "Resource": [
        "arn:aws:s3:::bucket-name/*"
      ]
    }
  ]
}

信任关系如下:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Service": "es.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

然后在我们的 IAM user 上加上 PassRole 的权限,这样我们就可以把 OpenSearchSnapshotRole 传递给 OpenSearch 集群。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "iam:PassRole",
      "Resource": "arn:aws:iam::123456789012:role/OpenSearchSnapshotRole"
    }
  ]
}

注册存储库

在源集群执行注册

PUT /_snapshot/snapshot-repo-name
{
  "type": "s3",
  "settings": {
    "bucket": "<bucket-name>",
    "base_path": "<bucket-prefix>",

在目标集群同样执行这个语句,为了防止覆盖源集群存储库的数据,将 "readonly": true 添加到"settings" PUT 请求中,这样就只有一个集群具有对存储库的写入权限。

PUT /_snapshot/snapshot-repo-name
{
  "type": "s3",
  "settings": {
    "bucket": "<bucket-name>",
    "base_path": "<bucket-prefix>",
    "readonly": true,

对于 OpenSearch 来说,还需要执行 passrole,所以还需要添加role_arn这个字段,由于 IAM:PassRole 需要对 HTTP 请求做 signV4 日签名,所以这部常常使用 Postman 来完成。把角色传递过去之后,接下来的快照还原操作就可以在 OpenSearch Dashboard 中进行操作了。

需要注意的是,需要在 auth 这里输入 AccessKey,SecretKey,AWS Region,Service Name(es)来做 SignV4 的签名。

请求体如下:

{
  "type": "s3",
  "settings": {
    "bucket": "<bucket-name>",
    "base_path": "<bucket-prefix>",
    "readonly": true,
    "role_arn": "arn:aws:iam::123456789012:role/OpenSearchSnapshotRole"
  }
}
  • 查看所有注册的存储库
    • GET _snapshot:这个命令返回所有已注册的快照存储库列表及其基本信息。
GET _snapshot
{
  "es_repository": {
    "type": "s3",
    "settings": {
      "bucket": "your-s3-bucket-name",
      "region": "your-s3-bucket-region"
    }
  }
}
  • 查看特定存储库的详细信息GET _snapshot/es_repository:这个命令返回名为es_repository的存储库的详细配置信息,包括存储桶名称、区域和其他设置。
GET _snapshot/es_repository
{
  "es_repository": {
    "type": "s3",
    "settings": {
      "bucket": "your-s3-bucket-name",
      "region": "your-s3-bucket-region",
      "access_key": "your-access-key",
      "secret_key": "your-secret-key"
    }
  }
}
  • 查看特定存储库中的快照GET _cat/snapshots/es_repository?v:这个命令返回es_repository存储库中的所有快照及其详细信息,包括快照 ID、状态、开始时间、结束时间、持续时间、包含的索引数量、成功和失败的分片数量等。
GET _cat/snapshots/es_repository?v
id                     status start_epoch start_time end_epoch end_time duration indices successful_shards failed_shards total_shards
snapshot_1             SUCCESS 1628884800 08:00:00   1628888400 09:00:00 1h       3       10                0             10
snapshot_2             SUCCESS 1628971200 08:00:00   1628974800 09:00:00 1h       3       10                0             10

创建索引快照

# PUT _snapshot/my_repository/<my_snapshot_{now/d}>
PUT _snapshot/my_repository/my_snapshot
{
  "indices": "my-index,logs-my_app-default",
}

根据快照的大小不同,完成快照可能需要一些时间。默认情况下,create snapshot API 只会异步启动快照过程,该过程在后台运行。要更改为同步调用,可以将 wait_for_completion 查询参数设置为 true

PUT _snapshot/my_repository/my_snapshot?wait_for_completion=true

另外还可以使用 clone snapshot API 克隆现有的快照。要监控当前正在运行的快照,可以使用带有 _current 请求路径参数的 get snapshot API。

GET _snapshot/my_repository/_current

如果要获取参与当前运行快照的每个分片的完整详细信息,可以使用 get snapshot status API。

GET _snapshot/_status

成功创建快照之后,就可以在 S3 上看到备份的数据块文件,这个是正确的快照层级结构:

需要注意的是, "base_path": ""这里最好不要加/,虽然不影响同集群迁移,这个会为我们在不同厂商的搜索引擎中迁移遇到问题,可能是这样的,所以需要注意。

所以在 Open Search 中还原 Elasticsearch 就遇到了这个问题:

{
  "error": {
    "root_cause": [
      {
        "type": "snapshot_missing_exception",
        "reason": "[easy_repository:2/-jOQ0oucQDGF3hJMNz-vKQ] is missing"
      }
    ],
    "type": "snapshot_missing_exception",
    "reason": "[easy_repository:2/-jOQ0oucQDGF3hJMNz-vKQ] is missing",
    "caused_by": {
      "type": "no_such_file_exception",
      "reason": "Blob object [11111/indices/7fv2zAi4Rt203JfsczUrBg/meta-YGnzxZABRBxW-2vqcmci.dat] not found: The specified key does not exist. (Service: S3, Status Code: 404, Request ID: R71DDHX4XXM0434T, Extended Request ID: d9M/HWvPvMFdPhB6KX+wYCW3ZFqeFo9EoscWPkulOXWa+TnovAE5PlemtuVzKXjlC+rrgskXAus=)"
    }
  },
  "status": 404
}

恢复索引快照

POST _snapshot/my_repository/my_snapshot_2099.05.06/_restore
{
  "indices": "my-index,logs-my_app-default",
}

各个集群的还原

  1. Elasticsearch 7.10.2 的快照可以还原到 Easysearch 和 Amazon OpenSearch

  2. 从 Easysearch 1.8.2 还原到 Elasticsearch 7.10.2 报错如下:
{
  "error": {
    "root_cause": [
      {
        "type": "snapshot_restore_exception",
        "reason": "[s3_repository:1/a2qV4NYIReqvgW6BX_nxxw] cannot restore index [my_indexs] because it cannot be upgraded"
      }
    ],
    "type": "snapshot_restore_exception",
    "reason": "[s3_repository:1/a2qV4NYIReqvgW6BX_nxxw] cannot restore index [my_indexs] because it cannot be upgraded",
    "caused_by": {
      "type": "illegal_state_exception",
      "reason": "The index [[my_indexs/ALlTCIr0RJqtP06ouQmf0g]] was created with version [1.8.2] but the minimum compatible version is [6.0.0-beta1]. It should be re-indexed in Elasticsearch 6.x before upgrading to 7.10.2."
    }
  },
  "status": 500
}
  1. 从 Amazon OpenSearch 2.1.3 还原到 Elasticsearch 7.10.2 报错如下(无论是否开启兼容模式):
{
  "error": {
    "root_cause": [
      {
        "type": "snapshot_restore_exception",
        "reason": "[aos:2/D-oyYSscSdCbZFcmPZa_yg] the snapshot was created with Elasticsearch version [36.34.78-beta2] which is higher than the version of this node [7.10.2]"
      }
    ],
    "type": "snapshot_restore_exception",
    "reason": "[aos:2/D-oyYSscSdCbZFcmPZa_yg] the snapshot was created with Elasticsearch version [36.34.78-beta2] which is higher than the version of this node [7.10.2]"
  },
  "status": 500
}
  1. 从 Easysearch 1.8.2 还原到 Amazon OpenSearch2.13 报错如下(无论是否开启兼容模式):
{
  "error": {
    "root_cause": [
      {
        "type": "snapshot_restore_exception",
        "reason": "[easy_repository:2/LE18AWHlRJu9rpz9BJatUQ] cannot restore index [my_indexs] because it cannot be upgraded"
      }
    ],
    "type": "snapshot_restore_exception",
    "reason": "[easy_repository:2/LE18AWHlRJu9rpz9BJatUQ] cannot restore index [my_indexs] because it cannot be upgraded",
    "caused_by": {
      "type": "illegal_state_exception",
      "reason": "The index [[my_indexs/VHOo7yfDTRa48uhQvquFzQ]] was created with version [1.8.2] but the minimum compatible version is OpenSearch 1.0.0 (or Elasticsearch 7.0.0). It should be re-indexed in OpenSearch 1.x (or Elasticsearch 7.x) before upgrading to 2.13.0."
    }
  },
  "status": 500
}
  1. Amazon OpenSearch 还原到 Easysearch 同样失败
{
  "error": {
    "root_cause": [
      {
        "type": "snapshot_restore_exception",
        "reason": "[aoss:2/D-oyYSscSdCbZFcmPZa_yg] cannot restore index [aos] because it cannot be upgraded"
      }
    ],
    "type": "snapshot_restore_exception",
    "reason": "[aoss:2/D-oyYSscSdCbZFcmPZa_yg] cannot restore index [aos] because it cannot be upgraded",
    "caused_by": {
      "type": "illegal_state_exception",
      "reason": "The index [[aos/864WjTAXQCaxJ829V5ktaw]] was created with version [36.34.78-beta2] but the minimum compatible version is [6.0.0]. It should be re-indexed in Easysearch 6.x before upgrading to 1.8.2."
    }
  },
  "status": 500
}
  1. Elasticsearch 8.14.3 迁移到 Amazon OpenSearch 或者 Elasticsearch 都是有这个报错:
{
  "error": {
    "root_cause": [
      {
        "type": "parsing_exception",
        "reason": "Failed to parse object: unknown field [uuid] found",
        "line": 1,
        "col": 25
      }
    ],
    "type": "repository_exception",
    "reason": "[snap] Unexpected exception when loading repository data",
    "caused_by": {
      "type": "parsing_exception",
      "reason": "Failed to parse object: unknown field [uuid] found",
      "line": 1,
      "col": 25
    }
  },
  "status": 500
}

这是由于 Elasticsearch 8 在创建快照的时候会默认加上一个 UUID 的字段,所以我们低版本的 Easysearch、Amazon OpenSearch 中会找不到这个字段,在执行GET _cat/snapshots/snap?v的时候就报错,及时在注册存储库的时候显示加上 UUID 的字段也无事无补。

{
  "snapshot-repo-name": {
    "type": "s3",
    "uuid": "qlJ0uqErRmW6aww2Fyt4Fg",
    "settings": {
    "bucket": "<bucket-name>",
    "base_path": "<bucket-prefix>",
    }
  },

以下是兼容性对比,每行第一列代表源集群,第一行代表目标集群:

快照兼容对比 Easysearch 1.8.2 Elasticsearch 7.10.2 OpenSearch 2.13
Easysearch 1.8.2 兼容 不兼容 不兼容
Elasticsearch 7.10.2 兼容 兼容 兼容
OpenSearch 2.13 不兼容 不兼容 兼容

Elasticsearch 的兼容列表官方的列表如下:

参考文献

  1. 开始使用 Elastic Stack 和 Docker Compose:第 1 部分
    https://www.elastic.co/cn/blog/getting-started-with-the-elastic-stack-and-docker-compose

  2. Docker Compose 部署多节点 Elasticsearch
    https://www.elastic.co/guide/en/elasticsearch/reference/7.10/docker.html#docker-compose-file

  3. repository-s3 教程
    https://www.elastic.co/guide/en/elasticsearch/reference/8.14/repository-s3.html
    https://www.elastic.co/guide/en/elasticsearch/plugins/7.10/repository-s3.html

  4. snapshot-restore
    https://www.elastic.co/guide/en/elasticsearch/reference/7.10/snapshot-restore.html

  5. 在亚马逊 OpenSearch 服务中创建索引快照
    https://docs.amazonaws.cn/zh_cn/opensearch-service/latest/developerguide/managedomains-snapshots.html#managedomains-snapshot-restore

  6. 教程:迁移至 Amazon OpenSearch Service
    https://docs.amazonaws.cn/zh_cn/opensearch-service/latest/developerguide/migration.html

关于 Easysearch 有奖征文活动

黑神话悟空

无论你是 Easysearch 的老用户,还是第一次听说这个名字,只要你对 INFINI Labs 旗下的 Easysearch 产品感兴趣,或者是希望了解 Easysearch,都可以参加这次活动。

详情查看:Easysearch 征文活动

作者:韩旭,亚马逊云技术支持,亚马逊云科技技领云博主,目前专注于云计算开发和大数据领域。

原文:https://infinilabs.cn/blog/2024/comparison-of-snapshot-compatibility-between-easysearch-elasticsearch-and-opensearch/

从 OpenAI 停服看中国市场:国产替代崛起的机遇与挑战

EasysearchINFINI Labs 小助手 发表了文章 • 0 个评论 • 3611 次浏览 • 2024-07-05 11:50 • 来自相关话题

INFINI Easysearch

一、OpenAI 停服事件背景

OpenAI 自 2020 年推出 GPT-3 以来,在全球范围内引起了极大的反响。其强大的自然语言处理能力使其成为许多企业和开发者的首选工具。然而,2024 年 6 月 25 日,许多中国用户收到了一封来自 OpenAI 的邮件,邮件中明确表示,自 2024 年 7 月 9 日起,OpenAI 将停止对中国内地和香港地区提供 API 服务。

INFINI Easysearch

这一事件引发了国内开发者和企业的广泛讨论,特别是在人工智能技术应用逐渐深入的背景下,OpenAI 的停服无疑会对中国市场产生一定的影响。在 AI 技术迅猛发展的当下,许多中国企业和开发者依赖 OpenAI 的 API 进行各种应用的开发。尤其是在大模型技术领域,不少初创公司通过“套壳”OpenAI 技术快速推向市场。所谓“OpenAI 套壳”,是指一些公司仅对 OpenAI 的技术进行表面包装和小改动,而未进行深度创新 。OpenAI CEO 山姆·奥特曼曾明确指出,简单包装 OpenAI 技术的公司难以长久生存。此次 API 服务的终止,意味着这些企业需要寻找新的技术支持,或者在短时间内加速自主研发 。

二、国产替代的挑战与机遇

OpenAI 停止对中国提供 API 服务将对国内 AI 行业带来短期冲击,但从长远来看,这也可能成为推动国内 AI 技术自主创新和研发的契机。国内企业将被迫加大自主研发力度,减少对外部技术的依赖,从而推动国产 AI 技术的发展 。虽然目前国内大模型企业在技术上与 OpenAI 存在一定差距,但已有不少公司在不断赶超。例如,百度的文心大模型、科大讯飞的星火大模型以及清华智谱的 ChatGLM 基础模型,都在性能上逐渐逼近甚至超过了 GPT-4 。从现状来看,国内大模型厂商已经逐步进入了性能提升的关键期,应用场景从办公、生活拓展到医疗、工业、教育等领域。

三、Elasticsearch 国产化替代的需求

INFINI Easysearch

Elasticsearch(简称 ES)作为一种开源的分布式搜索和分析引擎,以其强大的搜索能力和高效的数据处理能力,广泛应用于各种大数据和搜索相关业务场景。然而,随着国际政治环境的变化和技术壁垒的加剧,依赖国外技术的风险日益凸显。在这种背景下,推动 Elasticsearch 的国产化替代至关重要,既能保障国家信息安全,也能促进国内技术自主创新和产业发展。

首先,依赖国外技术可能带来技术封锁风险,一旦国外企业因政治或经济原因停止服务,中国企业的业务连续性和数据安全性将受到威胁。推动国产化替代有助于规避这些风险,保障数据安全和业务的稳定运行。国外搜索引擎和数据库系统通常为西方市场优化,未必适合中国市场。例如,Elasticsearch 在处理中文信息时需要额外的插件和调整,而国产替代方案可以更好地适应本地化需求,同时确保数据存储和处理符合国家法律法规。

其次,推动 Elasticsearch 的国产化替代有助于激发国内企业的创新活力,减少对国外技术的依赖,提升在搜索和大数据领域的核心竞争力。采用国产替代方案不仅能够降低企业的技术成本,还能构建自主的技术生态系统,减少对外部的依赖。与此同时国产化替代也有助于提升国内技术人才水平,通过自主研发和技术创新培养出高水平的技术人才,推动技术创新和产业升级。

在性能和安全方面,Elasticsearch 在数据保护和性能方面存在不足。开源版本不具备数据保护功能,用户必须付费获得相关的安全功能。2021 年 Elastic 公司将其开源软件许可证变更为双授权许可,可能带来安全风险。此外,Elasticsearch 在数据读写性能和集群扩展上也存在技术挑战,进一步推动了国产替代的需求。

四、Easysearch:国产替代的优秀范例

INFINI Easysearch

在 OpenAI 退出中国市场的背景下,国产技术的重要性日益凸显。作为国产搜索引擎技术的代表,Easysearch 展示了强大的替代潜力。

Easysearch 是一款基于国内自主研发的高性能搜索引擎,其核心引擎基于开源的 Apache Lucene。与 Elasticsearch 相比,Easysearch 不仅提供了相当的功能,还进行了更具针对性的优化。

  • 轻量级:Easysearch 的安装包小于 50MB,部署安装简单,适合企业快速上手。

  • 跨平台支持:Easysearch 支持主流操作系统和 CPU 架构,兼容国产信创环境,确保多样化环境下的稳定运行。

  • 高性能:Easysearch 针对不同的使用场景进行了优化,以更低的硬件成本提供更高的服务性能,从而实现降本增效。

  • 安全增强:Easysearch 默认提供完整的企业级安全功能,支持 LDAP/AD 集成,能够对索引、文档和字段级别进行粒度化权限管控,确保数据的安全性和隐私性。

  • 稳定可靠:Easysearch 修复了大量内核问题,解决了内存泄露、集群卡顿和查询缓慢等问题,经过严苛的业务环境考验,保证了其稳定性和可靠性。

  • 简单易用:Easysearch 提供了企业级管理后台,运营标准化和自动化,使用户能够通过简单的页面操作实现专家级的运维管理工作。

Easysearch 特别注重数据安全和隐私保护,所有数据都在国内处理和存储,符合数据主权要求。这对关注数据安全和隐私的企业尤为重要,能够有效保障数据的安全性和合规性。

Easysearch 致力于构建一个开放的技术生态,通过丰富的开发者资源和支持,为国内开发者提供了一个强大的技术平台。

  • 兼容性:Easysearch 兼容 Elasticsearch 的语法,支持 Elasticsearch 原有的 Query DSL 和 SQL 语法,并且兼容现有的 Elasticsearch SDK。这样,企业和开发者可以平滑地迁移到 Easysearch,无需修改现有代码。

  • 中文适配:Easysearch 在功能上进行了中文适配,能够更好地支持中文搜索和分析,满足本地化需求。

  • 功能增强:Easysearch 不断完善和增强企业级功能,使其在搜索业务场景中保持简洁与易用性,同时提升功能的丰富度和深度。

  • 信创适配:Easysearch 支持信创环境,确保在国产环境中也能平稳运行和使用。

  • 平滑迁移:Easysearch 基于网关实现了无缝的跨版本迁移与升级,用户可以随时安全回退,确保系统的持续稳定性。

Easysearch 作为国产搜索引擎技术的代表,展示了国产替代的强大潜力。通过自主研发和技术创新,Easysearch 不仅提供了强大的功能和性能,还确保了数据安全和隐私保护。它为国内企业和开发者提供了一个可靠的技术平台,推动了国产技术的发展和应用。未来,随着更多国产技术的崛起,中国将在全球技术领域占据更加重要的地位。

五、结束语

随着 OpenAI 服务在国内的终止,中国 AI 市场迎来了自主创新的机遇。国内企业如百度、科大讯飞等正加速自主研发,缩小技术差距。同时,在搜索引擎领域,极限科技推出 Easysearch 搜索引擎为 Elasticsearch 国产替代提供了新的选择。展望未来,国产技术的持续创新将助力中国在全球技术领域占据更重要的地位。

关于极限科技(INFINI Labs)

INFINI Labs

极限科技,全称极限数据(北京)科技有限公司,是一家专注于实时搜索与数据分析的软件公司。旗下品牌极限实验室(INFINI Labs)致力于打造极致易用的数据探索与分析体验。

极限科技是一支年轻的团队,采用天然分布式的方式来进行远程协作,员工分布在全球各地,希望通过努力成为中国乃至全球企业大数据实时搜索分析产品的首选,为中国技术品牌输出添砖加瓦。

官网:https://www.infinilabs.cn

联系我们

作者:Muses

原文:https://infinilabs.cn/blog/2024/from-openai-service-discontinuation-to-the-chinese-market-opportunities-and-challenges-of-domestic-replacement-rising/

【搜索客社区日报】第1853期 (2024-07-05)

社区日报Fred2000 发表了文章 • 0 个评论 • 2627 次浏览 • 2024-07-05 09:26 • 来自相关话题

Gitee 两大指标超越 GitHub,携手中国开源共绘新篇章 https://mp.weixin.qq.com/s/J92AOb9HGQDb4FqqJUPGhQ 前沿重器[51] | 聊聊搜索系统4:query理解 https://mp.weixin.qq.com/s/R4njGbiz_yT0wqN4by0uDg Elasticsearch 是什么?工作原理是怎么样的? https://mp.weixin.qq.com/s/UXzFg6LbHCifeObiLsXAMA INFINI Easysearch 尝鲜 Hands on https://mp.weixin.qq.com/s/OLdD3KkgXK5Q4e2RDzMD8Q 编辑:Fred  更多资讯:http://news.searchkit.cn
Gitee 两大指标超越 GitHub,携手中国开源共绘新篇章 https://mp.weixin.qq.com/s/J92AOb9HGQDb4FqqJUPGhQ 前沿重器[51] | 聊聊搜索系统4:query理解 https://mp.weixin.qq.com/s/R4njGbiz_yT0wqN4by0uDg Elasticsearch 是什么?工作原理是怎么样的? https://mp.weixin.qq.com/s/UXzFg6LbHCifeObiLsXAMA INFINI Easysearch 尝鲜 Hands on https://mp.weixin.qq.com/s/OLdD3KkgXK5Q4e2RDzMD8Q 编辑:Fred  更多资讯:http://news.searchkit.cn

搜索型数据库的技术发展历程与趋势前瞻

资讯动态INFINI Labs 小助手 发表了文章 • 0 个评论 • 3765 次浏览 • 2024-06-26 13:13 • 来自相关话题

概述

随着数字科技的飞速发展和信息量的爆炸性增长,搜索引擎已成为我们获取信息的首选途径之一,典型的代表厂商如 Google。然而,随着用户需求的不断演变,传统的搜索技术已经无法满足人们对信息的实时性、个性化和多样性的需求。

在企业内部,这种需求更加显著。随着企业数字化转型的持续深化,非结构化数据正日益成为各类组织数据增长的主要来源,也是数据体系中至关重要的组成部分,蕴含着巨大的价值。如何高效地存储和利用非结构化数据的重要性也日益凸显。企业需要更高效地管理和检索内部的海量数据,以支持业务决策和运营需求。

据 IDC 数据预计,到 2025 年,80%的数据将是非结构化数据;而根据 Gartner 的数据显示,从 2019 年到 2024 年,非结构化数据容量预计将增加两倍。然而,目前非结构化数据面临着表现形式多样、管理复杂性高、价值挖掘难度大等诸多挑战。传统的数据库系统往往无法满足企业对实时性和多样性的搜索需求,为了解决这些挑战,以自动分词、倒排索引、相关度计算、向量检索引擎等技术为核心构建的搜索型数据库应运而生。这些数据库自上世纪 90 年代诞生以来不断发展演进,正在成为数据库领域中不可或缺的一个重要分支。

什么是搜索型数据库?

搜索型数据库早期又称全文数据库,或者企业搜索引擎,是一种专门用于存储和管理大规模文本数据,并支持高效的文本搜索和信息检索的数据库系统,不过随着技术不断发展和应用场景日益丰富,目前搜索型数据库不仅仅可以处理长文本数据,也可以处理常见的数值、日期等结构化数据,IP、地理位置信息、图片、音视频等非结构化数据,搜索型数据库的应用范畴不断拓展,正在由支撑业务系统检索加速、IT 运维可观测性、聚合查询分析等向多场景、多模态数据搜索方向发展。

典型的搜索数据库一般具有以下特点:

  1. 灵活的索引能力:搜索数据库能够处理多种类型的数据,包括文本、图像、音频、视频等非结构化数据。它们采用自动分词、倒排索引等技术,能够高效地处理不同格式和类型的数据,提供灵活的搜索和检索功能。
  2. 高效的查询性能:搜索数据库具有高效的查询处理能力,能够快速索引和检索大规模的数据。借助优化的索引结构和查询算法,搜索数据库能够在短时间内准确地返回与查询相关的结果,提高用户的搜索效率,常用于解决关系型数据库的高并发检索需求。
  3. 支持复杂的搜索功能:搜索数据库提供多样化的搜索功能,包括全文检索、模糊搜索、精确搜索、范围搜索、向量搜索、地理信息检索等。用户可以根据不同的需求和场景,灵活地选择和组合不同的搜索功能,以获取符合期望的搜索结果。
  4. 高性能和可扩展性:搜索数据库具有高性能和可扩展性的特点,能够处理大规模数据和高并发访问。它们采用分布式架构和并行计算技术,实现了水平扩展,能够满足不断增长的数据量和用户访问量的需求。

综上所述,搜索数据库具有处理非结构化数据、实时搜索和更新、多样化的搜索功能、个性化推荐和智能搜索、高性能和可扩展性、全面的搜索结果展示等特点,是处理大规模数据和提供高效搜索服务的重要工具。

搜索型数据库的应用场景

搜索型数据库在各行各业都有广泛的应用,以下是一些典型的应用场景:

  1. 零售和电商:在零售和电商行业,搜索型数据库被广泛应用于产品搜索和推荐系统中。通过搜索功能,顾客可以轻松查找所需商品,而个性化推荐系统则可以根据用户的搜索历史和行为习惯推荐相关的产品,提高购物体验和交易转化率。
  2. 医疗保健:在医疗保健行业,搜索型数据库被用于医学文献检索、疾病诊断和药物搜索等方面。医生和研究人员可以利用搜索功能找到相关的医学文献和研究成果,帮助诊断疾病和制定治疗方案。
  3. 金融服务:在金融服务行业,搜索型数据库被用于金融数据检索、市场分析和投资决策等方面。投资者可以通过搜索功能查找相关的金融数据和市场资讯,帮助他们做出更加准确的投资决策。
  4. 制造业:在制造业中,搜索型数据库被用于生产过程监控、质量控制和故障诊断等方面。工程师可以利用搜索功能查找相关的生产数据和技术资料,帮助他们解决生产中的问题和挑战。
  5. 媒体和娱乐:在媒体和娱乐行业,搜索型数据库被用于内容检索、版权管理和用户推荐等方面。用户可以通过搜索功能查找感兴趣的新闻、音乐和视频等内容,而个性化推荐系统则可以根据用户的搜索历史和偏好推荐相关的内容。
  6. 教育和培训:在教育和培训行业,搜索型数据库被用于学习资源检索、课程管理和学习分析等方面。学生和教师可以利用搜索功能查找相关的学习资源和课程内容,而学习分析系统则可以分析学生的搜索行为和学习表现,为教学提供参考和支持。
  7. IT 运维可观测性:通过搜索型数据库,可以实时监控系统的运行状况、性能指标和日志数据,帮助运维团队及时发现和解决系统故障、性能问题和异常情况,确保系统的稳定运行。
  8. 安全监测和威胁检测:利用搜索型数据库对系统的安全日志进行审计和监控,监测用户的访问行为和系统操作,及时发现异常行为和安全事件。同时,搜索型数据库还可以与威胁情报数据集成,对内部日志数据进行关联分析,快速识别并应对各种安全威胁和攻击行为,保障系统和数据的安全。

综上所述,搜索型数据库在各行各业都发挥着重要作用,数据规模从 GB 到 PB 不等,体现在生活中的方方面面,为用户提供了高效、准确和个性化的信息搜索和检索服务,推动了各行业的发展和进步。随着搜索技术的不断创新和发展,搜索型数据库在各行业中的应用将会越来越广泛,并持续为用户带来更加便捷和智能的搜索体验。

搜索型数据库的发展历程

搜索型数据库的发展历程可以概括如下四个阶段:

  1. 起步阶段(1990 年代):搜索数据库的雏形开始于上世纪 90 年代,当时以全文检索为主要技术手段,最初用于文档检索和网络搜索。典型代表包括 AltaVista、Excite 等。
  2. 技术突破(2000 年代):随着互联网的快速发展,搜索数据库开始应用于更多领域,如电子商务、社交网络等。Lucene、Sphinx 等开源搜索引擎的出现推动了搜索技术的进步。
  3. 商业化发展(2010 年代):搜索数据库进入商业化阶段,以 Elasticsearch 等为代表的商业搜索引擎崭露头角。企业开始大规模应用搜索数据库来管理和检索大量数据。
  4. 智能化转型(2020 年代):随着人工智能技术的发展,搜索数据库逐渐向智能化转型,开始引入机器学习、自然语言处理等技术,提供个性化推荐和智能搜索服务。同时,搜索数据库也在更多领域得到应用,如医疗保健、金融服务等。

    综上所述,搜索数据库经历了从起步阶段到技术突破、商业化发展再到智能化转型的发展历程,表明了其在信息检索领域的重要性和不断演进的趋势,不并断推动着搜索技术的进步和应用范围的扩展。随着人工智能技术的不断成熟,搜索数据库将会在智能化、个性化等方面取得更大的进步,为用户提供更加优质的搜索体验。

搜索型数据库的发展情况

搜索型数据库市场上已经有不少成熟的产品和厂商,但是总的来说,搜索型数据库的界限范围有点模糊,当然其他数据库也有同样的问题,有很多数据库既是文档数据库,又是多模态数据库,还是向量数据库等等,而常见的搜索型数据库主要诞生于:

  • 由搜索引擎内核库发展而来的搜索数据库,如 Elasticsearch
  • 由其他数据库扩展而来的搜索数据库,如 Postgres Full-Text Search
  • 从零开始整体设计的搜索数据库:如 INFINI Pizza

通过流行的 DB-Engines 的搜索引擎排行榜,可以初探国外主流的搜索型数据库的流行趋势,如下图:

可以看到 Elastic 公司的 Elasticsearch 还是依旧保持强悍,自从 Elasticsearch 十多年前掀翻了 Splunk 的桌子,硬生生的在日志领域杀出一条新路,随后大杀四方,碾压整个搜索行业,霸榜至今。Elastic 商业化增长稳健,2023 年收入超过 10 亿美金。

OpenSearch 是由 AWS 发起的 Elasticsearch 开源分支,起因是由于 Elastic 针对云厂商采取的协议变更为 Elastic+SSPL,OpenSearch 基于 Apache 2.0 协议的 Elasticsearch 7.10 版本衍生而来,目前也具备了一定的用户基础。

Splunk 是一款用于搜索、监控和分析大规模机器生成的数据的软件平台,主要用于日志和安全分析领域,属于商业闭源产品。2023 年中被思科(Cisco) 以 230 亿美元现金收购,瞬间刷爆朋友圈。另外有意思的是,前四名除了 Splunk,底层都是 Lucene 内核。

MarkLogic 成立于 2001 年,自我定位是一个 NoSQL 多模态数据库厂商,也是商业闭源软件,生态成熟但是系统过于复杂,学习曲线较陡, 2023 年初被 Progress Software 以 3.55 亿美元收购算是一个比较好的结局。

当然了,除了榜上的这些产品,还有很多优秀的挑战者正摩拳擦掌,跃跃欲试。如下面的这些项目: vespa、Rockset、Doris,Clickhouse、quickwit、Pinot、SingleStore、qdrant、milvus、algolia、meilisearch、typesense、Manticore Search 等等。这些项目不一定都是自己定位是搜索型数据库,有侧重在 AI 领域的,有侧重在实时分析领域的等等,可谓各有千秋,不过都具备一定的搜索和分析能力,不出意外,基本上每家都要号称吊打 Elasticsearch 一番。

国内搜索型数据库的发展情况

搜索型数据库已经成为企业事实上的重要基础设施,而国内搜索型数据库的发展近些年也是开始得到重视,2023 年初,由中国信通院云计算与大数据研究所牵头,依托中国通信标准化协会大数据技术标准推进委员会,联合拓尔思、极限科技、星环科技等 30 余家企业编制的《搜索型数据库技术要求》正式出炉,该标准已成为行业内搜索型数据库技术选型和产品开发的风向标,极限科技的 INFINI Easysearch 率先通过了该标准

墨天轮社区也开辟了搜索型数据库的排行榜,共有 6 家企业的产品上榜:

国内搜索型数据库的市场还在起步阶段,厂商和可选的产品也还比较少,不过随着市场的成熟,相信未来将迎来一波高速的发展。

搜索型数据库的趋势前瞻

技术在演变,场景在演变,数据也在演变,搜索数据库领域的发展也呈现出多个显著的趋势,这些趋势将进一步推动搜索技术的演进和应用范围的扩展。笔者观测到的主要的发展趋势包括以下方向供参考:

1. 趋势一:实时搜索与分析

  • 实时搜索是搜索数据库领域的一个重要发展趋势,业务应用都在朝实时方向演进,用户对信息的即时性需求不断增加,要求搜索结果能够及时反映最新的数据和内容。

  • 实时搜索技术通过实时索引和实时更新机制,能够实现快速的数据检索和更新,提供与时俱进的搜索结果,满足用户对信息的即时性需求。

  • 目前以 Lucene 为内核的搜索型数据库基本上都只能做到 NRT(近实时)搜索,并且频繁更新带来的挑战和资源的浪费比较高,如果能做到更高效的实时性,可以大大提升用户的搜索体验和实时决策能力。

2. 趋势二:多模态混合搜索

  • 多模态搜索是指在搜索过程中同时考虑多种信息形式,如文本、图像、视频等,以提高搜索结果的准确性和全面性。

  • 这种技术能够通过分析和理解多种信息形式之间的关联性,为用户提供更加全面、丰富的搜索结果,适用于需要综合不同媒体形式的搜索场景。

  • 现实世界的数据越来越复杂化,非结构化数据的利用的场景也越来越多,多模态可以为业务提供更加灵活的分析和探索能力,混合搜索的能力非常具有吸引力。

3. 趋势三:AI 智能语义搜索

  • 大模型、AI 智能搜索技术的探索可谓是一日千里,通过利用人工智能技术来实现搜索过程中的智能化、语义化和个性化,结合自然语言处理、机器学习等技术分析用户意图,提供更加智能、个性化的搜索服务。

  • 随着大模型的兴起,搜索数据库开始采用像 RAG(Retriever-Reader for Generative Question Answering)这样的大型预训练模型来提升搜索的效果。RAG 模型结合了检索器和阅读器的功能,能够实现更加准确和全面的搜索结果,为用户提供更加智能和个性化的搜索服务。

  • 搜索型数据库可谓是 AI 落地最好的是试验田,Elasticsearch 通过拥抱 AI 和大模型,目前股价又重回巅峰,可喜可贺。

4. 趋势四:云原生、存算分离、Serverless

  • 随着云计算技术的发展,搜索数据库正逐渐向云原生架构转变。云原生搜索数据库利用容器化、微服务架构等技术,实现了更高的灵活性、可扩展性和容错性,为企业提供了更加稳定和高效的搜索服务,并且成本更低,更加弹性。

  • 存算分离是搜索数据库发展的另一重要趋势。通过将存储与计算分离,搜索数据库可以更好地适应数据存储和计算需求的变化,提高系统的性能和效率。存算分离技术使得搜索数据库能够实现更高的并发访问和更快的数据处理速度,为用户提供更加流畅和稳定的搜索体验。

  • Serverless 提供开箱即用的体验,成本更低,使用更加灵活,也是目前很多搜索服务提供商正在积极探索的方向。

5. 趋势五:增强现实搜索

  • 随着增强现实技术的发展,尤其是 Apple 发布的头戴式 Vision Pro,一部革命性的空间运算设备,将数位内容无缝融入实体世界,而搜索技术也将逐渐与增强现实相结合,为用户提供更加直观和沉浸式的搜索体验。增强现实搜索能够将搜索结果与现实世界相结合,结合 AI 技术为用户提供更加个性化和便捷的搜索服务,这是一个全新的领域,也意味着巨大的机会。

6. 趋势六:现代硬件的高效利用

  • 现代硬件及软件运行环境已发生翻天覆地的变化, 片上计算,边缘计算,FPGA,DPU,GPU,一台设备几百核上 TB 内存已经成为现实,可运行之上的软件却还是停留在几十年前的架构。 如 Elasticsearch 其核心 Lucene(及类似实现) 是在 1997 建立的,距今已有 27 年了,虽然也在与时俱进,但是部分架构和设计理念已不具备先进性。

  • 在现代的硬件上采用更先进的算法,更新的数据结构、更新的设计理论,利用最新的 CPU 指令集,向量化,批处理,充分发挥多核、大内存和 SSD 的优势,从而达到更高的效率,更低的成本,去解决之前不可能实现的问题,大有可为,也是下一代引擎需要关注的方向。

随着各类数据库功能的边界越来越模糊,应用场景高度交叉重叠,市场竞争也变得白热化,不过笔者认为垂直领域的搜索型数据库机会还是很大,而想做大而全的数据库产品已经没有太多的市场生存空间,一定要在垂直领域有特别专注的地方,我们 INFINI Labs 正在基于 Rust 研发的下一代搜索引擎 INFINI Pizza,就侧重于面向终端用户场景,解决海量数据更新情况下,同时满足高并发和低延迟的核心业务实时检索需求。

总结

综上所述,搜索数据库领域正处于快速发展的阶段。随着互联网数据量的不断增长和用户需求的不断变化,搜索数据库技术将不断创新和进步,以满足用户对信息获取的更加即时、个性化和多样化的需求。未来,随着人工智能技术的进一步发展和应用,搜索数据库将会变得更加智能化、普及化和多样化,为用户提供更加高效、准确和个性化的搜索服务,推动互联网信息的更加便捷获取和利用。

关于极限科技(INFINI Labs)

INFINI Labs

极限科技,全称极限数据(北京)科技有限公司,是一家专注于实时搜索与数据分析的软件公司。旗下品牌极限实验室(INFINI Labs)致力于打造极致易用的数据探索与分析体验。

极限科技是一支年轻的团队,采用天然分布式的方式来进行远程协作,员工分布在全球各地,希望通过努力成为中国乃至全球企业大数据实时搜索分析产品的首选,为中国技术品牌输出添砖加瓦。

官网:https://infinilabs.cn

联系我们

原文:https://infinilabs.cn/blog/2024/the-technological-development-and-future-trends-of-search-oriented-databases/

极限网关助力好未来 Elasticsearch 容器化升级

ElasticsearchINFINI Labs 小助手 发表了文章 • 0 个评论 • 4290 次浏览 • 2024-06-12 15:01 • 来自相关话题

极限网关在好未来的最佳实践案例,轻松扛住日增百 TB 数据的流量,助力 ES 从物理机到云原生架构的改造,实现了流控、请求分析、安全管理、无缝迁移等场景。一次完美的客户体验~

背景

物理机架构时代

2022 年,好未来整个日志 Elasticsearch 拥有数十套服务集群,几百台物理机。这么多台机器耗费成本非常高,而且还要花费很大精力去维护。在人力资源有限情况下,存在非常多的弊端,运行成本高,不仅是机器折旧还有机柜等费用。

流量特征

这是来自某个业务线,如下图 1,真实流量,潮汐性非常明显。好未来有很多条业务线,几乎跟这个趋势都一致的,除了个别业务有“续报”、“开课”等活动特殊情况。潮汐性带来的问题就是高峰期 CPU、内存资源是可以消耗很高;低峰期资源使用量非常低,由于是物理架构,这些资源无法给其他业务线共享。

图1

图1

降本增效-容器化改造原动力

日志服务对成本的空前的压力促使我们推进 Elasticsearch 进行架构改造;如何改造,改造成什么样子,这两个问题一直是推进改造原动力。业界能够同时对水平扩展和垂直扩展就是 K8S,我们开始对 Elasticsearch 改造成能在 K8S 上运行进行探索,从而提升 CPU、内存利用率。

物理机时代,没办法把资源动态的扩缩,动态调配,资源隔离,单靠人力操作调度成本太高,几乎无法完成;集群对内存资源需求要比 CPU 资源大很多,由于机器型号配置是固定的,无法“定制”,这也会导致成本居高不下。所以,无论从那个方面来讲,容器化优势非常明显,既能够优化成本,也能够降低运维复杂度。

ES 容器化改造

进行架构升级重点难点- API 服务

改造过程,我们遇到了很多问题,比如容器 ES 版本和物理机 ES 版本不一致,如何让 ES API 能够兼容不同的 ES 版本,由于版本的不兼容,导致无法直接使用原有的 tribenode 进行服务,怎么提供一个高可用的 Elasticsearch API 服务。我们考虑到多个方面,比如使用官方推荐的 proxy 模式、第三方服务等进行选择,经过多方面对比,选择了极限网关 进行 tribenode 替换。

原始 ES API 服务痛点

  • API 访问没有流量控制
  • 可观测性差,而且稳定性一般
  • 版本兼容性差

物理机时代 API 架构

在物理机时代 ES 集群,API 架构如图 2,可以明显看到 tribe node 对所有 ES 集群的“侵入性”是非常大的,这就带来了很多问题,比较严重的就是单个集群对 ES tribenode 的影响和版本升级带来的不兼容问题。

图2

图2

混合时代 API 架构

通过图 3,我们可以看到,极限网关对于版本兼容性很好,能够适配不同的版本。因此,最终选择极限网关作为下一代 ES API 服务方。

图3

图3

里程碑:全部 ES 集群容器化

在 2023 年 3 月份,通过 Elastic 官方 ECK 模式,完成全部日志 ES 集群容器化改造,拥有数百节点,1PB+ 数据存储,每日新增数据 100T 左右。紧接着,除了日志服务外,同时支持了好未来多条业务线。

图4

图4

极限网关实践

下面主要讲述了,为什么选择极限网关,以及极限网关在好未来落地、应用这些内容。

为什么选择极限网关?

学习成本低

我们可以从文档中看到极限网关,其架构简洁,语法简单,直观易懂。学习成本比较低,上手非常快,对新手友好。

性能强悍

经过压测,发现极限网关速度非常快,且针对 Elasticsearch 做了非常细致的优化,能成倍提升写入和查询的速度。

安全性高

支持多种认证方式,最简单的账号密码认证,可以给自定义多个账户密码,大大简化了 Elasticsearch 的安全设置,同时,还可以支持 LDAP 安全验证。

跨版本支持

我们容器化改造过程需要兼容不同版本的 Elasticsrearch,极限网关针对不同的 Elasticsearch 版本做了兼容和针对性处理,能够让业务代码无缝的进行适配,后端 Elasticsearch 集群版本升级能够做到无缝过渡,降低版本升级和数据迁移的复杂度,非常匹配我们的业务场景。

灵活可扩展

可灵活对每个请求进行干预和路由,支持路由的智能学习,内置丰富的过滤器,通过配置动态修改每个请求的处理逻辑,也支持通过插件来进行扩展,满足我们对流量的控制,尤其是限流、用户、IP 等这些功能非常实用。

启用安全策略-为 API 服务保驾护航

痛点

在升级之前使用 tribe 作为 API 服务提供后端,几乎相当于裸奔,没有任何认证策略;另外,tribe 本身的稳定性也有问题,官方在新版本逐渐废弃这种 CCS(跨集群搜索),期间出现多次服务崩溃。

极限网关解决问题

极限网关通过,“basic_auth” 插件,提供最基本的安全校验,使用起来非常方便;同时,极限网关提供 LDAP 插件,可以接入公共的 LDAP 服务,对所有的访问用户进行校验,安全策略对所有的用户生效,不用担心因为 IP 问题泄漏数据等。

强大的过滤功能

在使用 ES 集群过程中,许多场景,需要对请求进行控制、限制等操作。在这方便,感受到了极限网关强大的产品力。比如下面的两个场景

对异常流量进行限流

  • 支持对 IP 限流
  • 支持对 hostname 限流
  • 支持 header 限流

对异常用户进行封禁

当 Elasticsearch 是通过 Basic Auth 或者 LDAP 方式来进行身份认证的时候,request_user_filter 过滤器可用来按请求的用户名信息来进行过滤。操作起来也非常简单,只需要 request_user_filter 这一个过滤器。

- request_user_filter:
    include:
        - "elastic"
    exclude:
        - "Ryan"

总结来讲,主要有这些方面的功能:

图5

图5

优秀的可观测性

痛点

改造前经常为看不到直观的数据指标感到头疼,查看指标需要多个地方同时打开,去筛选,查找,非常繁琐,付出的成本非常大。为此,大家都再考虑如何优化这种情况,无奈优先级比较低,一直没有真正的投入时间去优化这块。

完美解决

使用了极限网关,通过收集请求日志,非常清晰的收集到想要的数据,具体如下:

  • 总体方面:
    • 流量曲线
    • 状态码占比
    • 缓存统计
    • 每台网关请求流量
  • 细节方面:
    • 打印每次请求语句
    • 可以查看请求到具体 ES 节点流量
    • 可以查看过滤器的列表

通过下图,我们可以从管理视角直观的看到各种信息,这对于管理员来讲,省时省力,方便快捷。

图6

图6

意外收获:无缝迁移业务 Elasticsearch 上云

由于前期日志业务上云,受到非常好的反馈,多个业务线期望能够上云上服务,达到降本增效的目的。

支持双写

数据可以通过极限网关同时写入两个 ES 集群,能够保障数据完全一致,安全可靠。

无缝切换

切换很丝滑,影响非常小,能够让外界几乎感受不到服务波动。

图7

图7

通过使用极限网关,自建 ES 集群可以无缝的迁移上云,在整个迁移的过程中,两套集群通过网关进行了解耦,在迁移的过程中还能实现版本的无缝升级,极大降低了迁移成本,提高迁移效率,多次验证服务稳定可靠。

极限网关流量概览

这是其中一套极限网关的流量统计。用这部分数据进行巡检,一目了然,做到全局的掌控,提高感知力度。

图8

图8

极限网关使用总结

极限网关提供一系列高性能和高可靠性的网关服务。使用这样的服务给我们带来以下好处:

  1. 可观测性好:极限网关可以动态的对 Elasticsearch 运行过程中请求进行拦截和分析,通过指标和日志来了解集群运行状态,这些指标可以用于提升性能和业务优化。
  2. 增强安全性:包含先进的安全机制,如 basicauth、LDAP 等支持,保护用户数据不受未授权访问和各种网络威胁的侵害。
  3. 高稳定性:通过冗余设计和故障转移机制,极限网关能够确保网络服务的高可用性,即使在某些组件发生故障时也能保持服务不中断,单版本最长服务超过 15 个月。
  4. 易于管理:通过提供 INFINI Console 简洁直观的管理界面,让用户能够轻松配置和监控网络状态,提升管理效率。
  5. 客户支持:良好的客户服务支持可以帮助用户快速解决使用过程中遇到的问题,提供专业的技术指导。

综上所述,极限网关为用户提供了一个高速、安全、稳定且易于管理的 ES 网关,适合对网络性能有较高要求的个人和企业用户。

未来规划

第一阶段,完成了日志 ES 集群,所有集群的容器化改造,合并,成功的把成本降低了 60%以上。这期间积累了丰富容器化经验,为业务 ES 集群上容器做了良好的铺垫;成本优势和运维优势吸引越来越多的业务接入到容器化 ES 集群。

提升 ES 集群效能--新技术应用&&版本升级

  • 极限科技官方推荐的 Easysearch 在压缩率,查询速度等等方面有很多的优势,通过长时间的测试稳定性,新特性,对比云原生的 ES 集群,根据测试结果,给“客户”提供多种选择,这也是工作重点之一。
  • 我们当前使用的 ES 版本是 6.8,已经远远落后于官方版本,今年我们计划在选择合适的集群升级 ES 版本,拥抱更多官方提供的特性。

混合(多)云架构支持

随着越来越多的 ES 集群在机房的 K8S 集群部署,这里资源出现了紧张局面。 我们尝试在云上部署自建 ES 集群,弥补机房资源有限,无法大规模扩容,同时能够支持多活场景,满足更多客户的不同需求。混合云主要实现以下几种能力:

1、扩缩容:满足不同业务灵活适配

混合(多)云部署,可以让负载内部私有云 ES,同时部署到公有云,提升扩展 IT 基础设施不仅局限于 CPU、内存,还有存储。比如某一个业务要做活动,预估流量“大爆发”,需要提前准备大规模资源,在机房内根本来不及采购扩容支持,然而在公有云上就能很方便扩容、缩容。在云上搭建 ES 集群,设置满足需求的数量、容量、配置,配合极限网关路由策略,精准的把控流量流向。

图9

图9

2、灾备:紧急情况快速部署,恢复 ES 集群读写

当机房级别大规模故障,部分业务实现了多活,单一的机房故障不会影响其服务能力,而此时比如日志查看等仍有需求,为了满足这部分“客户”需求,可以在云上 K8S 集群,快速搭建 ES 集群,恢复日志读写功能。

图10

图10

参考文档:

作者:张华勋,前新浪 CDN 研发,工作主要涉及 Mysql、MongoDB、Redis、Elasticsearch、流量调度等组件和系统,以及运维自动化、平台化等工作。现就职于好未来。

关于好未来

好未来(NYSE:TAL)是一家以内容能力与科技能力为基础,以科教、科创、科普为战略方向,助力人的终身成长,并持续探索创新的科技公司。 好未来的前身学而思成立于 2003 年,2010 年在美国纽交所正式挂牌交易。好未来以“爱与科技助力终身成长”为使命,致力成为持续创新的组织。更多参见:https://www.100tal.com/

关于极限科技(INFINI Labs)

INFINI Labs

极限科技,全称极限数据(北京)科技有限公司,是一家专注于实时搜索与数据分析的软件公司。旗下品牌极限实验室(INFINI Labs)致力于打造极致易用的数据探索与分析体验。

极限科技是一支年轻的团队,采用天然分布式的方式来进行远程协作,员工分布在全球各地,希望通过努力成为中国乃至全球企业大数据实时搜索分析产品的首选,为中国技术品牌输出添砖加瓦。

官网:https://www.infinilabs.cn

联系我们