MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

ElasticSearch数据单位API在存储管理中的应用

2023-07-126.2k 阅读

ElasticSearch数据单位API基础

数据单位概述

在ElasticSearch中,数据单位的理解至关重要。ElasticSearch处理的数据单位从最基本的文档(Document)开始。文档是ElasticSearch中可被索引的最小数据单元,它以JSON格式存在,包含了各种字段(Field)。每个文档都有一个唯一的标识符,即 _id。例如,一个描述书籍的文档可能如下:

{
    "_id": "1",
    "title": "ElasticSearch in Action",
    "author": "Rivers",
    "publication_year": 2015
}

文档之上是索引(Index),索引可以看作是一组文档的集合,它类似于传统关系型数据库中的数据库概念。例如,我们可以创建一个名为 books 的索引来存储所有与书籍相关的文档。

数据单位API介绍

  1. 创建索引API:使用 PUT 请求来创建索引。例如,要创建一个名为 my_index 的索引,可以使用以下的 curl 命令:
curl -X PUT "localhost:9200/my_index"

在实际应用中,我们可能需要对索引进行更多的设置,比如指定分片数和副本数。以下是一个设置了3个主分片和2个副本的示例:

curl -X PUT "localhost:9200/my_index" -H 'Content-Type: application/json' -d'
{
    "settings": {
        "number_of_shards": 3,
        "number_of_replicas": 2
    }
}'
  1. 索引文档API:通过 PUTPOST 请求将文档添加到索引中。如果使用 PUT 请求,需要在URL中指定文档的 _id;而 POST 请求则会自动生成 _id。以下是使用 PUT 请求添加文档的示例:
curl -X PUT "localhost:9200/my_index/_doc/1" -H 'Content-Type: application/json' -d'
{
    "title": "Sample Document",
    "content": "This is a sample document for ElasticSearch"
}'

使用 POST 请求的示例如下:

curl -X POST "localhost:9200/my_index/_doc" -H 'Content-Type: application/json' -d'
{
    "title": "Another Sample Document",
    "content": "This is another sample document"
}'
  1. 检索文档API:使用 GET 请求来检索文档。例如,要获取 my_index 索引中 _id1 的文档,可以使用以下命令:
curl -X GET "localhost:9200/my_index/_doc/1"

如果要检索多个文档,可以使用 mget API。以下是一个示例:

curl -X POST "localhost:9200/_mget" -H 'Content-Type: application/json' -d'
{
    "docs": [
        {
            "_index": "my_index",
            "_id": "1"
        },
        {
            "_index": "my_index",
            "_id": "2"
        }
    ]
}'

ElasticSearch存储管理架构

存储管理组件

  1. 节点(Node):ElasticSearch集群由多个节点组成,每个节点都可以存储数据并参与集群的索引和搜索操作。节点分为主节点(Master Node)和数据节点(Data Node)。主节点负责管理集群的元数据,如索引的创建、删除,节点的加入和离开等。数据节点则负责存储和处理实际的数据。我们可以通过配置文件来指定节点的类型。在 elasticsearch.yml 文件中,通过设置 node.master: true 可以将节点配置为主节点,设置 node.data: true 可以将节点配置为数据节点。
  2. 分片(Shard):为了处理大数据量,ElasticSearch将索引划分为多个分片。每个分片是一个独立的Lucene索引,可以分布在不同的节点上。主分片(Primary Shard)负责处理文档的写入和更新操作,副本分片(Replica Shard)则用于提供数据冗余和提高搜索性能。例如,在创建索引时设置 number_of_shards: 5,则该索引将被划分为5个主分片。这些分片会在集群中的节点上自动分配。
  3. 副本(Replica):副本是主分片的拷贝,用于数据冗余和提高系统的可用性和性能。当某个主分片所在的节点出现故障时,副本分片可以接管其工作。同时,副本分片也可以参与搜索操作,分担主分片的负载。在创建索引时可以设置副本的数量,如 number_of_replicas: 1 表示每个主分片有一个副本。

