• 【详解配置文件系列】es7配置文件详解


    首发博客地址

    系列文章地址


    配置文件

    # ---------------------------------- Cluster -----------------------------------
    cluster.name: my-cluster
    # 集群的名称

    node.name: node-1
    # 节点的名称

    node.master: true
    # 是否允许节点成为主节点(默认为 true)

    node.data: true
    # 是否允许节点存储数据(默认为 true)

    # ----------------------------------- Paths ------------------------------------
    path.data: /path/to/data
    # 数据文件的存储路径

    path.logs: /path/to/logs
    # 日志文件的存储路径

    # ---------------------------------- Network -----------------------------------
    network.host: 0.0.0.0
    # 监听的网络接口地址(默认为 0.0.0.0,即监听所有接口)

    http.port: 9200
    # HTTP 通信使用的端口号(默认为 9200)

    transport.tcp.port: 9300
    # 节点间通信使用的 TCP 端口号(默认为 9300)

    # --------------------------------- Discovery ----------------------------------
    discovery.seed_hosts: [ "host1", "host2" ]
    # 发现初始主机节点的地址列表,用于集群自动发现

    cluster.initial_master_nodes: [ "node-1", "node-2" ]
    # 初始主节点列表,用于集群自动发现

    # ---------------------------------- Gateway -----------------------------------
    gateway.recover_after_nodes: 3
    # 节点数达到指定数量后,才开始恢复数据(默认为 3)

    gateway.expected_nodes: 5
    # 预期的节点数量,用于恢复数据(默认为 5)

    # ---------------------------------- Memory ------------------------------------
    bootstrap.memory_lock: true
    # 是否锁定 Elasticsearch 进程的内存(需要设置文件系统权限)

    # ---------------------------------- Various -----------------------------------
    action.destructive_requires_name: true
    # 在执行危险操作(如删除索引)时,需要显式指定操作名称(默认为 true)

    # ---------------------------------- Security ----------------------------------
    xpack.security.enabled: true
    # 是否启用 X-Pack 安全功能(默认为 false)

    xpack.security.authc.api_key.enabled: true
    # 是否启用 API 密钥认证(默认为 false)

    # ---------------------------------- Logging ----------------------------------
    logger.org.elasticsearch.transport: debug
    # 日志级别设置(可选:trace, debug, info, warn, error, fatal)
    • 1

    cluster.name

    cluster.nameElasticsearch 配置文件中的一个重要选项,用于指定集群的名称。每个运行的 Elasticsearch 实例都必须具有相同的集群名称才能加入同一个集群。

    cluster.name: my-cluster
    • 1
    • cluster.name是一个自定义的字符串,用于标识一个 Elasticsearch 集群。集群名称可以是任何合法的字符串,但最好选择一个具有描述性的名称,以便在多个集群之间区分。

    • 所有想要加入同一个集群的 Elasticsearch 节点都必须设置相同的cluster.name值。这样,它们才能相互发现并协同工作,共享数据和状态。

    • 如果您在配置文件中更改了cluster.name选项的值,需要确保所有节点都使用相同的集群名称,并重新启动它们才能生效。

    • 默认情况下,Elasticsearch 的集群名称为"elasticsearch"。但为了避免与其他集群发生冲突,建议将cluster.name设置为唯一的名称。

    • 集群名称是 Elasticsearch 集群的重要标识,它还用于在集群中的节点之间进行发现、通信和协调。

    确保在配置 Elasticsearch 集群时,将所有节点的cluster.name选项设置为相同的值,以确保它们能够正常加入同一个集群并协同工作。

    node.name

    node.name是 Elasticsearch 配置文件中的一个选项,用于指定节点的名称。每个运行的 Elasticsearch 节点都应该具有唯一的名称,以便在集群中进行识别和通信。

    node.name: node-1
    • 1
    • node.name是一个自定义的字符串,用于标识一个 Elasticsearch 节点。节点名称可以是任何合法的字符串,但最好选择一个具有描述性的名称,以便在集群中识别和管理节点。

    • 每个 Elasticsearch 节点都应该具有唯一的node.name值,以避免与其他节点发生冲突。

    • 节点名称对于集群中的节点之间的发现、通信和协调非常重要。节点名称用于在集群中识别和标识特定的节点。

    • 如果您在配置文件中更改了node.name选项的值,需要确保每个节点都使用唯一的名称,并重新启动它们才能生效。

    • 默认情况下,如果没有显式设置node.name选项,Elasticsearch 会自动生成一个随机的节点名称。

    在配置 Elasticsearch 节点时,确保为每个节点设置唯一的node.name值,以便在集群中正确识别和管理节点。这将有助于确保节点之间的正常通信和协作。

    node.master: true

    node.master是 Elasticsearch 配置文件中的一个选项,用于指定节点是否可以成为主节点。主节点负责集群中的元数据管理和协调工作。

    node.master: true
    • 1
    • node.master是一个布尔值选项,用于指定节点是否可以成为主节点。默认情况下,它的值为true,表示节点可以担任主节点的角色。

    • 主节点负责集群级别的操作,如创建或删除索引、分配分片、维护节点拓扑结构等。通常情况下,一个集群中只有少数几个节点会被选为主节点。

    • 如果您有多个节点运行在同一个集群中,并希望将某些节点排除在主节点的角色之外,可以将node.master选项设置为false

    • 在配置节点时,根据集群的规模和需求,需要仔细选择主节点的数量和分布。通常建议在较大的集群中选择多个主节点,以提高冗余性和可用性。

    • 如果集群中的主节点失败或不可用,Elasticsearch 会自动从剩余的节点中选举新的主节点。

    确保在配置节点时,根据集群的需求和规模,正确设置node.master选项,以确保主节点的角色分配和集群的正常运行。

    node.data: true

    node.data是 Elasticsearch 配置文件中的一个选项,用于指定节点是否可以存储数据。数据节点负责存储和处理索引数据。

    node.data: true
    • 1
    • node.data是一个布尔值选项,用于指定节点是否可以存储数据。默认情况下,它的值为true,表示节点可以作为数据节点。

    • 数据节点负责存储索引的分片数据和执行与索引数据相关的操作,如索引和搜索。在一个 Elasticsearch 集群中,可以有多个数据节点来分担数据的存储和处理负载。

    • 如果您希望某个节点只负责协调和管理集群,并不存储任何数据,则可以将node.data选项设置为false

    • 在配置节点时,根据集群的需求和规模,需要仔细考虑数据节点的数量和分布。通常建议在大型集群中选择多个数据节点,以实现数据的冗余和高可用性。

    • 数据节点会自动接收和管理分配给它们的分片,并与其他数据节点进行数据同步和复制,以确保数据的可靠性和一致性。

    确保在配置节点时,根据集群的需求和规模,正确设置node.data选项,以确保数据节点的角色分配和集群的正常运行。

    path.data: /path/to/data

    path.data是 Elasticsearch 配置文件中的一个选项,用于指定数据文件的存储路径。

    以下是对path.data选项的详细解释:

    path.data: /path/to/data
    • 1
    • path.data用于指定 Elasticsearch 存储索引数据的路径。这个路径可以是一个本地文件系统的目录,也可以是一个挂载的网络文件系统(NFS)路径。

    • 在配置文件中,将/path/to/data替换为实际的数据存储路径。

    • 默认情况下,Elasticsearch 会在启动时自动创建一个名为data的子目录,并在该目录下存储索引数据。

    • 如果您希望将索引数据存储在不同的位置,可以使用path.data选项来指定自定义的数据存储路径。确保目录具有适当的权限,以便 Elasticsearch 进程可以读取和写入数据。

    • 如果您有多个数据节点运行在同一个集群中,那么所有数据节点的path.data配置应该指向相同的目录,以确保数据的共享和一致性。

    • 对于高可用性和数据冗余,建议将数据存储在多个独立的磁盘驱动器上,以避免单点故障。

    确保在配置 Elasticsearch 节点时,正确设置path.data选项,以指定数据文件的存储路径,并确保路径的可用性和适当的权限设置。

    path.logs: /path/to/logs

    path.logs是 Elasticsearch 配置文件中的一个选项,用于指定日志文件的存储路径。

    以下是对path.logs选项的详细解释:

    path.logs: /path/to/logs
    • 1
    • path.logs用于指定 Elasticsearch 存储日志文件的路径。这个路径可以是一个本地文件系统的目录,也可以是一个挂载的网络文件系统(NFS)路径。

    • 在配置文件中,将/path/to/logs替换为实际的日志文件存储路径。

    • 默认情况下,Elasticsearch 会在启动时自动创建一个名为logs的子目录,并在该目录下存储日志文件。

    • 如果您希望将日志文件存储在不同的位置,可以使用path.logs选项来指定自定义的日志文件存储路径。确保目录具有适当的权限,以便 Elasticsearch 进程可以写入日志文件。

    • 日志文件包含了 Elasticsearch 的运行日志、错误日志和其他日志信息,对于故障排除和监控非常重要。

    • 确保为日志存储路径选择一个具有足够的磁盘空间和适当的文件系统性能的位置。

    确保在配置 Elasticsearch 节点时,正确设置path.logs选项,以指定日志文件的存储路径,并确保路径的可用性和适当的权限设置。

    network.host

    network.host是 Elasticsearch 配置文件中的一个选项,用于指定 Elasticsearch 监听的网络接口地址。

    以下是对network.host选项的详细解释:

    network.host: 192.168.0.1
    • 1
    • network.host用于指定 Elasticsearch 监听的网络接口地址。可以使用具体的 IP 地址或主机名来指定要监听的网络接口。

    • 默认情况下,network.host的值是localhost,表示 Elasticsearch 只监听本地回环接口(127.0.0.1),即只允许本地访问。

    • 要使 Elasticsearch 对外可见并允许来自其他主机或网络的访问,可以将network.host设置为具体的 IP 地址或主机名。

    • 可以指定一个具体的 IP 地址(如192.168.0.1)来监听特定的网络接口。也可以使用通配符地址(如0.0.0.0)来监听所有可用的网络接口。

    • 如果您的服务器有多个网络接口(如多个网卡),可以根据需求选择要监听的特定接口。

    • 使用network.host选项时,需要注意安全性和访问控制,确保只允许受信任的主机或网络访问 Elasticsearch。

    确保在配置 Elasticsearch 节点时,根据实际需求、网络环境和安全考虑,正确设置network.host选项,以指定 Elasticsearch 监听的网络接口地址。

    http.port

    http.port是 Elasticsearch 配置文件中的一个选项,用于指定 Elasticsearch HTTP 通信所使用的端口号。

    以下是对http.port选项的详细解释:

    http.port: 9200
    • 1
    • http.port用于指定 Elasticsearch 监听的 HTTP 通信端口号。默认情况下,它的值是9200

    • 当客户端通过 HTTP 协议与 Elasticsearch 进行通信时,使用的是http.port指定的端口号。

    • 如果您希望在访问 Elasticsearch 时使用不同的端口号,可以修改http.port的值为所需的端口号。

    • 请确保所选的端口号在您的环境中是未被使用的,并且没有防火墙或其他网络设备阻止与该端口的通信。

    • 如果您有多个 Elasticsearch 节点运行在同一个集群中,每个节点都应该使用不同的http.port来避免端口冲突。

    确保在配置 Elasticsearch 节点时,根据实际需求和网络环境,正确设置http.port选项,以指定 Elasticsearch HTTP 通信所使用的端口号。

    transport.tcp.port

    transport.tcp.port是 Elasticsearch 配置文件中的一个选项,用于指定 Elasticsearch 节点间通信所使用的 TCP 端口号。

    以下是对transport.tcp.port选项的详细解释:

    transport.tcp.port: 9300
    • 1
    • transport.tcp.port用于指定 Elasticsearch 节点间通信所使用的 TCP 端口号。默认情况下,它的值是9300

    • 当 Elasticsearch 节点之间进行通信时,使用的是transport.tcp.port指定的端口号。节点间的通信主要用于数据复制、协调和集群管理等操作。

    • 如果您希望在访问 Elasticsearch 节点间通信时使用不同的端口号,可以修改transport.tcp.port的值为所需的端口号。

    • 请确保所选的端口号在您的环境中是未被使用的,并且没有防火墙或其他网络设备阻止与该端口的通信。

    • 如果您有多个 Elasticsearch 节点运行在同一个集群中,每个节点都应该使用不同的transport.tcp.port来避免端口冲突。

    • 默认情况下,客户端与 Elasticsearch 节点之间的通信应该使用 HTTP 协议,而不是直接通过transport.tcp.port进行通信。

    确保在配置 Elasticsearch 节点时,根据实际需求和网络环境,正确设置transport.tcp.port选项,以指定 Elasticsearch 节点间通信所使用的 TCP 端口号。

    discovery.seed_hosts

    discovery.seed_hosts是 Elasticsearch 配置文件中的一个选项,用于指定集群自动发现所需的初始主机节点列表。

    以下是对discovery.seed_hosts选项的详细解释:

    discovery.seed_hosts: [ "host1", "host2" ]
    • 1
    • discovery.seed_hosts用于指定集群自动发现时需要连接的初始主机节点列表。这些主机节点是用于引导新加入的节点发现和加入集群。

    • discovery.seed_hosts的值应该是一个字符串数组,包含了初始主机节点的主机名或 IP 地址。

    • 在启动 Elasticsearch 节点时,它会尝试连接discovery.seed_hosts列表中的每个主机,以获取集群的初始状态和其他节点的信息。

    • 当新的 Elasticsearch 节点加入集群时,它会通过与discovery.seed_hosts中的主机节点通信,自动发现并加入集群。

    • 请确保discovery.seed_hosts中的主机节点是可达的,并且在启动新节点之前,这些主机节点已经在运行。

    • discovery.seed_hosts选项在集群的初始配置中非常重要,它确保新节点能够正确加入已有的 Elasticsearch 集群。

    确保在配置 Elasticsearch 节点时,根据实际需求和集群拓扑,正确设置discovery.seed_hosts选项,以指定集群自动发现所需的初始主机节点列表。

    cluster.initial_master_nodes

    cluster.initial_master_nodes是 Elasticsearch 配置文件中的一个选项,用于指定集群的初始主节点列表。

    以下是对cluster.initial_master_nodes选项的详细解释:

    cluster.initial_master_nodes: [ "node-1", "node-2" ]
    • 1
    • cluster.initial_master_nodes用于指定集群的初始主节点列表。这些节点是集群中的初始主节点,负责集群的管理和协调工作。

    • cluster.initial_master_nodes的值应该是一个字符串数组,包含了初始主节点的名称。

    • 在启动 Elasticsearch 节点时,它会尝试连接cluster.initial_master_nodes列表中的每个节点,以选举出集群中的主节点。

    • 初始主节点是在集群启动时被选举出来的,并负责管理集群的元数据和协调工作。

    • 请确保cluster.initial_master_nodes中的节点名称是正确的,并且这些节点已经在运行。

    • cluster.initial_master_nodes选项在集群的初始配置中非常重要,它确保正确选举出初始的主节点,以启动和管理集群。

    确保在配置 Elasticsearch 节点时,根据实际需求和集群拓扑,正确设置cluster.initial_master_nodes选项,以指定集群的初始主节点列表。

    gateway.recover_after_nodes

    gateway.recover_after_nodes是 Elasticsearch 配置文件中的一个选项,用于指定在多少个节点可用后开始进行数据恢复。

    以下是对gateway.recover_after_nodes选项的详细解释:

    gateway.recover_after_nodes: 3
    • 1
    • gateway.recover_after_nodes用于指定在多少个节点可用后开始进行数据恢复。默认情况下,它的值是3

    • 当一个 Elasticsearch 集群中的节点发生故障或重新启动时,数据恢复过程将在指定数量的可用节点后开始执行。

    • gateway.recover_after_nodes的值应该是一个正整数,表示需要达到的可用节点数量。

    • 通过设置gateway.recover_after_nodes,可以确保在集群中有足够的节点可用时才进行数据恢复,以避免数据恢复过程对集群的过大负载。

    • 请注意,gateway.recover_after_nodes选项仅适用于启用了持久化存储的情况,例如使用本地磁盘或专用数据存储。

    • 如果集群中的可用节点数量少于指定的gateway.recover_after_nodes值,数据恢复将不会自动开始。在这种情况下,您需要手动触发数据恢复过程。

    确保在配置 Elasticsearch 节点时,根据实际需求和集群规模,正确设置gateway.recover_after_nodes选项,以确保在足够数量的节点可用后开始进行数据恢复。

    gateway.expected_nodes

    gateway.expected_nodes是 Elasticsearch 配置文件中的一个选项,用于指定预期的节点数量,用于数据恢复。

    以下是对gateway.expected_nodes选项的详细解释:

    gateway.expected_nodes: 5
    • 1
    • gateway.expected_nodes用于指定预期的节点数量,用于数据恢复。默认情况下,它的值是5

    • 当一个 Elasticsearch 集群中的节点发生故障或重新启动时,数据恢复过程将等待达到预期的节点数量。

    • gateway.expected_nodes的值应该是一个正整数,表示期望的节点数量。

    • 通过设置gateway.expected_nodes,可以确保在集群中有足够的节点可用时才开始数据恢复,以确保数据的完整性和一致性。

    • 当达到预期节点数量时,数据恢复过程会自动开始。如果节点数量少于预期,则数据恢复将等待,直到达到预期节点数量或手动触发恢复过程。

    • 请注意,gateway.expected_nodes选项仅适用于启用了持久化存储的情况,例如使用本地磁盘或专用数据存储。

    确保在配置 Elasticsearch 节点时,根据实际需求和集群规模,正确设置gateway.expected_nodes 选项,以确保在达到预期的节点数量时开始数据恢复。这有助于保证数据的完整性和一致性。

    bootstrap.memory_lock

    bootstrap.memory_lock是 Elasticsearch 配置文件中的一个选项,用于锁定 Elasticsearch 进程的内存,以防止内存被交换到磁盘上。

    以下是对bootstrap.memory_lock选项的详细解释:

    bootstrap.memory_lock: true
    • 1
    • bootstrap.memory_lock用于指定是否锁定 Elasticsearch 进程的内存。默认情况下,它的值是false,即未启用内存锁定。

    • 当将bootstrap.memory_lock设置为true时,Elasticsearch 将尝试锁定进程的内存,防止操作系统将内存交换到磁盘上。

    • 锁定内存可以提高 Elasticsearch 的性能,因为内存交换会导致延迟和性能下降。但是,要启用内存锁定,需要确保 Elasticsearch 的运行用户(如 elasticsearch)具有足够的权限。

    • 如果您启用了内存锁定并遇到权限问题或其他错误,可以将bootstrap.memory_lock设置为false,以允许 Elasticsearch 进程的内存被交换到磁盘上。

    • 请注意,启用内存锁定可能需要对操作系统进行额外的配置,以允许 Elasticsearch 进程锁定内存。具体步骤和要求取决于您使用的操作系统和分配的权限。

    确保在配置 Elasticsearch 节点时,根据实际需求和系统配置,正确设置bootstrap.memory_lock 选项,以控制是否锁定 Elasticsearch 进程的内存。请确保在启用内存锁定之前了解相关的权限和操作系统要求。

    action.destructive_requires_name

    action.destructive_requires_name是 Elasticsearch 配置文件中的一个选项,用于要求在执行危险操作(如删除索引)时显式指定操作名称。

    以下是对action.destructive_requires_name选项的详细解释:

    action.destructive_requires_name: true
    • 1
    • action.destructive_requires_name用于控制在执行危险操作时是否要求显式指定操作名称。默认情况下,它的值是false ,即不要求指定操作名称。

    • 危险操作包括删除索引、关闭集群、清除缓存等可能会导致数据丢失或集群不可用的操作。

    • 当将action.destructive_requires_name设置为true时,执行危险操作时需要在请求中显式指定操作名称,以增加操作的安全性。

    • 指定操作名称是一种避免意外执行危险操作的措施,因为它需要更明确的意图才能执行这些操作。

    • 通过设置action.destructive_requires_nametrue可以帮助防止意外的数据丢失或集群不可用,但同时需要确保在需要执行危险操作时能够正确指定操作名称。

    确保在配置 Elasticsearch 节点时,根据实际需求和安全要求,正确设置action.destructive_requires_name 选项,以控制在执行危险操作时是否要求显式指定操作名称。这有助于提高操作的安全性和可靠性。

    xpack.security.enabled

    xpack.security.enabled是 Elasticsearch 配置文件中的一个选项,用于启用或禁用 Elasticsearch 的安全功能(X-Pack Security)。

    以下是对xpack.security.enabled选项的详细解释:

    xpack.security.enabled: true
    • 1
    • xpack.security.enabled用于启用或禁用 Elasticsearch 的安全功能。默认情况下,它的值是false,即未启用安全功能。

    • 当将xpack.security.enabled设置为true时,Elasticsearch 将启用安全功能,包括身份验证、授权、加密通信等。

    • 启用安全功能可以保护 Elasticsearch 集群免受未经授权的访问,并提供更安全的数据传输和操作。

    • 要启用安全功能,您需要安装和配置 X-Pack Security 插件,并设置适当的身份验证和授权机制,如内置用户、角色、权限等。

    • 请注意,启用安全功能会对性能产生一定的影响,因为它会增加身份验证和授权的开销,并引入加密和解密的开销。

    确保在配置 Elasticsearch 节点时,根据实际需求和安全要求,正确设置xpack.security.enabled 选项,以启用或禁用 Elasticsearch 的安全功能。请确保在启用安全功能之前,正确安装和配置 X-Pack Security 插件,并了解相关的身份验证和授权机制。

    xpack.security.authc.api_key.enabled

    xpack.security.authc.api_key.enabled是 Elasticsearch 配置文件中的一个选项,用于启用或禁用 API 密钥身份验证方式。

    以下是对xpack.security.authc.api_key.enabled选项的详细解释:

    xpack.security.authc.api_key.enabled: true
    • 1
    • xpack.security.authc.api_key.enabled用于启用或禁用 API 密钥身份验证方式。默认情况下,它的值是false,即禁用 API 密钥身份验证。

    • 当将xpack.security.authc.api_key.enabled设置为true时,Elasticsearch 将启用 API 密钥身份验证方式。

    • API 密钥是一种轻量级的身份验证方式,它允许客户端使用预生成的密钥来进行身份验证,而无需提供用户名和密码。

    • 启用 API 密钥身份验证可以在不暴露实际用户名和密码的情况下,为客户端提供一种安全的身份验证方式。

    • 要使用 API 密钥身份验证,需要创建和管理 API 密钥,并为客户端提供相应的密钥和权限。

    • 请注意,启用 API 密钥身份验证方式需要启用 X-Pack Security 功能,并进行适当的配置。

    确保在配置 Elasticsearch 节点时,根据实际需求和安全要求,正确设置xpack.security.authc.api_key.enabled 选项,以启用或禁用 API 密钥身份验证方式。请确保在启用 API 密钥身份验证之前,正确配置和管理 API 密钥,并了解相关的权限和安全机制。

    logger.org.elasticsearch.transport

    logger.org.elasticsearch.transport是 Elasticsearch 配置文件中用于配置 Elasticsearch 传输模块的日志记录器。

    以下是对logger.org.elasticsearch.transport的详细解释:

    logger.org.elasticsearch.transport: debug
    • 1
    • logger.org.elasticsearch.transport用于配置 Elasticsearch 传输模块的日志记录级别。默认情况下,它的值是info

    • 通过设置不同的日志记录级别,可以控制 Elasticsearch 传输模块产生的日志消息的详细程度。

    • 可用的日志记录级别包括:tracedebuginfowarnerror。级别从最详细的trace到最简要的error逐渐减少。

    • 设置logger.org.elasticsearch.transport的值为debug将启用详细的调试日志记录,有助于追踪和调试与传输模块相关的问题。

    • 请注意,启用详细的日志记录级别可能会产生大量的日志输出,因此在生产环境中应谨慎使用,并根据需要进行调整。

    确保在配置 Elasticsearch 节点时,根据实际需求和调试要求,正确设置logger.org.elasticsearch.transport 选项,以配置 Elasticsearch 传输模块的日志记录级别。请注意在生产环境中谨慎使用详细的日志记录级别,以避免过多的日志输出。

    本文由 mdnice 多平台发布

  • 相关阅读:
    巧记大小端字节序
    Latte:一个类似Sora的开源视频生成项目
    FPGA----ZCU106基于axi-hp通道的pl与ps数据交互(全网唯一最详)
    67基于matlab图像处理,包括颜色和亮度调整、翻转功能、空间滤波和去噪、频域滤波和去噪、噪声添加,形态学操作、边缘检测及示波器集成的GUI图像处理。
    wpf主页面解析
    2023年11月IDE流行度最新排名
    【前端设计模式】之发布订阅模式
    深度学习YOLOv4环境配置
    vue重修之Vuex【下部】
    DSPE-PEG-Azide,DSPE-PEG-N3,磷脂-聚乙二醇-叠氮可和DBCO直接反应
  • 原文地址:https://blog.csdn.net/njpkhuan/article/details/132656732