存储管理流程

  1. 写入流程:当一个文档被索引时,首先会根据文档的 _id 计算出应该存储在哪个主分片上。然后,请求会被发送到负责该主分片的节点。主分片接收到请求后,将文档写入磁盘,并将写入操作同步到所有相关的副本分片。只有当所有副本分片都确认写入成功后,该文档的写入操作才被认为是成功的。例如,假设有一个包含3个主分片和2个副本的索引,当一个文档被索引时,它会被写入到其中一个主分片上,然后这个主分片会将写入操作同步到另外两个副本分片上。
  2. 读取流程:当进行搜索请求时,请求会被发送到集群中的任意一个节点。该节点会将请求转发到所有相关的主分片和副本分片。这些分片会并行处理搜索请求,并将结果返回给请求节点。请求节点再将这些结果合并并返回给客户端。例如,如果有一个搜索请求,请求节点可能会将请求发送到包含相关数据的主分片和副本分片,这些分片同时进行搜索,然后将结果返回给请求节点进行合并。

数据单位API在存储管理中的应用

索引创建与优化

  1. 合理设置分片和副本:在创建索引时,根据数据量和预期的增长来合理设置分片和副本的数量非常重要。如果数据量较小,设置过多的分片会增加管理开销;而数据量较大时,分片数不足则会影响性能。例如,对于一个预计存储100GB数据的索引,如果设置的分片数过少,可能会导致单个分片数据量过大,影响写入和搜索性能。以下是一个根据数据量预估来设置分片的示例:
curl -X PUT "localhost:9200/big_data_index" -H 'Content-Type: application/json' -d'
{
    "settings": {
        "number_of_shards": 10,
        "number_of_replicas": 1
    }
}'

这里假设根据经验和对数据增长的预估,设置10个主分片和1个副本。 2. 索引模板:索引模板可以帮助我们在创建索引时应用一组预定义的设置和映射。这对于创建多个具有相似结构的索引非常有用。例如,我们可以创建一个模板,为所有以 log_ 开头的索引设置相同的分片、副本和字段映射。以下是创建索引模板的示例:

curl -X PUT "localhost:9200/_template/log_template" -H 'Content-Type: application/json' -d'
{
    "index_patterns": ["log_*"],
    "settings": {
        "number_of_shards": 5,
        "number_of_replicas": 1
    },
    "mappings": {
        "properties": {
            "timestamp": {
                "type": "date"
            },
            "message": {
                "type": "text"
            }
        }
    }
}'

这样,当我们创建 log_20230101 这样的索引时,就会自动应用这个模板的设置。

文档管理与存储优化

  1. 批量操作:为了提高写入性能,ElasticSearch提供了批量操作API(Bulk API)。通过批量操作,可以将多个索引、删除等操作合并到一个请求中。例如,以下是一个使用 Bulk API 批量索引文档的示例:
curl -X POST "localhost:9200/my_index/_bulk" -H 'Content-Type: application/json' -d'
{"index": {"_id": "1"}}
{"title": "Document 1", "content": "Content of document 1"}
{"index": {"_id": "2"}}
{"title": "Document 2", "content": "Content of document 2"}
'

这样可以减少网络开销,提高写入效率。 2. 文档版本控制:ElasticSearch支持文档的版本控制。每次文档更新时,版本号会自动递增。通过指定版本号,可以确保只有在文档版本匹配时才进行更新操作。例如,以下是使用版本控制进行更新的示例:

curl -X PUT "localhost:9200/my_index/_doc/1?version=1" -H 'Content-Type: application/json' -d'
{
    "title": "Updated Document 1",
    "content": "Updated content of document 1"
}'

如果当前文档的版本不是1,更新操作将失败。

存储监控与维护

  1. 监控API:ElasticSearch提供了一系列监控API来获取集群和索引的状态信息。例如,使用 _cat API可以查看集群的健康状态、节点信息、索引信息等。以下是查看集群健康状态的命令:
curl -X GET "localhost:9200/_cat/health?v"

该命令会返回集群的健康状态,包括状态(绿、黄、红)、节点数、数据量等信息。如果状态为红色,表示集群中存在主分片不可用的情况,需要及时处理。 2. 索引优化与清理:随着时间的推移,索引可能会因为频繁的更新和删除操作而产生碎片化,影响性能。可以使用 optimize API(在ElasticSearch 6.0之后已被 forcemerge 取代)来合并索引段,减少碎片化。以下是使用 forcemerge API的示例:

curl -X POST "localhost:9200/my_index/_forcemerge?max_num_segments=1"

这会将 my_index 索引的段合并为1个,提高搜索性能。同时,对于不再需要的索引,可以使用 DELETE 请求进行删除:

curl -X DELETE "localhost:9200/my_index"

高级应用场景

多租户数据存储

在多租户的应用场景中,我们可以为每个租户创建一个独立的索引,或者在一个索引中通过文档的某个字段(如 tenant_id)来区分不同租户的数据。如果为每个租户创建独立索引,可以利用索引模板来快速创建具有相同结构的索引。例如,为租户 tenant1 创建索引:

curl -X PUT "localhost:9200/tenant1_index" -H 'Content-Type: application/json' -d'
{
    "settings": {
        "number_of_shards": 3,
        "number_of_replicas": 1
    },
    "mappings": {
        "properties": {
            "tenant_id": {
                "type": "keyword"
            },
            "data": {
                "type": "text"
            }
        }
    }
}'

然后可以将属于 tenant1 的文档索引到 tenant1_index 中。如果在一个索引中区分租户数据,可以在索引文档时添加 tenant_id 字段:

curl -X POST "localhost:9200/multi_tenant_index/_doc" -H 'Content-Type: application/json' -d'
{
    "tenant_id": "tenant1",
    "data": "Data for tenant 1"
}'

在搜索时,可以通过过滤 tenant_id 来获取特定租户的数据:

curl -X GET "localhost:9200/multi_tenant_index/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "term": {
            "tenant_id": "tenant1"
        }
    }
}'

数据生命周期管理

  1. 基于时间的索引滚动:对于时间序列数据,如日志数据,通常需要定期创建新的索引,并将旧索引的数据进行归档或删除。可以使用ElasticSearch的索引别名和滚动索引的方式来实现。首先,创建一个索引别名指向当前的索引,例如 current_logs 别名指向 logs_202301 索引。当新的月份到来时,创建一个新的索引 logs_202302,并更新索引别名 current_logs 指向 logs_202302。以下是创建索引别名的示例:
curl -X POST "localhost:9200/_aliases" -H 'Content-Type: application/json' -d'
{
    "actions": [
        {
            "add": {
                "index": "logs_202301",
                "alias": "current_logs"
            }
        }
    ]
}'

更新别名指向新索引的示例:

curl -X POST "localhost:9200/_aliases" -H 'Content-Type: application/json' -d'
{
    "actions": [
        {
            "remove": {
                "index": "logs_202301",
                "alias": "current_logs"
            }
        },
        {
            "add": {
                "index": "logs_202302",
                "alias": "current_logs"
            }
        }
    ]
}'
  1. 数据老化策略:可以结合ElasticSearch的索引生命周期管理(ILM)功能来实现数据老化策略。通过ILM,可以定义数据在不同阶段的行为,如热阶段(频繁读写)、温阶段(较少读写)和冷阶段(很少读写)。例如,定义一个策略,让新数据在热阶段存储在高性能磁盘上,一段时间后转移到成本较低的存储上,最终在一定时间后删除。以下是一个简单的ILM策略示例:
curl -X PUT "localhost:9200/_ilm/policy/log_policy" -H 'Content-Type: application/json' -d'
{
    "policy": {
        "phases": {
            "hot": {
                "min_age": "0ms",
                "actions": {
                    "rollover": {
                        "max_size": "50GB",
                        "max_age": "30d"
                    }
                }
            },
            "warm": {
                "min_age": "30d",
                "actions": {
                    "allocate": {
                        "include": {
                            "storage": "warm"
                        }
                    }
                }
            },
            "cold": {
                "min_age": "60d",
                "actions": {
                    "allocate": {
                        "include": {
                            "storage": "cold"
                        }
                    },
                    "delete": {
                        "min_age": "90d"
                    }
                }
            }
        }
    }
}'

然后在创建索引时应用这个策略:

curl -X PUT "localhost:9200/logs" -H 'Content-Type: application/json' -d'
{
    "settings": {
        "number_of_shards": 3,
        "number_of_replicas": 1,
        "index.lifecycle.name": "log_policy",
        "index.lifecycle.rollover_alias": "logs_write"
    }
}'

性能优化与调优

硬件与配置优化

  1. 内存分配:ElasticSearch是内存密集型应用,合理分配内存至关重要。通常,建议将JVM堆内存设置为物理内存的一半,且不超过32GB。在 elasticsearch.yml 文件中,可以通过 XmsXmx 参数来设置JVM堆内存的初始值和最大值。例如:
# 在elasticsearch-env.sh文件中设置
export ES_JAVA_OPTS="-Xms16g -Xmx16g"
  1. 磁盘选择:对于存储数据的节点,选择高性能的磁盘可以显著提高读写性能。固态硬盘(SSD)相比于传统机械硬盘(HDD)具有更快的读写速度,尤其在处理大量小文件时优势明显。在配置文件中,可以通过 path.data 参数指定数据存储路径,确保数据存储在性能良好的磁盘上。

索引性能调优

  1. 字段映射优化:合理定义字段的映射类型可以提高搜索性能。例如,对于不需要进行全文搜索的字段,将其类型设置为 keyword 而不是 text,可以减少索引空间和提高搜索速度。以下是一个字段映射优化的示例:
curl -X PUT "localhost:9200/my_index" -H 'Content-Type: application/json' -d'
{
    "mappings": {
        "properties": {
            "product_id": {
                "type": "keyword"
            },
            "product_name": {
                "type": "text"
            }
        }
    }
}'

这里将 product_id 设置为 keyword 类型,适合用于精确匹配搜索。 2. 搜索性能优化:使用合适的查询语句和过滤器可以提高搜索性能。例如,对于范围查询,可以使用 range 过滤器来减少搜索范围。以下是一个使用 range 过滤器的示例:

curl -X GET "localhost:9200/my_index/_search" -H 'Content-Type: application/json' -d'
{
    "query": {
        "bool": {
            "filter": [
                {
                    "range": {
                        "price": {
                            "gte": 10,
                            "lte": 100
                        }
                    }
                }
            ]
        }
    }
}'

这样可以快速筛选出价格在10到100之间的文档,提高搜索效率。

集群性能调优

  1. 节点扩展:根据业务需求和数据量的增长,适时扩展集群节点数量。可以通过添加新的数据节点来提高存储和处理能力,添加新的主节点来提高集群的管理性能。在添加节点时,需要确保新节点的配置与现有节点兼容。例如,在启动新节点时,确保其 cluster.name 与现有集群名称一致,并且网络配置正确。
  2. 负载均衡:ElasticSearch内置了负载均衡机制,会自动将请求分配到不同的节点上。但是,在某些情况下,如节点性能差异较大时,可能需要手动调整负载均衡策略。可以通过调整分片分配策略来实现,例如使用 cluster.routing.allocation.balance.shard 参数来控制分片在节点间的分配。以下是在 elasticsearch.yml 文件中设置该参数的示例:
cluster.routing.allocation.balance.shard: 0.4

这里将分片分配的均衡度设置为0.4,值越小表示越倾向于将分片分配到负载较低的节点上。

通过对以上各个方面的深入理解和合理应用,我们能够充分发挥ElasticSearch数据单位API在存储管理中的强大功能,构建高效、可靠的数据存储和检索系统。无论是处理大规模数据的企业级应用,还是对性能和灵活性要求较高的互联网应用,ElasticSearch都能通过其丰富的API和灵活的架构满足各种需求。在实际应用中,需要根据具体的业务场景和数据特点,不断优化和调整设置,以达到最佳的性能和效果。同时,持续关注ElasticSearch的版本更新和新功能发布,及时应用到项目中,能够进一步提升系统的竞争力和适应性。