update docs

pull/2/head
Zhang Peng 2020-06-16 07:10:44 +08:00
parent 157d49d74c
commit 3acc61e12d
30 changed files with 4039 additions and 65 deletions

View File

@ -53,7 +53,6 @@
- [Redis 复制](docs/nosql/redis/redis-replication.md)
- [Redis 哨兵](docs/nosql/redis/redis-sentinel.md)
- [Redis 集群](docs/nosql/redis/redis-cluster.md)
- [Redis 事务](docs/nosql/redis/redis-transaction.md)
- [Redis 发布与订阅](docs/nosql/redis/redis-pub-sub.md)
- [Redis 运维](docs/nosql/redis/redis-ops.md) 🔨
@ -106,6 +105,6 @@
- [CRUG | Redisson PRO vs. Jedis: Which Is Faster? 翻译](https://www.jianshu.com/p/82f0d5abb002)
- [redis 分布锁 Redisson 性能测试](https://blog.csdn.net/everlasting_188/article/details/51073505)
## 🚪 传送
## 🚪 传送
◾ 🏠 [LINUX-TUTORIAL 首页](https://github.com/dunwu/linux-tutorial) ◾ 🎯 [我的博客](https://github.com/dunwu/blog) ◾

Binary file not shown.

Binary file not shown.

View File

@ -54,7 +54,6 @@ footer: CC-BY-SA-4.0 Licensed | Copyright © 2018-Now Dunwu
- [Redis 复制](nosql/redis/redis-replication.md)
- [Redis 哨兵](nosql/redis/redis-sentinel.md)
- [Redis 集群](nosql/redis/redis-cluster.md)
- [Redis 事务](nosql/redis/redis-transaction.md)
- [Redis 发布与订阅](nosql/redis/redis-pub-sub.md)
- [Redis 运维](nosql/redis/redis-ops.md) 🔨
@ -110,3 +109,10 @@ footer: CC-BY-SA-4.0 Licensed | Copyright © 2018-Now Dunwu
## 🚪 传送门
◾ 🏠 [LINUX-TUTORIAL 首页](https://github.com/dunwu/linux-tutorial) ◾ 🎯 [我的博客](https://github.com/dunwu/blog) ◾

View File

@ -0,0 +1,58 @@
# Java 和搜索引擎
## 📖 内容
### ElasticSearch
> [ElasticSearch](https://www.elastic.co/products/elasticsearch) 是一个基于 [Lucene](http://lucene.apache.org/core/documentation.html) 构建的开源分布式RESTful 搜索引擎。
- [ElasticSearch 入门指南](elasticsearch/elasticsearch.md)
- [ElasticSearch 运维](nosql/elasticsearch/elasticsearch-ops.md)
### Elastic 技术栈
> **Elastic 技术栈通常被用来作为日志采集、检索、可视化解决方案。**
>
> ELK 是 elastic 公司旗下三款产品 [ElasticSearch](https://www.elastic.co/products/elasticsearch) 、[Logstash](https://www.elastic.co/products/logstash) 、[Kibana](https://www.elastic.co/products/kibana) 的首字母组合。
>
> [Logstash](https://www.elastic.co/products/logstash) 传输和处理你的日志、事务或其他数据。
>
> [Kibana](https://www.elastic.co/products/kibana) 将 Elasticsearch 的数据分析并渲染为可视化的报表。
>
> Elastic 技术栈,在 ELK 的基础上扩展了一些新的产品,如:[Beats](https://www.elastic.co/products/beats) 、[X-Pack](https://www.elastic.co/products/x-pack) 。
- [Elastic 技术栈快速入门](nosql/elasticsearch/elastic/elastic-quickstart.md)
- [Beats 入门指南](nosql/elasticsearch/elastic/elastic-beats.md)
- [Beats 运维](nosql/elasticsearch/elastic/elastic-beats-ops.md)
- [Kibana 入门指南](nosql/elasticsearch/elastic/elastic-kibana.md)
- [Kibana 运维](nosql/elasticsearch/elastic/elastic-kibana-ops.md)
- [Logstash 入门指南](nosql/elasticsearch/elastic/elastic-logstash.md)
- [Logstash 运维](nosql/elasticsearch/elastic/elastic-logstash-ops.md)
## 📚 资料
- **官方**
- [Elasticsearch 官网](https://www.elastic.co/cn/products/elasticsearch)
- [Elasticsearch Github](https://github.com/elastic/elasticsearch)
- [Elasticsearch 官方文档](https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html)
- [Logstash 官网](https://www.elastic.co/cn/products/logstash)
- [Logstash Github](https://github.com/elastic/logstash)
- [Logstash 官方文档](https://www.elastic.co/guide/en/logstash/current/index.html)
- [Kibana 官网](https://www.elastic.co/cn/products/kibana)
- [Kibana Github](https://github.com/elastic/kibana)
- [Kibana 官方文档](https://www.elastic.co/guide/en/kibana/current/index.html)
- [Beats 官网](https://www.elastic.co/cn/products/beats)
- [Beats Github](https://github.com/elastic/beats)
- [Beats 官方文档](https://www.elastic.co/guide/en/beats/libbeat/current/index.html)
- **第三方工具**
- [logstash-logback-encoder](https://github.com/logstash/logstash-logback-encoder)
- **教程**
- [Elasticsearch 权威指南(中文版)](https://es.xiaoleilu.com/index.html)
- [ELK Stack 权威指南](https://github.com/chenryn/logstash-best-practice-cn)
- **博文**
- [Elasticsearch+Logstash+Kibana 教程](https://www.cnblogs.com/xing901022/p/4704319.html)
- [ELKElasticsearch、Logstash、Kibana安装和配置](https://github.com/judasn/Linux-Tutorial/blob/master/ELK-Install-And-Settings.md)
## 🚪 传送
◾ 🏠 [JAVACORE 首页](https://github.com/dunwu/javatech) ◾ 🎯 [我的博客](https://github.com/dunwu/blog) ◾

View File

@ -0,0 +1,238 @@
# Filebeat 运维
> Beats 平台集合了多种单一用途数据采集器。它们从成百上千或成千上万台机器和系统向 Logstash 或 Elasticsearch 发送数据。
>
> 因为我只接触过 Filebeat所有本文仅介绍 Filebeat 的日常运维。
## 1. Filebeat 安装
### 1.1. 环境要求
> 版本Elastic Stack 7.4
### 1.2. 安装步骤
Unix / Linux 系统建议使用下面方式安装,因为比较通用。
```
wget https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-6.1.1-linux-x86_64.tar.gz
tar -zxf filebeat-6.1.1-linux-x86_64.tar.gz
```
> 更多内容可以参考:[filebeat-installation](https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-installation.html)
## 2. Filebeat 配置
> 首先,必须要知道的是:`filebeat.yml` 是 filebeat 的配置文件。其路径会因为你安装方式而有所不同。
>
> Beat 所有系列产品的配置文件都基于 [YAML](http://www.yaml.org/) 格式FileBeat 当然也不例外。
>
> 更多 filebeat 配置内容可以参考:[配置 filebeat](https://www.elastic.co/guide/en/beats/filebeat/current/configuring-howto-filebeat.html)
>
> 更多 filebeat.yml 文件格式内容可以参考:[filebeat.yml 文件格式](https://www.elastic.co/guide/en/beats/libbeat/6.1/config-file-format.html)
filebeat.yml 部分配置示例:
```yml
filebeat:
prospectors:
- type: log
paths:
- /var/log/*.log
multiline:
pattern: '^['
match: after
```
### 2.1. 重要配置项
> 下面我将列举 Filebeat 的较为重要的配置项。
>
> 如果想了解更多配置信息,可以参考:
>
> 更多 filebeat 配置内容可以参考:[配置 filebeat](https://www.elastic.co/guide/en/beats/filebeat/current/configuring-howto-filebeat.html)
>
> 更多 filebeat.yml 文件格式内容可以参考:[filebeat.yml 文件格式](https://www.elastic.co/guide/en/beats/libbeat/6.1/config-file-format.html)
#### 2.1.1. filebeat.prospectors
(文件监视器)用于指定需要关注的文件。
**示例**
```yaml
filebeat.prospectors:
- type: log
enabled: true
paths:
- /var/log/*.log
```
#### 2.1.2. output.elasticsearch
如果你希望使用 filebeat 直接向 elasticsearch 输出数据,需要配置 output.elasticsearch 。
**示例**
```yaml
output.elasticsearch:
hosts: ['192.168.1.42:9200']
```
#### 2.1.3. output.logstash
如果你希望使用 filebeat 向 logstash 输出数据,然后由 logstash 再向 elasticsearch 输出数据,需要配置 output.logstash。
> **注意**
>
> 相比于向 elasticsearch 输出数据,个人更推荐向 logstash 输出数据。
>
> 因为 logstash 和 filebeat 一起工作时,如果 logstash 忙于处理数据,会通知 FileBeat 放慢读取速度。一旦拥塞得到解决FileBeat 将恢复到原来的速度并继续传播。这样,可以减少管道超负荷的情况。
**示例**
```yaml
output.logstash:
hosts: ['127.0.0.1:5044']
```
此外,还需要在 logstash 的配置文件(如 logstash.conf中指定 beats input 插件:
```yaml
input {
beats {
port => 5044 # 此端口需要与 filebeat.yml 中的端口相同
}
}
# The filter part of this file is commented out to indicate that it is
# optional.
# filter {
#
# }
output {
elasticsearch {
hosts => "localhost:9200"
manage_template => false
index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}"
document_type => "%{[@metadata][type]}"
}
}
```
#### 2.1.4. setup.kibana
如果打算使用 Filebeat 提供的 Kibana 仪表板,需要配置 setup.kibana 。
**示例**
```yaml
setup.kibana:
host: 'localhost:5601'
```
#### 2.1.5. setup.template.settings
在 Elasticsearch 中,[索引模板](https://www.elastic.co/guide/en/elasticsearch/reference/6.1/indices-templates.html)用于定义设置和映射,以确定如何分析字段。
在 Filebeat 中setup.template.settings 用于配置索引模板。
Filebeat 推荐的索引模板文件由 Filebeat 软件包安装。如果您接受 filebeat.yml 配置文件中的默认配置Filebeat 在成功连接到 Elasticsearch 后自动加载模板。
您可以通过在 Filebeat 配置文件中配置模板加载选项来禁用自动模板加载,或加载自己的模板。您还可以设置选项来更改索引和索引模板的名称。
> **参考**
>
> 更多内容可以参考:[filebeat-template](https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-template.html)
>
> **说明**
>
> 如无必要,使用 Filebeat 配置文件中的默认索引模板即可。
#### 2.1.6. setup.dashboards
Filebeat 附带了示例 Kibana 仪表板。在使用仪表板之前,您需要创建索引模式 `filebeat- *`,并将仪表板加载到 Kibana 中。为此,您可以运行 `setup` 命令或在 `filebeat.yml` 配置文件中配置仪表板加载。
为了在 Kibana 中加载 Filebeat 的仪表盘,需要在 `filebeat.yml` 配置中启动开关:
```
setup.dashboards.enabled: true
```
> **参考**
>
> 更多内容可以参考:[configuration-dashboards](https://www.elastic.co/guide/en/beats/filebeat/current/configuration-dashboards.html)
## 3. Filebeat 命令
filebeat 提供了一系列命令来完成各种功能。
执行命令方式:
```bash
./filebeat COMMAND
```
> **参考**
>
> 更多内容可以参考:[command-line-options](https://www.elastic.co/guide/en/beats/filebeat/current/command-line-options.html)
>
> **说明**
>
> 个人认为命令行没有必要一一掌握,因为绝大部分功能都可以通过配置来完成。且通过命令行指定功能这种方式要求每次输入同样参数,不利于固化启动方式。
>
> 最重要的当然是启动命令 run 了。
>
> **示例** 指定配置文件启动
>
> ```bash
> ./filebeat run -e -c filebeat.yml -d "publish"
> ./filebeat -e -c filebeat.yml -d "publish" # run 可以省略
> ```
## 4. Filebeat 模块
> [Filebeat](https://www.elastic.co/cn/products/beats/filebeat) 和 [Metricbeat](https://www.elastic.co/cn/products/beats/metricbeat) 内部集成了一系列模块,用以简化常见日志格式(例如 NGINX、Apache 或诸如 Redis 或 Docker 等系统指标)的收集、解析和可视化过程。
- 配置 elasticsearch 和 kibana
```
output.elasticsearch:
hosts: ["myEShost:9200"]
username: "elastic"
password: "elastic"
setup.kibana:
host: "mykibanahost:5601"
username: "elastic"
password: "elastic
```
> username 和 password 是可选的,如果不需要认证则不填。
- 初始化环境
执行下面命令filebeat 会加载推荐索引模板。
```
./filebeat setup -e
```
- 指定模块
执行下面命令,指定希望加载的模块。
```
./filebeat -e --modules system,nginx,mysql
```
> 更多内容可以参考:
>
> - [配置 filebeat 模块](https://www.elastic.co/guide/en/beats/filebeat/current/configuration-filebeat-modules.html)
> - [filebeat 支持模块](https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-modules.html)
## 5. 参考资料
- [Beats 官网](https://www.elastic.co/cn/products/beats)
- [Beats Github](https://github.com/elastic/beats)
- [Beats 官方文档](https://www.elastic.co/guide/en/beats/libbeat/current/index.html)

View File

@ -0,0 +1,295 @@
---
title: Elastic 技术栈之 Filebeat
date: 2017-01-03
categories:
- javatool
tags:
- java
- javatool
- log
- elastic
---
# Elastic 技术栈之 Filebeat
## 简介
Beats 是安装在服务器上的数据中转代理。
Beats 可以将数据直接传输到 Elasticsearch 或传输到 Logstash 。
![img](https://www.elastic.co/guide/en/beats/libbeat/current/images/beats-platform.png)
Beats 有多种类型,可以根据实际应用需要选择合适的类型。
常用的类型有:
- **Packetbeat**网络数据包分析器,提供有关您的应用程序服务器之间交换的事务的信息。
- **Filebeat**从您的服务器发送日志文件。
- **Metricbeat**是一个服务器监视代理程序,它定期从服务器上运行的操作系统和服务收集指标。
- **Winlogbeat**提供Windows事件日志。
> **参考**
>
> 更多 Beats 类型可以参考:[community-beats](https://www.elastic.co/guide/en/beats/libbeat/current/community-beats.html)
>
> **说明**
>
> 由于本人工作中只应用了 FileBeat所以后面内容仅介绍 FileBeat 。
### FileBeat 的作用
相比 LogstashFileBeat 更加轻量化。
在任何环境下,应用程序都有停机的可能性。 Filebeat 读取并转发日志行,如果中断,则会记住所有事件恢复联机状态时所在位置。
Filebeat带有内部模块auditdApacheNginxSystem和MySQL可通过一个指定命令来简化通用日志格式的收集解析和可视化。
FileBeat 不会让你的管道超负荷。FileBeat 如果是向 Logstash 传输数据,当 Logstash 忙于处理数据,会通知 FileBeat 放慢读取速度。一旦拥塞得到解决FileBeat 将恢复到原来的速度并继续传播。
![img](https://www.elastic.co/guide/en/beats/filebeat/current/images/filebeat.png)
## 安装
Unix / Linux 系统建议使用下面方式安装,因为比较通用。
```
wget https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-6.1.1-linux-x86_64.tar.gz
tar -zxf filebeat-6.1.1-linux-x86_64.tar.gz
```
> **参考**
>
> 更多内容可以参考:[filebeat-installation](https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-installation.html)
## 配置
### 配置文件
首先,需要知道的是:`filebeat.yml` 是 filebeat 的配置文件。配置文件的路径会因为你安装方式的不同而变化。
Beat 所有系列产品的配置文件都基于 [YAML](http://www.yaml.org/) 格式FileBeat 当然也不例外。
filebeat.yml 部分配置示例:
```yaml
filebeat:
prospectors:
- type: log
paths:
- /var/log/*.log
multiline:
pattern: '^['
match: after
```
> **参考**
>
> 更多 filebeat 配置内容可以参考:[配置 filebeat](https://www.elastic.co/guide/en/beats/filebeat/current/configuring-howto-filebeat.html)
>
> 更多 filebeat.yml 文件格式内容可以参考:[filebeat.yml 文件格式](https://www.elastic.co/guide/en/beats/libbeat/6.1/config-file-format.html)
### 重要配置项
#### filebeat.prospectors
(文件监视器)用于指定需要关注的文件。
**示例**
```yaml
filebeat.prospectors:
- type: log
enabled: true
paths:
- /var/log/*.log
```
#### output.elasticsearch
如果你希望使用 filebeat 直接向 elasticsearch 输出数据,需要配置 output.elasticsearch 。
**示例**
```yaml
output.elasticsearch:
hosts: ["192.168.1.42:9200"]
```
#### output.logstash
如果你希望使用 filebeat 向 logstash输出数据然后由 logstash 再向elasticsearch 输出数据,需要配置 output.logstash。
> **注意**
>
> 相比于向 elasticsearch 输出数据,个人更推荐向 logstash 输出数据。
>
> 因为 logstash 和 filebeat 一起工作时,如果 logstash 忙于处理数据,会通知 FileBeat 放慢读取速度。一旦拥塞得到解决FileBeat 将恢复到原来的速度并继续传播。这样,可以减少管道超负荷的情况。
**示例**
```yaml
output.logstash:
hosts: ["127.0.0.1:5044"]
```
此外,还需要在 logstash 的配置文件(如 logstash.conf中指定 beats input 插件:
```yaml
input {
beats {
port => 5044 # 此端口需要与 filebeat.yml 中的端口相同
}
}
# The filter part of this file is commented out to indicate that it is
# optional.
# filter {
#
# }
output {
elasticsearch {
hosts => "localhost:9200"
manage_template => false
index => "%{[@metadata][beat]}-%{[@metadata][version]}-%{+YYYY.MM.dd}"
document_type => "%{[@metadata][type]}"
}
}
```
#### setup.kibana
如果打算使用 Filebeat 提供的 Kibana 仪表板,需要配置 setup.kibana 。
**示例**
```yaml
setup.kibana:
host: "localhost:5601"
```
#### setup.template.settings
在 Elasticsearch 中,[索引模板](https://www.elastic.co/guide/en/elasticsearch/reference/6.1/indices-templates.html)用于定义设置和映射,以确定如何分析字段。
在 Filebeat 中setup.template.settings 用于配置索引模板。
Filebeat 推荐的索引模板文件由 Filebeat 软件包安装。如果您接受 filebeat.yml 配置文件中的默认配置Filebeat在成功连接到 Elasticsearch 后自动加载模板。
您可以通过在 Filebeat 配置文件中配置模板加载选项来禁用自动模板加载,或加载自己的模板。您还可以设置选项来更改索引和索引模板的名称。
> **参考**
>
> 更多内容可以参考:[filebeat-template](https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-template.html)
>
> **说明**
>
> 如无必要,使用 Filebeat 配置文件中的默认索引模板即可。
#### setup.dashboards
Filebeat 附带了示例 Kibana 仪表板。在使用仪表板之前,您需要创建索引模式 `filebeat- *`并将仪表板加载到Kibana 中。为此,您可以运行 `setup` 命令或在 `filebeat.yml` 配置文件中配置仪表板加载。
为了在 Kibana 中加载 Filebeat 的仪表盘,需要在 `filebeat.yml` 配置中启动开关:
```
setup.dashboards.enabled: true
```
> **参考**
>
> 更多内容可以参考:[configuration-dashboards](https://www.elastic.co/guide/en/beats/filebeat/current/configuration-dashboards.html)
>
## 命令
filebeat 提供了一系列命令来完成各种功能。
执行命令方式:
```bash
./filebeat COMMAND
```
> **参考**
>
> 更多内容可以参考:[command-line-options](https://www.elastic.co/guide/en/beats/filebeat/current/command-line-options.html)
>
> **说明**
>
> 个人认为命令行没有必要一一掌握,因为绝大部分功能都可以通过配置来完成。且通过命令行指定功能这种方式要求每次输入同样参数,不利于固化启动方式。
>
> 最重要的当然是启动命令 run 了。
>
> **示例** 指定配置文件启动
>
> ```bash
> ./filebeat run -e -c filebeat.yml -d "publish"
> ./filebeat -e -c filebeat.yml -d "publish" # run 可以省略
> ```
## 模块
Filebeat 提供了一套预构建的模块让您可以快速实施和部署日志监视解决方案并附带示例仪表板和数据可视化。这些模块支持常见的日志格式例如NginxApache2和MySQL 等。
### 运行模块的步骤
- 配置 elasticsearch 和 kibana
```
output.elasticsearch:
hosts: ["myEShost:9200"]
username: "elastic"
password: "elastic"
setup.kibana:
host: "mykibanahost:5601"
username: "elastic"
password: "elastic
```
> username 和 password 是可选的,如果不需要认证则不填。
- 初始化环境
执行下面命令filebeat 会加载推荐索引模板。
```
./filebeat setup -e
```
- 指定模块
执行下面命令,指定希望加载的模块。
```
./filebeat -e --modules system,nginx,mysql
```
> **参考**
>
> 更多内容可以参考: [配置 filebeat 模块](https://www.elastic.co/guide/en/beats/filebeat/current/configuration-filebeat-modules.html) | [filebeat 支持模块](https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-modules.html)
## 原理
Filebeat 有两个主要组件:
harvester负责读取一个文件的内容。它会逐行读取文件内容并将内容发送到输出目的地。
prospector负责管理 harvester 并找到所有需要读取的文件源。比如类型是日志prospector 就会遍历制定路径下的所有匹配要求的文件。
```yaml
filebeat.prospectors:
- type: log
paths:
- /var/log/*.log
- /var/path2/*.log
```
Filebeat保持每个文件的状态并经常刷新注册表文件中的磁盘状态。状态用于记住 harvester 正在读取的最后偏移量,并确保发送所有日志行。
Filebeat 将每个事件的传递状态存储在注册表文件中。所以它能保证事件至少传递一次到配置的输出,没有数据丢失。
## 资料
[Beats 官方文档](https://www.elastic.co/guide/en/beats/libbeat/current/index.html)

View File

@ -0,0 +1,346 @@
# Kibana 运维
> 通过 Kibana您可以对自己的 Elasticsearch 进行可视化,还可以在 Elastic Stack 中进行导航,这样您便可以进行各种操作了,从跟踪查询负载,到理解请求如何流经您的整个应用,都能轻松完成。
## 1. 安装
### 1.1. 环境要求
> 版本Elastic Stack 7.4
### 1.2. 安装步骤
安装步骤如下:
1. 在 [kibana 官方下载地址](https://www.elastic.co/downloads/kibana)下载所需版本包并解压到本地。
2. 修改 `config/kibana.yml` 配置文件,设置 `elasticsearch.url` 指向 Elasticsearch 实例。
3. 运行 `bin/kibana` Windows 上运行 `bin\kibana.bat`
4. 在浏览器上访问 <http://localhost:5601>
## 2. 使用
### 2.1. 检索
单击侧面导航栏中的 `检索Discover` ,可以显示 `Kibana` 的数据查询功能功能。
![img](https://www.elastic.co/guide/en/kibana/current/images/tutorial-discover.png)
在搜索栏中,您可以输入 Elasticsearch 查询条件来搜索您的数据。您可以在 `Discover` 页面中浏览结果并在 `Visualize` 页面中创建已保存搜索条件的可视化。
当前索引模式显示在查询栏下方。索引模式确定提交查询时搜索哪些索引。要搜索一组不同的索引请从下拉菜单中选择不同的模式。要添加索引模式index pattern请转至 `Management/Kibana/Index Patterns` 并单击 `Add New`
您可以使用字段名称和您感兴趣的值构建搜索。对于数字字段,可以使用比较运算符,如大于(>),小于(<)或等于(=)。您可以将元素与逻辑运算符 `AND``OR` 和 `NOT` 链接,全部使用大写。
默认情况下,每个匹配文档都显示所有字段。要选择要显示的文档字段,请将鼠标悬停在“可用字段”列表上,然后单击要包含的每个字段旁边的添加按钮。例如,如果只添加 account_number则显示将更改为包含五个帐号的简单列表
![img](https://www.elastic.co/guide/en/kibana/6.1/images/tutorial-discover-3.png)
kibana 的搜索栏遵循 [query-string-syntax](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html#query-string-syntax) 文档中所说明的查询语义。
这里说明一些最基本的查询语义。
查询字符串会被解析为一系列的术语和运算符。一个术语可以是一个单词quick、brown或用双引号包围的短语如"quick brown")。
查询操作允许您自定义搜索 - 下面介绍了可用的选项。
#### 2.1.1. 字段名称
正如查询字符串查询中所述,将在搜索条件中搜索 default_field但可以在查询语法中指定其他字段
例如:
- 查询 `status` 字段中包含 `active` 关键字
```
status:active
```
- `title` 字段包含 `quick``brown` 关键字。如果您省略 `OR` 运算符,则将使用默认运算符
```
title:(quick OR brown)
title:(quick brown)
```
- author 字段查找精确的短语 "john smith",即精确查找。
```
author:"John Smith"
```
- 任意字段 `book.title``book.content` 或 `book.date` 都包含 `quick``brown`(注意我们需要如何使用 `\*` 表示通配符)
```
book.\*:(quick brown)
```
- title 字段包含任意非 null 值
```
_exists_:title
```
#### 2.1.2. 通配符
ELK 提供了 ? 和 \* 两个通配符。
- `?` 表示任意单个字符;
- `*` 表示任意零个或多个字符。
```
qu?ck bro*
```
> **注意:通配符查询会使用大量的内存并且执行性能较为糟糕,所以请慎用。** > **提示**:纯通配符 \* 被写入 [exsits](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-exists-query.html) 查询,从而提高了查询效率。因此,通配符 `field*` 将匹配包含空值的文档,如:`{“field”“”}`,但是如果字段丢失或显示将值置为 null 则不匹配,如:`“field”null}` > **提示**:在一个单词的开头(例如:`*ing`)使用通配符这种方式的查询量特别大,因为索引中的所有术语都需要检查,以防万一匹配。通过将 `allow_leading_wildcard` 设置为 `false`,可以禁用。
#### 2.1.3. 正则表达式
可以通过 `/` 将正则表达式包裹在查询字符串中进行查询
例:
```
name:/joh?n(ath[oa]n)/
```
支持的正则表达式语义可以参考:[Regular expression syntax](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-regexp-query.html#regexp-syntax)
#### 2.1.4. 模糊查询
我们可以使用 `~` 运算符来进行模糊查询。
例:
假设我们实际想查询
```
quick brown forks
```
但是,由于拼写错误,我们的查询关键字变成如下情况,依然可以查到想要的结果。
```
quikc\~ brwn\~ foks\~
```
这种模糊查询使用 Damerau-Levenshtein 距离来查找所有匹配最多两个更改的项。所谓的更改是指单个字符的插入,删除或替换,或者两个相邻字符的换位。
默认编辑距离为 `2`,但编辑距离为 `1` 应足以捕捉所有人类拼写错误的 80。它可以被指定为
```
quikc\~1
```
#### 2.1.5. 近似检索
尽管短语查询(例如,`john smith`)期望所有的词条都是完全相同的顺序,但是近似查询允许指定的单词进一步分开或以不同的顺序排列。与模糊查询可以为单词中的字符指定最大编辑距离一样,近似搜索也允许我们指定短语中单词的最大编辑距离:
```
"fox quick"\~5
```
字段中的文本越接近查询字符串中指定的原始顺序,该文档就越被认为是相关的。当与上面的示例查询相比时,短语 `"quick fox"` 将被认为比 `"quick brown fox"` 更近似查询条件。
#### 2.1.6. 范围
可以为日期,数字或字符串字段指定范围。闭区间范围用方括号 `[min TO max]` 和开区间范围用花括号 `{min TO max}` 来指定。
我们不妨来看一些示例。
- 2012 年的所有日子
```
date:[2012-01-01 TO 2012-12-31]
```
- 数字 1 到 5
```
count:[1 TO 5]
```
- 在 `alpha``omega` 之间的标签,不包括 `alpha``omega`
```
tag:{alpha TO omega}
```
- 10 以上的数字
```
count:[10 TO *]
```
- 2012 年以前的所有日期
```
date:{* TO 2012-01-01}
```
此外,开区间和闭区间也可以组合使用
- 数组 1 到 5但不包括 5
```
count:[1 TO 5}
```
一边无界的范围也可以使用以下语法:
```
age:>10
age:>=10
age:<10
age:<=10
```
当然,你也可以使用 AND 运算符来得到连个查询结果的交集
```
age:(>=10 AND <20)
age:(+>=10 +<20)
```
#### 2.1.7. Boosting
使用操作符 `^` 使一个术语比另一个术语更相关。例如,如果我们想查找所有有关狐狸的文档,但我们对狐狸特别感兴趣:
```
quick^2 fox
```
默认提升值是 1但可以是任何正浮点数。 0 到 1 之间的提升减少了相关性。
增强也可以应用于短语或组:
```
"john smith"^2 (foo bar)^4
```
#### 2.1.8. 布尔操作
默认情况下,只要一个词匹配,所有词都是可选的。搜索 `foo bar baz` 将查找包含 `foo``bar``baz` 中的一个或多个的任何文档。我们已经讨论了上面的`default_operator`,它允许你强制要求所有的项,但也有布尔运算符可以在查询字符串本身中使用,以提供更多的控制。
首选的操作符是 `+`(此术语必须存在)和 `-` (此术语不得存在)。所有其他条款是可选的。例如,这个查询:
```
quick brown +fox -news
```
这条查询意味着:
- fox 必须存在
- news 必须不存在
- quick 和 brown 是可有可无的
熟悉的运算符 `AND``OR` 和 `NOT`(也写成 `&&``||` 和 `!`)也被支持。然而,这些操作符有一定的优先级:`NOT` 优先于 `AND``AND` 优先于 `OR`。虽然 `+``-` 仅影响运算符右侧的术语,但 `AND``OR` 会影响左侧和右侧的术语。
#### 2.1.9. 分组
多个术语或子句可以用圆括号组合在一起,形成子查询
```
(quick OR brown) AND fox
```
可以使用组来定位特定的字段,或者增强子查询的结果:
```
status:(active OR pending) title:(full text search)^2
```
#### 2.1.10. 保留字
如果你需要使用任何在你的查询本身中作为操作符的字符而不是作为操作符那么你应该用一个反斜杠来转义它们。例如要搜索1 + 1= 2您需要将查询写为 `\(1\+1\)\=2`
保留字符是:`+ - = && || > < ! ( ) { } [ ] ^ " ~ * ? : \ /`
无法正确地转义这些特殊字符可能会导致语法错误,从而阻止您的查询运行。
#### 2.1.11. 空查询
如果查询字符串为空或仅包含空格,则查询将生成一个空的结果集。
### 2.2. 可视化
要想使用可视化的方式展示您的数据,请单击侧面导航栏中的 `可视化Visualize`
Visualize 工具使您能够以多种方式(如饼图、柱状图、曲线图、分布图等)查看数据。要开始使用,请点击蓝色的 `Create a visualization``+` 按钮。
![https://www.elastic.co/guide/en/kibana/6.1/images/tutorial-visualize-landing.png](https://www.elastic.co/guide/en/kibana/6.1/images/tutorial-visualize-landing.png)
有许多可视化类型可供选择。
![https://www.elastic.co/guide/en/kibana/6.1/images/tutorial-visualize-wizard-step-1.png](https://www.elastic.co/guide/en/kibana/6.1/images/tutorial-visualize-wizard-step-1.png)
下面,我们来看创建几个图标示例:
#### 2.2.1. Pie
您可以从保存的搜索中构建可视化文件,也可以输入新的搜索条件。要输入新的搜索条件,首先需要选择一个索引模式来指定要搜索的索引。
默认搜索匹配所有文档。最初,一个“切片”包含整个饼图:
![https://www.elastic.co/guide/en/kibana/6.1/images/tutorial-visualize-pie-1.png](https://www.elastic.co/guide/en/kibana/6.1/images/tutorial-visualize-pie-1.png)
要指定在图表中展示哪些数据,请使用 Elasticsearch 存储桶聚合。分组汇总只是将与您的搜索条件相匹配的文档分类到不同的分类中,也称为分组。
为每个范围定义一个存储桶:
1. 单击 `Split Slices`
2. 在 `Aggregation` 列表中选择 `Terms`。*注意:这里的 Terms 是 Elk 采集数据时定义好的字段或标签*。
3. 在 `Field` 列表中选择 `level.keyword`
4. 点击 ![images/apply-changes-button.png](https://www.elastic.co/guide/en/kibana/6.1/images/apply-changes-button.png) 按钮来更新图表。
![image.png](https://upload-images.jianshu.io/upload_images/3101171-7fb2042dc6d59520.png)
完成后,如果想要保存这个图表,可以点击页面最上方一栏中的 `Save` 按钮。
#### 2.2.2. Vertical Bar
我们在展示一下如何创建柱状图。
1. 点击蓝色的 `Create a visualization``+` 按钮。选择 `Vertical Bar`
2. 选择索引模式。由于您尚未定义任何 bucket ,因此您会看到一个大栏,显示与默认通配符查询匹配的文档总数。
3. 指定 Y 轴所代表的字段
4. 指定 X 轴所代表的字段
5. 点击 ![images/apply-changes-button.png](https://www.elastic.co/guide/en/kibana/6.1/images/apply-changes-button.png) 按钮来更新图表。
![image.png](https://upload-images.jianshu.io/upload_images/3101171-5aa7627284c19a56.png)
完成后,如果想要保存这个图表,可以点击页面最上方一栏中的 `Save` 按钮。
### 2.3. 报表
`报表Dashboard` 可以整合和共享 `Visualize` 集合。
1. 点击侧面导航栏中的 Dashboard。
2. 点击添加显示保存的可视化列表。
3. 点击之前保存的 `Visualize`,然后点击列表底部的小向上箭头关闭可视化列表。
4. 将鼠标悬停在可视化对象上会显示允许您编辑,移动,删除和调整可视化对象大小的容器控件。
## 3. FAQ
### 3.1. Kibana No Default Index Pattern Warning
**问题:**安装 ELK 后,访问 kibana 页面时,提示以下错误信息:
```
Warning No default index pattern. You must select or create one to continue.
...
Unable to fetch mapping. Do you have indices matching the pattern?
```
这就说明 logstash 没有把日志写入到 elasticsearch。
**解决方法:**
检查 logstash 与 elasticsearch 之间的通讯是否有问题,一般问题就出在这。
## 4. 参考资料
- [Kibana 官网](https://www.elastic.co/cn/products/kibana)
- [Kibana Github](https://github.com/elastic/kibana)
- [Kibana 官方文档](https://www.elastic.co/guide/en/kibana/current/index.html)

View File

@ -0,0 +1,305 @@
# Elastic 技术栈之 Kibana
## Discover
单击侧面导航栏中的 `Discover` ,可以显示 `Kibana` 的数据查询功能功能。
![img](https://www.elastic.co/guide/en/kibana/current/images/tutorial-discover.png)
在搜索栏中,您可以输入 Elasticsearch 查询条件来搜索您的数据。您可以在 `Discover` 页面中浏览结果并在 `Visualize` 页面中创建已保存搜索条件的可视化。
当前索引模式显示在查询栏下方。索引模式确定提交查询时搜索哪些索引。要搜索一组不同的索引请从下拉菜单中选择不同的模式。要添加索引模式index pattern请转至 `Management/Kibana/Index Patterns` 并单击 `Add New`
您可以使用字段名称和您感兴趣的值构建搜索。对于数字字段,可以使用比较运算符,如大于(>),小于(<)或等于(=)。您可以将元素与逻辑运算符 `AND``OR` 和 `NOT` 链接,全部使用大写。
默认情况下,每个匹配文档都显示所有字段。要选择要显示的文档字段,请将鼠标悬停在“可用字段”列表上,然后单击要包含的每个字段旁边的添加按钮。例如,如果只添加 account_number则显示将更改为包含五个帐号的简单列表
![img](https://www.elastic.co/guide/en/kibana/6.1/images/tutorial-discover-3.png)
### 查询语义
kibana 的搜索栏遵循 [query-string-syntax](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html#query-string-syntax) 文档中所说明的查询语义。
这里说明一些最基本的查询语义。
查询字符串会被解析为一系列的术语和运算符。一个术语可以是一个单词quick、brown或用双引号包围的短语如"quick brown")。
查询操作允许您自定义搜索 - 下面介绍了可用的选项。
#### 字段名称
正如查询字符串查询中所述,将在搜索条件中搜索 default_field但可以在查询语法中指定其他字段
例如:
- 查询 `status` 字段中包含 `active` 关键字
```
status:active
```
- `title` 字段包含 `quick``brown` 关键字。如果您省略 `OR` 运算符,则将使用默认运算符
```
title:(quick OR brown)
title:(quick brown)
```
- author 字段查找精确的短语 "john smith",即精确查找。
```
author:"John Smith"
```
- 任意字段 `book.title``book.content` 或 `book.date` 都包含 `quick``brown`(注意我们需要如何使用 `\*` 表示通配符)
```
book.\*:(quick brown)
```
- title 字段包含任意非 null 值
```
_exists_:title
```
#### 通配符
ELK 提供了 ? 和 \* 两个通配符。
- `?` 表示任意单个字符;
- `*` 表示任意零个或多个字符。
```
qu?ck bro*
```
> **注意:通配符查询会使用大量的内存并且执行性能较为糟糕,所以请慎用。** > **提示**:纯通配符 `*` 被写入 [exsits](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-exists-query.html) 查询,从而提高了查询效率。因此,通配符 `field*` 将匹配包含空值的文档,如:`{“field”“”}`,但是如果字段丢失或显示将值置为 null 则不匹配,如:`“field”null}` > **提示**:在一个单词的开头(例如:`*ing`)使用通配符这种方式的查询量特别大,因为索引中的所有术语都需要检查,以防万一匹配。通过将 `allow_leading_wildcard` 设置为 `false`,可以禁用。
#### 正则表达式
可以通过 `/` 将正则表达式包裹在查询字符串中进行查询
例:
```
name:/joh?n(ath[oa]n)/
```
支持的正则表达式语义可以参考:[Regular expression syntax](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-regexp-query.html#regexp-syntax)
#### 模糊查询
我们可以使用 `~` 运算符来进行模糊查询。
例:
假设我们实际想查询
```
quick brown forks
```
但是,由于拼写错误,我们的查询关键字变成如下情况,依然可以查到想要的结果。
```
quikc\~ brwn\~ foks\~
```
这种模糊查询使用 Damerau-Levenshtein 距离来查找所有匹配最多两个更改的项。所谓的更改是指单个字符的插入,删除或替换,或者两个相邻字符的换位。
默认编辑距离为 `2`,但编辑距离为 `1` 应足以捕捉所有人类拼写错误的 80。它可以被指定为
```
quikc\~1
```
#### 近似检索
尽管短语查询(例如,`john smith`)期望所有的词条都是完全相同的顺序,但是近似查询允许指定的单词进一步分开或以不同的顺序排列。与模糊查询可以为单词中的字符指定最大编辑距离一样,近似搜索也允许我们指定短语中单词的最大编辑距离:
```
"fox quick"\~5
```
字段中的文本越接近查询字符串中指定的原始顺序,该文档就越被认为是相关的。当与上面的示例查询相比时,短语 `"quick fox"` 将被认为比 `"quick brown fox"` 更近似查询条件。
#### 范围
可以为日期,数字或字符串字段指定范围。闭区间范围用方括号 `[min TO max]` 和开区间范围用花括号 `{min TO max}` 来指定。
我们不妨来看一些示例。
- 2012 年的所有日子
```
date:[2012-01-01 TO 2012-12-31]
```
- 数字 1 到 5
```
count:[1 TO 5]
```
- 在 `alpha``omega` 之间的标签,不包括 `alpha``omega`
```
tag:{alpha TO omega}
```
- 10 以上的数字
```
count:[10 TO *]
```
- 2012 年以前的所有日期
```
date:{* TO 2012-01-01}
```
此外,开区间和闭区间也可以组合使用
- 数组 1 到 5但不包括 5
```
count:[1 TO 5}
```
一边无界的范围也可以使用以下语法:
```
age:>10
age:>=10
age:<10
age:<=10
```
当然,你也可以使用 AND 运算符来得到连个查询结果的交集
```
age:(>=10 AND <20)
age:(+>=10 +<20)
```
#### Boosting
使用操作符 `^` 使一个术语比另一个术语更相关。例如,如果我们想查找所有有关狐狸的文档,但我们对狐狸特别感兴趣:
```
quick^2 fox
```
默认提升值是 1但可以是任何正浮点数。 0 到 1 之间的提升减少了相关性。
增强也可以应用于短语或组:
```
"john smith"^2 (foo bar)^4
```
#### 布尔操作
默认情况下,只要一个词匹配,所有词都是可选的。搜索 `foo bar baz` 将查找包含 `foo``bar``baz` 中的一个或多个的任何文档。我们已经讨论了上面的`default_operator`,它允许你强制要求所有的项,但也有布尔运算符可以在查询字符串本身中使用,以提供更多的控制。
首选的操作符是 `+`(此术语必须存在)和 `-` (此术语不得存在)。所有其他条款是可选的。例如,这个查询:
```
quick brown +fox -news
```
这条查询意味着:
- fox 必须存在
- news 必须不存在
- quick 和 brown 是可有可无的
熟悉的运算符 `AND``OR` 和 `NOT`(也写成 `&&``||` 和 `!`)也被支持。然而,这些操作符有一定的优先级:`NOT` 优先于 `AND``AND` 优先于 `OR`。虽然 `+``-` 仅影响运算符右侧的术语,但 `AND``OR` 会影响左侧和右侧的术语。
#### 分组
多个术语或子句可以用圆括号组合在一起,形成子查询
```
(quick OR brown) AND fox
```
可以使用组来定位特定的字段,或者增强子查询的结果:
```
status:(active OR pending) title:(full text search)^2
```
#### 保留字
如果你需要使用任何在你的查询本身中作为操作符的字符而不是作为操作符那么你应该用一个反斜杠来转义它们。例如要搜索1 + 1= 2您需要将查询写为 `\(1\+1\)\=2`
保留字符是:`+ - = && || > < ! ( ) { } [ ] ^ " ~ * ? : \ /`
无法正确地转义这些特殊字符可能会导致语法错误,从而阻止您的查询运行。
#### 空查询
如果查询字符串为空或仅包含空格,则查询将生成一个空的结果集。
## Visualize
要想使用可视化的方式展示您的数据,请单击侧面导航栏中的 `Visualize`
Visualize 工具使您能够以多种方式(如饼图、柱状图、曲线图、分布图等)查看数据。要开始使用,请点击蓝色的 `Create a visualization``+` 按钮。
![https://www.elastic.co/guide/en/kibana/6.1/images/tutorial-visualize-landing.png](https://www.elastic.co/guide/en/kibana/6.1/images/tutorial-visualize-landing.png)
有许多可视化类型可供选择。
![https://www.elastic.co/guide/en/kibana/6.1/images/tutorial-visualize-wizard-step-1.png](https://www.elastic.co/guide/en/kibana/6.1/images/tutorial-visualize-wizard-step-1.png)
下面,我们来看创建几个图标示例:
### Pie
您可以从保存的搜索中构建可视化文件,也可以输入新的搜索条件。要输入新的搜索条件,首先需要选择一个索引模式来指定要搜索的索引。
默认搜索匹配所有文档。最初,一个“切片”包含整个饼图:
![https://www.elastic.co/guide/en/kibana/6.1/images/tutorial-visualize-pie-1.png](https://www.elastic.co/guide/en/kibana/6.1/images/tutorial-visualize-pie-1.png)
要指定在图表中展示哪些数据,请使用 Elasticsearch 存储桶聚合。分组汇总只是将与您的搜索条件相匹配的文档分类到不同的分类中,也称为分组。
为每个范围定义一个存储桶:
1. 单击 `Split Slices`
2. 在 `Aggregation` 列表中选择 `Terms`。*注意:这里的 Terms 是 Elk 采集数据时定义好的字段或标签*。
3. 在 `Field` 列表中选择 `level.keyword`
4. 点击 ![images/apply-changes-button.png](https://www.elastic.co/guide/en/kibana/6.1/images/apply-changes-button.png) 按钮来更新图表。
![image.png](https://upload-images.jianshu.io/upload_images/3101171-7fb2042dc6d59520.png)
完成后,如果想要保存这个图表,可以点击页面最上方一栏中的 `Save` 按钮。
### Vertical Bar
我们在展示一下如何创建柱状图。
1. 点击蓝色的 `Create a visualization``+` 按钮。选择 `Vertical Bar`
2. 选择索引模式。由于您尚未定义任何 bucket ,因此您会看到一个大栏,显示与默认通配符查询匹配的文档总数。
3. 指定 Y 轴所代表的字段
4. 指定 X 轴所代表的字段
5. 点击 ![images/apply-changes-button.png](https://www.elastic.co/guide/en/kibana/6.1/images/apply-changes-button.png) 按钮来更新图表。
![image.png](https://upload-images.jianshu.io/upload_images/3101171-5aa7627284c19a56.png)
完成后,如果想要保存这个图表,可以点击页面最上方一栏中的 `Save` 按钮。
## Dashboard
`Dashboard` 可以整合和共享 `Visualize` 集合。
1. 点击侧面导航栏中的 Dashboard。
2. 点击添加显示保存的可视化列表。
3. 点击之前保存的 `Visualize`,然后点击列表底部的小向上箭头关闭可视化列表。
4. 将鼠标悬停在可视化对象上会显示允许您编辑,移动,删除和调整可视化对象大小的容器控件。

View File

@ -0,0 +1,495 @@
# Logstash 运维
> [Logstash](https://github.com/elastic/logstash) 是开源的服务器端数据处理管道,能够同时从多个来源采集数据,转换数据,然后将数据发送到您最喜欢的“存储库”中。
## 1. 安装
### 1.1. 安装步骤
安装步骤如下:
1在 [logstash 官方下载地址](https://www.elastic.co/downloads/logstash)下载所需版本包并解压到本地。
2添加一个 `logstash.conf` 文件,指定要使用的插件以及每个插件的设置。举个简单的例子:
```
input { stdin { } }
output {
elasticsearch { hosts => ["localhost:9200"] }
stdout { codec => rubydebug }
}
```
3运行 `bin/logstash -f logstash.conf` Windows 上运行`bin/logstash.bat -f logstash.conf`
## 2. 配置
### 2.1. 设置文件
- **`logstash.yml`**logstash 的默认启动配置文件
- **`jvm.options`**logstash 的 JVM 配置文件。
- **`startup.options`** (Linux):包含系统安装脚本在 `/usr/share/logstash/bin` 中使用的选项为您的系统构建适当的启动脚本。安装 Logstash 软件包时,系统安装脚本将在安装过程结束时执行,并使用 `startup.options` 中指定的设置来设置用户,组,服务名称和服务描述等选项。
### 2.2. logstash.yml 设置项
节选部分设置项,更多项请参考:<https://www.elastic.co/guide/en/logstash/current/logstash-settings-file.html>
| 参数 | 描述 | 默认值 |
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `node.name` | 节点名 | 机器的主机名 |
| `path.data` | Logstash 及其插件用于任何持久性需求的目录。 | `LOGSTASH_HOME/data` |
| `pipeline.workers` | 同时执行管道的过滤器和输出阶段的工作任务数量。如果发现事件正在备份,或 CPU 未饱和,请考虑增加此数字以更好地利用机器处理能力。 | Number of the hosts CPU cores |
| `pipeline.batch.size` | 尝试执行过滤器和输出之前,单个工作线程从输入收集的最大事件数量。较大的批量处理大小一般来说效率更高,但是以增加的内存开销为代价。您可能必须通过设置 `LS_HEAP_SIZE` 变量来有效使用该选项来增加 JVM 堆大小。 | `125` |
| `pipeline.batch.delay` | 创建管道事件批处理时,在将一个尺寸过小的批次发送给管道工作任务之前,等待每个事件需要多长时间(毫秒)。 | `5` |
| `pipeline.unsafe_shutdown` | 如果设置为 true则即使在内存中仍存在 inflight 事件时,也会强制 Logstash 在关闭期间退出。默认情况下Logstash 将拒绝退出,直到所有接收到的事件都被推送到输出。启用此选项可能会导致关机期间数据丢失。 | `false` |
| `path.config` | 主管道的 Logstash 配置路径。如果您指定一个目录或通配符,配置文件将按字母顺序从目录中读取。 | Platform-specific. See [[dir-layout\]](https://github.com/elastic/logstash/blob/6.1/docs/static/settings-file.asciidoc#dir-layout). |
| `config.string` | 包含用于主管道的管道配置的字符串。使用与配置文件相同的语法。 | None |
| `config.test_and_exit` | 设置为 true 时,检查配置是否有效,然后退出。请注意,使用此设置不会检查 grok 模式的正确性。 Logstash 可以从目录中读取多个配置文件。如果将此设置与 log.leveldebug 结合使用,则 Logstash 将记录组合的配置文件,并注掉其源文件的配置块。 | `false` |
| `config.reload.automatic` | 设置为 true 时,定期检查配置是否已更改,并在配置更改时重新加载配置。这也可以通过 SIGHUP 信号手动触发。 | `false` |
| `config.reload.interval` | Logstash 检查配置文件更改的时间间隔。 | `3s` |
| `config.debug` | 设置为 true 时,将完全编译的配置显示为调试日志消息。您还必须设置`log.leveldebug`。警告:日志消息将包括任何传递给插件配置作为明文的“密码”选项,并可能导致明文密码出现在您的日志! | `false` |
| `config.support_escapes` | 当设置为 true 时,带引号的字符串将处理转义字符。 | `false` |
| `modules` | 配置时,模块必须处于上表所述的嵌套 YAML 结构中。 | None |
| `http.host` | 绑定地址 | `"127.0.0.1"` |
| `http.port` | 绑定端口 | `9600` |
| `log.level` | 日志级别。有效选项fatal > error > warn > info > debug > trace | `info` |
| `log.format` | 日志格式。json JSON 格式)或 plain (原对象) | `plain` |
| `path.logs` | Logstash 自身日志的存储路径 | `LOGSTASH_HOME/logs` |
| `path.plugins` | 在哪里可以找到自定义的插件。您可以多次指定此设置以包含多个路径。 | |
## 3. 启动
### 3.1. 命令行
通过命令行启动 logstash 的方式如下:
```
bin/logstash [options]
```
其中 `options` 是您可以指定用于控制 Logstash 执行的命令行标志。
在命令行上设置的任何标志都会覆盖 Logstash 设置文件(`logstash.yml`)中的相应设置,但设置文件本身不会更改。
> **注**
>
> 虽然可以通过指定命令行参数的方式,来控制 logstash 的运行方式,但显然这么做很麻烦。
>
> 建议通过指定配置文件的方式,来控制 logstash 运行,启动命令如下:
>
> ```
> bin/logstash -f logstash.conf
> ```
>
> 若想了解更多的命令行参数细节,请参考:<https://www.elastic.co/guide/en/logstash/current/running-logstash-command-line.html>
### 3.2. 配置文件
上节我们了解到logstash 可以执行 `bin/logstash -f logstash.conf` ,按照配置文件中的参数去覆盖默认设置文件(`logstash.yml`)中的设置。
这节,我们就来学习一下这个配置文件如何配置参数。
#### 3.2.1. 配置文件结构
在工作原理一节中,我们已经知道了 Logstash 主要有三个工作阶段 input 、filter、output。而 logstash 配置文件文件结构也与之相对应:
```
input {}
filter {}
output {}
```
> 每个部分都包含一个或多个插件的配置选项。如果指定了多个过滤器,则会按照它们在配置文件中的显示顺序应用它们。
#### 3.2.2. 插件配置
插件的配置由插件名称和插件的一个设置块组成。
下面的例子中配置了两个输入文件配置:
```
input {
file {
path => "/var/log/messages"
type => "syslog"
}
file {
path => "/var/log/apache/access.log"
type => "apache"
}
}
```
您可以配置的设置因插件类型而异。你可以参考: [Input Plugins](https://www.elastic.co/guide/en/logstash/current/input-plugins.html), [Output Plugins](https://www.elastic.co/guide/en/logstash/current/output-plugins.html), [Filter Plugins](https://www.elastic.co/guide/en/logstash/current/filter-plugins.html), 和 [Codec Plugins](https://www.elastic.co/guide/en/logstash/current/codec-plugins.html) 。
#### 3.2.3. 值类型
一个插件可以要求设置的值是一个特定的类型,比如布尔值,列表或哈希值。以下值类型受支持。
- Array
```
users => [ {id => 1, name => bob}, {id => 2, name => jane} ]
```
- Lists
```
path => [ "/var/log/messages", "/var/log/*.log" ]
uris => [ "http://elastic.co", "http://example.net" ]
```
- Boolean
```
ssl_enable => true
```
- Bytes
```
my_bytes => "1113" # 1113 bytes
my_bytes => "10MiB" # 10485760 bytes
my_bytes => "100kib" # 102400 bytes
my_bytes => "180 mb" # 180000000 bytes
```
- Codec
```
codec => "json"
```
- Hash
```
match => {
"field1" => "value1"
"field2" => "value2"
...
}
```
- Number
```
port => 33
```
- Password
```
my_password => "password"
```
- URI
```
my_uri => "http://foo:bar@example.net"
```
- Path
```
my_path => "/tmp/logstash"
```
- String
- 转义字符
## 4. 插件
### 4.1. input
> Logstash 支持各种输入选择 可以在同一时间从众多常用来源捕捉事件。能够以连续的流式传输方式轻松地从您的日志、指标、Web 应用、数据存储以及各种 AWS 服务采集数据。
#### 4.1.1. 常用 input 插件
- **file**:从文件系统上的文件读取,就像 UNIX 命令 `tail -0F` 一样
- **syslog**在众所周知的端口 514 上侦听系统日志消息,并根据 RFC3164 格式进行解析
- **redis**从 redis 服务器读取,使用 redis 通道和 redis 列表。 Redis 经常用作集中式 Logstash 安装中的“代理”,它将来自远程 Logstash“托运人”的 Logstash 事件排队。
- **beats**处理由 Filebeat 发送的事件。
更多详情请见:[Input Plugins](https://www.elastic.co/guide/en/logstash/current/input-plugins.html)
### 4.2. filter
> 过滤器是 Logstash 管道中的中间处理设备。如果符合特定条件,您可以将条件过滤器组合在一起,对事件执行操作。
#### 4.2.1. 常用 filter 插件
- **grok**解析和结构任意文本。 Grok 目前是 Logstash 中将非结构化日志数据解析为结构化和可查询的最佳方法。
- **mutate**对事件字段执行一般转换。您可以重命名,删除,替换和修改事件中的字段。
- **drop**完全放弃一个事件,例如调试事件。
- **clone**制作一个事件的副本,可能会添加或删除字段。
- **geoip**添加有关 IP 地址的地理位置的信息(也可以在 Kibana 中显示惊人的图表!)
更多详情请见:[Filter Plugins](https://www.elastic.co/guide/en/logstash/current/filter-plugins.html)
### 4.3. output
> 输出是 Logstash 管道的最后阶段。一个事件可以通过多个输出,但是一旦所有输出处理完成,事件就完成了执行。
#### 4.3.1. 常用 output 插件
- **elasticsearch**将事件数据发送给 Elasticsearch推荐模式
- **file**将事件数据写入文件或磁盘。
- **graphite**将事件数据发送给 graphite一个流行的开源工具存储和绘制指标。 <http://graphite.readthedocs.io/en/latest/)。>
- **statsd**将事件数据发送到 statsd (这是一种侦听统计数据的服务,如计数器和定时器,通过 UDP 发送并将聚合发送到一个或多个可插入的后端服务)。
更多详情请见:[Output Plugins](https://www.elastic.co/guide/en/logstash/current/output-plugins.html)
### 4.4. codec
用于格式化对应的内容。
#### 4.4.1. 常用 codec 插件
- **json**以 JSON 格式对数据进行编码或解码。
- **multiline**将多行文本事件(如 java 异常和堆栈跟踪消息)合并为单个事件。
更多插件请见:[Codec Plugins](https://www.elastic.co/guide/en/logstash/current/codec-plugins.html)
## 5. 实战
前面的内容都是对 Logstash 的介绍和原理说明。接下来,我们来实战一些常见的应用场景。
### 5.1. 传输控制台数据
> stdin input 插件从标准输入读取事件。这是最简单的 input 插件,一般用于测试场景。
**应用**
1创建 `logstash-input-stdin.conf`
```
input { stdin { } }
output {
elasticsearch { hosts => ["localhost:9200"] }
stdout { codec => rubydebug }
}
```
更多配置项可以参考:<https://www.elastic.co/guide/en/logstash/current/plugins-inputs-stdin.html>
2执行 logstash使用 `-f` 来指定你的配置文件:
```
bin/logstash -f logstash-input-stdin.conf
```
### 5.2. 传输 logback 日志
> elk 默认使用的 Java 日志工具是 log4j2 ,并不支持 logback 和 log4j。
>
> 想使用 logback + logstash ,可以使用 [logstash-logback-encoder](https://github.com/logstash/logstash-logback-encoder) 。[logstash-logback-encoder](https://github.com/logstash/logstash-logback-encoder) 提供了 UDP / TCP / 异步方式来传输日志数据到 logstash。
>
> 如果你使用的是 log4j ,也不是不可以用这种方式,只要引入桥接 jar 包即可。如果你对 log4j 、logback ,或是桥接 jar 包不太了解,可以参考我的这篇博文:[细说 Java 主流日志工具库](https://github.com/dunwu/JavaStack/blob/master/docs/javalib/java-log.md) 。
#### 5.2.1. TCP 应用
logstash 配置:
1创建 `logstash-input-tcp.conf`
```
input {
# stdin { }
tcp {
# host:port就是上面appender中的 destination
# 这里其实把logstash作为服务开启9250端口接收logback发出的消息
host => "127.0.0.1" port => 9250 mode => "server" tags => ["tags"] codec => json_lines
}
}
output {
elasticsearch { hosts => ["localhost:9200"] }
stdout { codec => rubydebug }
}
```
更多配置项可以参考:<https://www.elastic.co/guide/en/logstash/current/plugins-inputs-tcp.html>
2执行 logstash使用 `-f` 来指定你的配置文件:`bin/logstash -f logstash-input-udp.conf`
java 应用配置:
1在 Java 应用的 pom.xml 中引入 jar 包:
```xml
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>4.11</version>
</dependency>
<!-- logback 依赖包 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-access</artifactId>
<version>1.2.3</version>
</dependency>
```
2接着在 logback.xml 中添加 appender
```xml
<appender name="ELK-TCP" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<!--
destination 是 logstash 服务的 host:port
相当于和 logstash 建立了管道,将日志数据定向传输到 logstash
-->
<destination>192.168.28.32:9251</destination>
<encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder"/>
</appender>
<logger name="io.github.dunwu.spring" level="TRACE" additivity="false">
<appender-ref ref="ELK-TCP" />
</logger>
```
大功告成,此后,`io.github.dunwu.spring` 包中的 TRACE 及以上级别的日志信息都会被定向输出到 logstash 服务。
![img](http://upload-images.jianshu.io/upload_images/3101171-cd876d79a14955b0.png)
接下来,就是 logback 的具体使用 ,如果对此不了解,不妨参考一下我的这篇博文:[细说 Java 主流日志工具库](https://github.com/dunwu/JavaStack/blob/master/docs/javalib/java-log.md) 。
**实例:**[我的 logback.xml](https://github.com/dunwu/JavaStack/blob/master/codes/javatool/src/main/resources/logback.xml)
#### 5.2.2. UDP 应用
UDP 和 TCP 的使用方式大同小异。
logstash 配置:
1创建 `logstash-input-udp.conf`
```
input {
udp {
port => 9250
codec => json
}
}
output {
elasticsearch { hosts => ["localhost:9200"] }
stdout { codec => rubydebug }
}
```
更多配置项可以参考:<https://www.elastic.co/guide/en/logstash/current/plugins-inputs-udp.html>
2执行 logstash使用 `-f` 来指定你的配置文件:`bin/logstash -f logstash-input-udp.conf`
java 应用配置:
1在 Java 应用的 pom.xml 中引入 jar 包:
**TCP 应用** 一节中的引入依赖包完全相同。
2接着在 logback.xml 中添加 appender
```xml
<appender name="ELK-UDP" class="net.logstash.logback.appender.LogstashSocketAppender">
<host>192.168.28.32</host>
<port>9250</port>
</appender>
<logger name="io.github.dunwu.spring" level="TRACE" additivity="false">
<appender-ref ref="ELK-UDP" />
</logger>
```
3接下来就是 logback 的具体使用 ,如果对此不了解,不妨参考一下我的这篇博文:[细说 Java 主流日志工具库](https://github.com/dunwu/JavaStack/blob/master/docs/javalib/java-log.md) 。
**实例:**[我的 logback.xml](https://github.com/dunwu/JavaStack/blob/master/codes/javatool/src/main/resources/logback.xml)
### 5.3. 传输文件
> 在 Java Web 领域,需要用到一些重要的工具,例如 Tomcat 、Nginx 、Mysql 等。这些不属于业务应用,但是它们的日志数据对于定位问题、分析统计同样很重要。这时无法使用 logback 方式将它们的日志传输到 logstash。
>
> 如何采集这些日志文件呢?别急,你可以使用 logstash 的 file input 插件。
>
> 需要注意的是,传输文件这种方式,必须在日志所在的机器上部署 logstash 。
**应用**
logstash 配置
1创建 `logstash-input-file.conf`
```
input {
file {
path => ["/var/log/nginx/access.log"]
type => "nginx-access-log"
start_position => "beginning"
}
}
output {
if [type] == "nginx-access-log" {
elasticsearch {
hosts => ["localhost:9200"]
index => "nginx-access-log"
}
}
}
```
2执行 logstash使用 `-f` 来指定你的配置文件:`bin/logstash -f logstash-input-file.conf`
更多配置项可以参考:<https://www.elastic.co/guide/en/logstash/current/plugins-inputs-file.html>
## 6. 小技巧
### 6.1. 启动、终止应用
如果你的 logstash 每次都是通过指定配置文件方式启动。不妨建立一个启动脚本。
```
# cd xxx 进入 logstash 安装目录下的 bin 目录
logstash -f logstash.conf
```
如果你的 logstash 运行在 linux 系统下,不妨使用 nohup 来启动一个守护进程。这样做的好处在于,即使关闭终端,应用仍会运行。
创建 startup.sh
```
nohup ./logstash -f logstash.conf >> nohup.out 2>&1 &
```
终止应用没有什么好方法,你只能使用 ps -ef | grep logstash ,查出进程,将其 kill 。不过,我们可以写一个脚本来干这件事:
创建 shutdown.sh
脚本不多解释,请自行领会作用。
```
PID=`ps -ef | grep logstash | awk '{ print $2}' | head -n 1`
kill -9 ${PID}
```
## 7. 参考资料
- [Logstash 官网](https://www.elastic.co/cn/products/logstash)
- [Logstash Github](https://github.com/elastic/logstash)
- [Logstash 官方文档](https://www.elastic.co/guide/en/logstash/current/index.html)
- [logstash-logback-encoder](https://github.com/logstash/logstash-logback-encoder)
- [ELK Stack 权威指南](https://github.com/chenryn/logstash-best-practice-cn)
- [ELKElasticsearch、Logstash、Kibana安装和配置](https://github.com/judasn/Linux-Tutorial/blob/master/ELK-Install-And-Settings.md)

View File

@ -0,0 +1,498 @@
# Elastic 技术栈之 Logstash 基础
> 本文是 Elastic 技术栈ELK的 Logstash 应用。
>
> 如果不了解 Elastic 的安装、配置、部署,可以参考:[Elastic 技术栈之快速入门](https://github.com/dunwu/JavaStack/blob/master/docs/javatool/elastic/elastic-quickstart.md)
## 简介
Logstash 可以传输和处理你的日志、事务或其他数据。
### 功能
Logstash 是 Elasticsearch 的最佳数据管道。
Logstash 是插件式管理模式在输入、过滤、输出以及编码过程中都可以使用插件进行定制。Logstash 社区有超过 200 种可用插件。
### 工作原理
Logstash 有两个必要元素:`input` 和 `output` ,一个可选元素:`filter`。
这三个元素,分别代表 Logstash 事件处理的三个阶段:输入 > 过滤器 > 输出。
![img](https://www.elastic.co/guide/en/logstash/current/static/images/basic_logstash_pipeline.png)
- input 负责从数据源采集数据。
- filter 将数据修改为你指定的格式或内容。
- output 将数据传输到目的地。
在实际应用场景中通常输入、输出、过滤器不止一个。Logstash 的这三个元素都使用插件式管理方式,用户可以根据应用需要,灵活的选用各阶段需要的插件,并组合使用。
后面将对插件展开讲解,暂且不表。
## 设置
### 设置文件
- **`logstash.yml`**logstash 的默认启动配置文件
- **`jvm.options`**logstash 的 JVM 配置文件。
- **`startup.options`** (Linux):包含系统安装脚本在 `/usr/share/logstash/bin` 中使用的选项为您的系统构建适当的启动脚本。安装 Logstash 软件包时,系统安装脚本将在安装过程结束时执行,并使用 `startup.options` 中指定的设置来设置用户,组,服务名称和服务描述等选项。
### logstash.yml 设置项
节选部分设置项,更多项请参考:[https://www.elastic.co/guide/en/logstash/current/logstash-settings-file.html](https://www.elastic.co/guide/en/logstash/current/logstash-settings-file.html)
| 参数 | 描述 | 默认值 |
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `node.name` | 节点名 | 机器的主机名 |
| `path.data` | Logstash 及其插件用于任何持久性需求的目录。 | `LOGSTASH_HOME/data` |
| `pipeline.workers` | 同时执行管道的过滤器和输出阶段的工作任务数量。如果发现事件正在备份,或 CPU 未饱和,请考虑增加此数字以更好地利用机器处理能力。 | Number of the hosts CPU cores |
| `pipeline.batch.size` | 尝试执行过滤器和输出之前,单个工作线程从输入收集的最大事件数量。较大的批量处理大小一般来说效率更高,但是以增加的内存开销为代价。您可能必须通过设置 `LS_HEAP_SIZE` 变量来有效使用该选项来增加 JVM 堆大小。 | `125` |
| `pipeline.batch.delay` | 创建管道事件批处理时,在将一个尺寸过小的批次发送给管道工作任务之前,等待每个事件需要多长时间(毫秒)。 | `5` |
| `pipeline.unsafe_shutdown` | 如果设置为 true则即使在内存中仍存在 inflight 事件时,也会强制 Logstash 在关闭期间退出。默认情况下Logstash 将拒绝退出,直到所有接收到的事件都被推送到输出。启用此选项可能会导致关机期间数据丢失。 | `false` |
| `path.config` | 主管道的 Logstash 配置路径。如果您指定一个目录或通配符,配置文件将按字母顺序从目录中读取。 | Platform-specific. See [[dir-layout\]](https://github.com/elastic/logstash/blob/6.1/docs/static/settings-file.asciidoc#dir-layout). |
| `config.string` | 包含用于主管道的管道配置的字符串。使用与配置文件相同的语法。 | None |
| `config.test_and_exit` | 设置为 true 时,检查配置是否有效,然后退出。请注意,使用此设置不会检查 grok 模式的正确性。 Logstash 可以从目录中读取多个配置文件。如果将此设置与 log.leveldebug 结合使用,则 Logstash 将记录组合的配置文件,并注掉其源文件的配置块。 | `false` |
| `config.reload.automatic` | 设置为 true 时,定期检查配置是否已更改,并在配置更改时重新加载配置。这也可以通过 SIGHUP 信号手动触发。 | `false` |
| `config.reload.interval` | Logstash 检查配置文件更改的时间间隔。 | `3s` |
| `config.debug` | 设置为 true 时,将完全编译的配置显示为调试日志消息。您还必须设置`log.leveldebug`。警告:日志消息将包括任何传递给插件配置作为明文的“密码”选项,并可能导致明文密码出现在您的日志! | `false` |
| `config.support_escapes` | 当设置为 true 时,带引号的字符串将处理转义字符。 | `false` |
| `modules` | 配置时,模块必须处于上表所述的嵌套 YAML 结构中。 | None |
| `http.host` | 绑定地址 | `"127.0.0.1"` |
| `http.port` | 绑定端口 | `9600` |
| `log.level` | 日志级别。有效选项fatal > error > warn > info > debug > trace | `info` |
| `log.format` | 日志格式。json JSON 格式)或 plain (原对象) | `plain` |
| `path.logs` | Logstash 自身日志的存储路径 | `LOGSTASH_HOME/logs` |
| `path.plugins` | 在哪里可以找到自定义的插件。您可以多次指定此设置以包含多个路径。 | |
## 启动
### 命令行
通过命令行启动 logstash 的方式如下:
```shell
bin/logstash [options]
```
其中 `options` 是您可以指定用于控制 Logstash 执行的命令行标志。
在命令行上设置的任何标志都会覆盖 Logstash 设置文件(`logstash.yml`)中的相应设置,但设置文件本身不会更改。
> **注**
>
> 虽然可以通过指定命令行参数的方式,来控制 logstash 的运行方式,但显然这么做很麻烦。
>
> 建议通过指定配置文件的方式,来控制 logstash 运行,启动命令如下:
>
> ```shell
> bin/logstash -f logstash.conf
> ```
>
> 若想了解更多的命令行参数细节,请参考:<https://www.elastic.co/guide/en/logstash/current/running-logstash-command-line.html>
### 配置文件
上节我们了解到logstash 可以执行 `bin/logstash -f logstash.conf` ,按照配置文件中的参数去覆盖默认设置文件(`logstash.yml`)中的设置。
这节,我们就来学习一下这个配置文件如何配置参数。
#### 配置文件结构
在工作原理一节中,我们已经知道了 Logstash 主要有三个工作阶段 input 、filter、output。而 logstash 配置文件文件结构也与之相对应:
```javascript
input {}
filter {}
output {}
```
> 每个部分都包含一个或多个插件的配置选项。如果指定了多个过滤器,则会按照它们在配置文件中的显示顺序应用它们。
#### 插件配置
插件的配置由插件名称和插件的一个设置块组成。
下面的例子中配置了两个输入文件配置:
```javascript
input {
file {
path => "/var/log/messages"
type => "syslog"
}
file {
path => "/var/log/apache/access.log"
type => "apache"
}
}
```
您可以配置的设置因插件类型而异。你可以参考: [Input Plugins](https://www.elastic.co/guide/en/logstash/current/input-plugins.html), [Output Plugins](https://www.elastic.co/guide/en/logstash/current/output-plugins.html), [Filter Plugins](https://www.elastic.co/guide/en/logstash/current/filter-plugins.html), 和 [Codec Plugins](https://www.elastic.co/guide/en/logstash/current/codec-plugins.html) 。
#### 值类型
一个插件可以要求设置的值是一个特定的类型,比如布尔值,列表或哈希值。以下值类型受支持。
- Array
```javascript
users => [ {id => 1, name => bob}, {id => 2, name => jane} ]
```
- Lists
```javascript
path => [ "/var/log/messages", "/var/log/*.log" ]
uris => [ "http://elastic.co", "http://example.net" ]
```
- Boolean
```javascript
ssl_enable => true
```
- Bytes
```javascript
my_bytes => "1113" # 1113 bytes
my_bytes => "10MiB" # 10485760 bytes
my_bytes => "100kib" # 102400 bytes
my_bytes => "180 mb" # 180000000 bytes
```
- Codec
```javascript
codec => "json"
```
- Hash
```javascript
match => {
"field1" => "value1"
"field2" => "value2"
...
}
```
- Number
```javascript
port => 33
```
- Password
```javascript
my_password => "password"
```
- URI
```javascript
my_uri => "http://foo:bar@example.net"
```
- Path
```javascript
my_path => "/tmp/logstash"
```
- String
- 转义字符
## 插件
### input
> Logstash 支持各种输入选择 可以在同一时间从众多常用来源捕捉事件。能够以连续的流式传输方式轻松地从您的日志、指标、Web 应用、数据存储以及各种 AWS 服务采集数据。
#### 常用 input 插件
- **file**:从文件系统上的文件读取,就像 UNIX 命令 `tail -0F` 一样
- **syslog**在众所周知的端口 514 上侦听系统日志消息,并根据 RFC3164 格式进行解析
- **redis**从 redis 服务器读取,使用 redis 通道和 redis 列表。 Redis 经常用作集中式 Logstash 安装中的“代理”,它将来自远程 Logstash“托运人”的 Logstash 事件排队。
- **beats**处理由 Filebeat 发送的事件。
更多详情请见:[Input Plugins](https://www.elastic.co/guide/en/logstash/current/input-plugins.html)
### filter
> 过滤器是 Logstash 管道中的中间处理设备。如果符合特定条件,您可以将条件过滤器组合在一起,对事件执行操作。
#### 常用 filter 插件
- **grok**解析和结构任意文本。 Grok 目前是 Logstash 中将非结构化日志数据解析为结构化和可查询的最佳方法。
- **mutate**对事件字段执行一般转换。您可以重命名,删除,替换和修改事件中的字段。
- **drop**完全放弃一个事件,例如调试事件。
- **clone**制作一个事件的副本,可能会添加或删除字段。
- **geoip**添加有关 IP 地址的地理位置的信息(也可以在 Kibana 中显示惊人的图表!)
更多详情请见:[Filter Plugins](https://www.elastic.co/guide/en/logstash/current/filter-plugins.html)
### output
> 输出是 Logstash 管道的最后阶段。一个事件可以通过多个输出,但是一旦所有输出处理完成,事件就完成了执行。
#### 常用 output 插件
- **elasticsearch**将事件数据发送给 Elasticsearch推荐模式
- **file**将事件数据写入文件或磁盘。
- **graphite**将事件数据发送给 graphite一个流行的开源工具存储和绘制指标。 <http://graphite.readthedocs.io/en/latest/)。>
- **statsd**将事件数据发送到 statsd (这是一种侦听统计数据的服务,如计数器和定时器,通过 UDP 发送并将聚合发送到一个或多个可插入的后端服务)。
更多详情请见:[Output Plugins](https://www.elastic.co/guide/en/logstash/current/output-plugins.html)
### codec
用于格式化对应的内容。
#### 常用 codec 插件
- **json**以 JSON 格式对数据进行编码或解码。
- **multiline**将多行文本事件(如 java 异常和堆栈跟踪消息)合并为单个事件。
更多插件请见:[Codec Plugins](https://www.elastic.co/guide/en/logstash/current/codec-plugins.html)
## 实战
前面的内容都是对 Logstash 的介绍和原理说明。接下来,我们来实战一些常见的应用场景。
### 传输控制台数据
> stdin input 插件从标准输入读取事件。这是最简单的 input 插件,一般用于测试场景。
**应用**
1创建 `logstash-input-stdin.conf`
```javascript
input { stdin { } }
output {
elasticsearch { hosts => ["localhost:9200"] }
stdout { codec => rubydebug }
}
```
更多配置项可以参考:<https://www.elastic.co/guide/en/logstash/current/plugins-inputs-stdin.html>
2执行 logstash使用 `-f` 来指定你的配置文件:
```shell
bin/logstash -f logstash-input-stdin.conf
```
### 传输 logback 日志
> elk 默认使用的 Java 日志工具是 log4j2 ,并不支持 logback 和 log4j。
>
> 想使用 logback + logstash ,可以使用 [logstash-logback-encoder](https://github.com/logstash/logstash-logback-encoder) 。[logstash-logback-encoder](https://github.com/logstash/logstash-logback-encoder) 提供了 UDP / TCP / 异步方式来传输日志数据到 logstash。
>
> 如果你使用的是 log4j ,也不是不可以用这种方式,只要引入桥接 jar 包即可。如果你对 log4j 、logback ,或是桥接 jar 包不太了解,可以参考我的这篇博文:[细说 Java 主流日志工具库](https://github.com/dunwu/JavaStack/blob/master/docs/javalib/java-log.md) 。
#### TCP 应用
logstash 配置
1创建 `logstash-input-tcp.conf`
```javascript
input {
tcp {
port => 9251
codec => json_lines
mode => server
}
}
output {
elasticsearch { hosts => ["localhost:9200"] }
stdout { codec => rubydebug }
}
```
更多配置项可以参考:<https://www.elastic.co/guide/en/logstash/current/plugins-inputs-tcp.html>
2执行 logstash使用 `-f` 来指定你的配置文件:`bin/logstash -f logstash-input-udp.conf`
java 应用配置
1在 Java 应用的 pom.xml 中引入 jar 包:
```xml
<dependency>
<groupId>net.logstash.logback</groupId>
<artifactId>logstash-logback-encoder</artifactId>
<version>4.11</version>
</dependency>
<!-- logback 依赖包 -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-access</artifactId>
<version>1.2.3</version>
</dependency>
```
2接着在 logback.xml 中添加 appender
```xml
<appender name="ELK-TCP" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
<!--
destination 是 logstash 服务的 host:port
相当于和 logstash 建立了管道,将日志数据定向传输到 logstash
-->
<destination>192.168.28.32:9251</destination>
<encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder"/>
</appender>
<logger name="io.github.dunwu.spring" level="TRACE" additivity="false">
<appender-ref ref="ELK-TCP" />
</logger>
```
3接下来就是 logback 的具体使用 ,如果对此不了解,不妨参考一下我的这篇博文:[细说 Java 主流日志工具库](https://github.com/dunwu/JavaStack/blob/master/docs/javalib/java-log.md) 。
**实例:**[我的 logback.xml](https://github.com/dunwu/JavaStack/blob/master/codes/javatool/src/main/resources/logback.xml)
#### UDP 应用
UDP 和 TCP 的使用方式大同小异。
logstash 配置
1创建 `logstash-input-udp.conf`
```javascript
input {
udp {
port => 9250
codec => json
}
}
output {
elasticsearch { hosts => ["localhost:9200"] }
stdout { codec => rubydebug }
}
```
更多配置项可以参考:[https://www.elastic.co/guide/en/logstash/current/plugins-inputs-udp.html](https://www.elastic.co/guide/en/logstash/current/plugins-inputs-udp.html)
2执行 logstash使用 `-f` 来指定你的配置文件:`bin/logstash -f logstash-input-udp.conf`
java 应用配置
1在 Java 应用的 pom.xml 中引入 jar 包:
**TCP 应用** 一节中的引入依赖包完全相同。
2接着在 logback.xml 中添加 appender
```xml
<appender name="ELK-UDP" class="net.logstash.logback.appender.LogstashSocketAppender">
<host>192.168.28.32</host>
<port>9250</port>
</appender>
<logger name="io.github.dunwu.spring" level="TRACE" additivity="false">
<appender-ref ref="ELK-UDP" />
</logger>
```
3接下来就是 logback 的具体使用 ,如果对此不了解,不妨参考一下我的这篇博文:[细说 Java 主流日志工具库](https://github.com/dunwu/JavaStack/blob/master/docs/javalib/java-log.md) 。
**实例:**[我的 logback.xml](https://github.com/dunwu/JavaStack/blob/master/codes/javatool/src/main/resources/logback.xml)
### 传输文件
> 在 Java Web 领域,需要用到一些重要的工具,例如 Tomcat 、Nginx 、Mysql 等。这些不属于业务应用,但是它们的日志数据对于定位问题、分析统计同样很重要。这时无法使用 logback 方式将它们的日志传输到 logstash。
>
> 如何采集这些日志文件呢?别急,你可以使用 logstash 的 file input 插件。
>
> 需要注意的是,传输文件这种方式,必须在日志所在的机器上部署 logstash 。
**应用**
logstash 配置
1创建 `logstash-input-file.conf`
```javascript
input {
file {
path => ["/var/log/nginx/access.log"]
type => "nginx-access-log"
start_position => "beginning"
}
}
output {
if [type] == "nginx-access-log" {
elasticsearch {
hosts => ["localhost:9200"]
index => "nginx-access-log"
}
}
}
```
2执行 logstash使用 `-f` 来指定你的配置文件:`bin/logstash -f logstash-input-file.conf`
更多配置项可以参考:<https://www.elastic.co/guide/en/logstash/current/plugins-inputs-file.html>
## 小技巧
### 启动、终止应用
如果你的 logstash 每次都是通过指定配置文件方式启动。不妨建立一个启动脚本。
```shell
# cd xxx 进入 logstash 安装目录下的 bin 目录
logstash -f logstash.conf
```
如果你的 logstash 运行在 linux 系统下,不妨使用 nohup 来启动一个守护进程。这样做的好处在于,即使关闭终端,应用仍会运行。
**创建 startup.sh**
```shell
nohup ./logstash -f logstash.conf >> nohup.out 2>&1 &
```
终止应用没有什么好方法,你只能使用 ps -ef | grep logstash ,查出进程,将其 kill 。不过,我们可以写一个脚本来干这件事:
**创建 shutdown.sh**
脚本不多解释,请自行领会作用。
```shell
PID=`ps -ef | grep logstash | awk '{ print $2}' | head -n 1`
kill -9 ${PID}
```
## 资料
- [Logstash 官方文档](https://www.elastic.co/guide/en/logstash/current/index.html)
- [logstash-logback-encoder](https://github.com/logstash/logstash-logback-encoder)
- [ELK Stack 权威指南](https://github.com/chenryn/logstash-best-practice-cn)
- [ELKElasticsearch、Logstash、Kibana安装和配置](https://github.com/judasn/Linux-Tutorial/blob/master/ELK-Install-And-Settings.md)
## 推荐阅读
- [Elastic 技术栈](https://github.com/dunwu/JavaStack/blob/master/docs/javatool/elastic/README.md)
- [JavaStack](https://github.com/dunwu/JavaStack)

View File

@ -0,0 +1,276 @@
# Elastic 快速入门
> 开源协议:[Apache 2.0](https://github.com/elastic/elasticsearch/tree/7.4/licenses/APACHE-LICENSE-2.0.txt)
## 1. 简介
### 1.1. Elastic Stack 是什么
**Elastic Stack** 即 **ELK Stack**
ELK 是指 Elastic 公司旗下三款产品 [ElasticSearch](https://www.elastic.co/cn/products/elasticsearch) 、[Logstash](https://www.elastic.co/cn/products/logstash) 、[Kibana](https://www.elastic.co/cn/products/kibana) 的首字母组合。
- Elasticsearch 是一个搜索和分析引擎。
- Logstash 是服务器端数据处理管道,能够同时从多个来源采集数据,转换数据,然后将数据发送到诸如 Elasticsearch 等“存储库”中。
- Kibana 则可以让用户在 Elasticsearch 中使用图形和图表对数据进行可视化。
而 Elastic Stack 是 ELK Stack 的更新换代产品,最新产品引入了轻量型的单一功能数据采集器,并把它们叫做 [Beats](https://www.elastic.co/cn/products/beats)。
### 1.2. 为什么使用 Elastic Stack
对于有一定规模的公司来说,通常会很多个应用,并部署在大量的服务器上。运维和开发人员常常需要通过查看日志来定位问题。如果应用是集群化部署,试想如果登录一台台服务器去查看日志,是多么费时费力。
而通过 ELK 这套解决方案,可以同时实现日志收集、日志搜索和日志分析的功能。
### 1.3. Elastic Stack 架构
![img](https://www.elastic.co/guide/en/logstash/current/static/images/deploy3.png)
> **说明**
>
> 以上是 Elastic Stack 的一个架构图。从图中可以清楚的看到数据流向。
>
> - [Beats](https://www.elastic.co/products/beats) 是单一用途的数据传输平台,它可以将多台机器的数据发送到 Logstash 或 ElasticSearch。但 Beats 并不是不可或缺的一环,所以本文中暂不介绍。
> - [Logstash](https://www.elastic.co/products/logstash) 是一个动态数据收集管道。支持以 TCP/UDP/HTTP 多种方式收集数据(也可以接受 Beats 传输来的数据),并对数据做进一步丰富或提取字段处理。
> - [ElasticSearch](https://www.elastic.co/products/elasticsearch) 是一个基于 JSON 的分布式的搜索和分析引擎。作为 ELK 的核心,它集中存储数据。
>
> - [Kibana](https://www.elastic.co/products/kibana) 是 ELK 的用户界面。它将收集的数据进行可视化展示(各种报表、图形化数据),并提供配置、管理 ELK 的界面。
## 2. ElasticSearch
> [Elasticsearch](https://github.com/elastic/elasticsearch) 是一个分布式、RESTful 风格的搜索和数据分析引擎,能够解决不断涌现出的各种用例。 作为 Elastic Stack 的核心,它集中存储您的数据,帮助您发现意料之中以及意料之外的情况。
### 2.1. ElasticSearch 简介
[Elasticsearch](https://github.com/elastic/elasticsearch) 基于搜索库 [Lucene](https://github.com/apache/lucene-solr) 开发。ElasticSearch 隐藏了 Lucene 的复杂性,提供了简单易用的 REST API / Java API 接口(另外还有其他语言的 API 接口)。
ElasticSearch 可以视为一个文档存储,它**将复杂数据结构序列化为 JSON 存储**。
**ElasticSearch 是近乎于实时的全文搜素**,这是指:
- 从写入数据到数据可以被搜索,存在较小的延迟(大概是 1s
- 基于 ES 执行搜索和分析可以达到秒级
#### 2.1.1. 核心概念
- **`索引Index`** 可以认为是文档document的优化集合。
- 每个 **`文档document`** 都是字段field的集合。
- **`字段field`** 是包含数据的键值对。
- 默认情况下Elasticsearch 对每个字段中的所有数据建立索引,并且每个索引字段都具有专用的优化数据结构。
- 每个索引里可以有一个或者多个类型type。`类型type` 是 index 的一个逻辑分类,
- 当单台机器不足以存储大量数据时Elasticsearch 可以将一个索引中的数据切分为多个 **`分片shard`** 。 **`分片shard`** 分布在多台服务器上存储。有了 shard 就可以横向扩展,存储更多数据,让搜索和分析等操作分布到多台服务器上去执行,提升吞吐量和性能。每个 shard 都是一个 lucene index。
- 任何一个服务器随时可能故障或宕机,此时 shard 可能就会丢失,因此可以为每个 shard 创建多个 **`副本replica`**。replica 可以在 shard 故障时提供备用服务,保证数据不丢失,多个 replica 还可以提升搜索操作的吞吐量和性能。primary shard建立索引时一次设置不能修改默认 5 个replica shard随时修改数量默认 1 个),默认每个索引 10 个 shard5 个 primary shard5 个 replica shard最小的高可用配置是 2 台服务器。
### 2.2. ElasticSearch 原理
#### 2.2.1. ES 写数据过程
- 客户端选择一个 node 发送请求过去,这个 node 就是 `coordinating node`(协调节点)。
- `coordinating node` 对 document 进行**路由**,将请求转发给对应的 node有 primary shard
- 实际的 node 上的 `primary shard` 处理请求,然后将数据同步到 `replica node`
- `coordinating node` 如果发现 `primary node` 和所有 `replica node` 都搞定之后,就返回响应结果给客户端。
![es-write](https://github.com/doocs/advanced-java/raw/master/images/es-write.png)
#### 2.2.2. es 读数据过程
可以通过 `doc id` 来查询,会根据 `doc id` 进行 hash判断出来当时把 `doc id` 分配到了哪个 shard 上面去,从那个 shard 去查询。
- 客户端发送请求到**任意**一个 node成为 `coordinate node`
- `coordinate node``doc id` 进行哈希路由,将请求转发到对应的 node此时会使用 `round-robin` **随机轮询算法**,在 `primary shard` 以及其所有 replica 中随机选择一个,让读请求负载均衡。
- 接收请求的 node 返回 document 给 `coordinate node`
- `coordinate node` 返回 document 给客户端。
#### 2.2.3. 写数据底层原理
![es-write-detail](https://github.com/doocs/advanced-java/raw/master/images/es-write-detail.png)
先写入内存 buffer在 buffer 里的时候数据是搜索不到的;同时将数据写入 translog 日志文件。
如果 buffer 快满了,或者到一定时间,就会将内存 buffer 数据 `refresh` 到一个新的 `segment file` 中,但是此时数据不是直接进入 `segment file` 磁盘文件,而是先进入 `os cache` 。这个过程就是 `refresh`
每隔 1 秒钟es 将 buffer 中的数据写入一个**新的** `segment file`,每秒钟会产生一个**新的磁盘文件** `segment file`,这个 `segment file` 中就存储最近 1 秒内 buffer 中写入的数据。
但是如果 buffer 里面此时没有数据,那当然不会执行 refresh 操作,如果 buffer 里面有数据,默认 1 秒钟执行一次 refresh 操作,刷入一个新的 segment file 中。
操作系统里面,磁盘文件其实都有一个东西,叫做 `os cache`,即操作系统缓存,就是说数据写入磁盘文件之前,会先进入 `os cache`,先进入操作系统级别的一个内存缓存中去。只要 `buffer` 中的数据被 refresh 操作刷入 `os cache`中,这个数据就可以被搜索到了。
为什么叫 es 是**准实时**的? `NRT`,全称 `near real-time`。默认是每隔 1 秒 refresh 一次的,所以 es 是准实时的,因为写入的数据 1 秒之后才能被看到。可以通过 es 的 `restful api` 或者 `java api`**手动**执行一次 refresh 操作,就是手动将 buffer 中的数据刷入 `os cache`中,让数据立马就可以被搜索到。只要数据被输入 `os cache`buffer 就会被清空了,因为不需要保留 buffer 了,数据在 translog 里面已经持久化到磁盘去一份了。
重复上面的步骤,新的数据不断进入 buffer 和 translog不断将 `buffer` 数据写入一个又一个新的 `segment file` 中去,每次 `refresh` 完 buffer 清空translog 保留。随着这个过程推进translog 会变得越来越大。当 translog 达到一定长度的时候,就会触发 `commit` 操作。
commit 操作发生第一步,就是将 buffer 中现有数据 `refresh``os cache` 中去,清空 buffer。然后将一个 `commit point` 写入磁盘文件,里面标识着这个 `commit point` 对应的所有 `segment file`,同时强行将 `os cache` 中目前所有的数据都 `fsync` 到磁盘文件中去。最后**清空** 现有 translog 日志文件,重启一个 translog此时 commit 操作完成。
这个 commit 操作叫做 `flush`。默认 30 分钟自动执行一次 `flush`,但如果 translog 过大,也会触发 `flush`。flush 操作就对应着 commit 的全过程,我们可以通过 es api手动执行 flush 操作,手动将 os cache 中的数据 fsync 强刷到磁盘上去。
translog 日志文件的作用是什么?你执行 commit 操作之前,数据要么是停留在 buffer 中,要么是停留在 os cache 中,无论是 buffer 还是 os cache 都是内存,一旦这台机器死了,内存中的数据就全丢了。所以需要将数据对应的操作写入一个专门的日志文件 `translog`一旦此时机器宕机再次重启的时候es 会自动读取 translog 日志文件中的数据,恢复到内存 buffer 和 os cache 中去。
translog 其实也是先写入 os cache 的,默认每隔 5 秒刷一次到磁盘中去,所以默认情况下,可能有 5 秒的数据会仅仅停留在 buffer 或者 translog 文件的 os cache 中,如果此时机器挂了,会**丢失** 5 秒钟的数据。但是这样性能比较好,最多丢 5 秒的数据。也可以将 translog 设置成每次写操作必须是直接 `fsync` 到磁盘,但是性能会差很多。
实际上你在这里,如果面试官没有问你 es 丢数据的问题,你可以在这里给面试官炫一把,你说,其实 es 第一是准实时的,数据写入 1 秒后可以搜索到;可能会丢失数据的。有 5 秒的数据,停留在 buffer、translog os cache、segment file os cache 中,而不在磁盘上,此时如果宕机,会导致 5 秒的**数据丢失**。
**总结一下**,数据先写入内存 buffer然后每隔 1s将数据 refresh 到 os cache到了 os cache 数据就能被搜索到(所以我们才说 es 从写入到能被搜索到,中间有 1s 的延迟)。每隔 5s将数据写入 translog 文件(这样如果机器宕机,内存数据全没,最多会有 5s 的数据丢失translog 大到一定程度,或者默认每隔 30mins会触发 commit 操作,将缓冲区的数据都 flush 到 segment file 磁盘文件中。
> 数据写入 segment file 之后,同时就建立好了倒排索引。
#### 2.2.4. 删除/更新数据底层原理
如果是删除操作commit 的时候会生成一个 `.del` 文件,里面将某个 doc 标识为 `deleted` 状态,那么搜索的时候根据 `.del` 文件就知道这个 doc 是否被删除了。
如果是更新操作,就是将原来的 doc 标识为 `deleted` 状态,然后新写入一条数据。
buffer 每 refresh 一次,就会产生一个 `segment file`,所以默认情况下是 1 秒钟一个 `segment file`,这样下来 `segment file` 会越来越多,此时会定期执行 merge。每次 merge 的时候,会将多个 `segment file` 合并成一个,同时这里会将标识为 `deleted` 的 doc 给**物理删除掉**,然后将新的 `segment file` 写入磁盘,这里会写一个 `commit point`,标识所有新的 `segment file`,然后打开 `segment file` 供搜索使用,同时删除旧的 `segment file`
#### 2.2.5. 底层 lucene
简单来说lucene 就是一个 jar 包,里面包含了封装好的各种建立倒排索引的算法代码。我们用 Java 开发的时候,引入 lucene jar然后基于 lucene 的 api 去开发就可以了。
通过 lucene我们可以将已有的数据建立索引lucene 会在本地磁盘上面,给我们组织索引的数据结构。
#### 2.2.6. 倒排索引
在搜索引擎中,每个文档都有一个对应的文档 ID文档内容被表示为一系列关键词的集合。例如文档 1 经过分词,提取了 20 个关键词,每个关键词都会记录它在文档中出现的次数和出现位置。
那么,倒排索引就是**关键词到文档** ID 的映射,每个关键词都对应着一系列的文件,这些文件中都出现了关键词。
举个栗子。
有以下文档:
| DocId | Doc |
| ----- | ---------------------------------------------- |
| 1 | 谷歌地图之父跳槽 Facebook |
| 2 | 谷歌地图之父加盟 Facebook |
| 3 | 谷歌地图创始人拉斯离开谷歌加盟 Facebook |
| 4 | 谷歌地图之父跳槽 Facebook 与 Wave 项目取消有关 |
| 5 | 谷歌地图之父拉斯加盟社交网站 Facebook |
对文档进行分词之后,得到以下**倒排索引**。
| WordId | Word | DocIds |
| ------ | -------- | --------- |
| 1 | 谷歌 | 1,2,3,4,5 |
| 2 | 地图 | 1,2,3,4,5 |
| 3 | 之父 | 1,2,4,5 |
| 4 | 跳槽 | 1,4 |
| 5 | Facebook | 1,2,3,4,5 |
| 6 | 加盟 | 2,3,5 |
| 7 | 创始人 | 3 |
| 8 | 拉斯 | 3,5 |
| 9 | 离开 | 3 |
| 10 | 与 | 4 |
| .. | .. | .. |
另外,实用的倒排索引还可以记录更多的信息,比如文档频率信息,表示在文档集合中有多少个文档包含某个单词。
那么,有了倒排索引,搜索引擎可以很方便地响应用户的查询。比如用户输入查询 `Facebook`,搜索系统查找倒排索引,从中读出包含这个单词的文档,这些文档就是提供给用户的搜索结果。
要注意倒排索引的两个重要细节:
- 倒排索引中的所有词项对应一个或多个文档;
- 倒排索引中的词项**根据字典顺序升序排列**
> 上面只是一个简单的栗子,并没有严格按照字典顺序升序排列。
## 3. Logstash
> [Logstash](https://github.com/elastic/logstash) 是开源的服务器端数据处理管道,能够同时从多个来源采集数据,转换数据,然后将数据发送到您最喜欢的“存储库”中。
### 3.1. Logstash 简介
Logstash 可以传输和处理你的日志、事务或其他数据。
Logstash 是 Elasticsearch 的最佳数据管道。
Logstash 是插件式管理模式在输入、过滤、输出以及编码过程中都可以使用插件进行定制。Logstash 社区有超过 200 种可用插件。
### 3.2. Logstash 原理
Logstash 有两个必要元素:`input` 和 `output` ,一个可选元素:`filter`。
这三个元素,分别代表 Logstash 事件处理的三个阶段:输入 > 过滤器 > 输出。
![img](https://www.elastic.co/guide/en/logstash/current/static/images/basic_logstash_pipeline.png)
- **input** - 负责从数据源采集数据。
- **`filter`** - 将数据修改为你指定的格式或内容。
- **`output`** - 将数据传输到目的地。
在实际应用场景中通常输入、输出、过滤器不止一个。Logstash 的这三个元素都使用插件式管理方式,用户可以根据应用需要,灵活的选用各阶段需要的插件,并组合使用。
## 4. Beats
> **[Beats](https://github.com/elastic/beats) 是安装在服务器上的数据中转代理**。
>
> Beats 可以将数据直接传输到 Elasticsearch 或传输到 Logstash 。
![img](https://www.elastic.co/guide/en/beats/libbeat/current/images/beats-platform.png)
Beats 有多种类型,可以根据实际应用需要选择合适的类型。
常用的类型有:
- **Packetbeat**网络数据包分析器,提供有关您的应用程序服务器之间交换的事务的信息。
- **Filebeat**从您的服务器发送日志文件。
- **Metricbeat**是一个服务器监视代理程序,它定期从服务器上运行的操作系统和服务收集指标。
- **Winlogbeat**提供 Windows 事件日志。
### 4.1. Filebeat 简介
> *由于本人仅接触过 Filebeat所以本文只介绍 Beats 组件中的 Filebeat*
相比 LogstashFileBeat 更加轻量化。
在任何环境下,应用程序都有停机的可能性。 Filebeat 读取并转发日志行,如果中断,则会记住所有事件恢复联机状态时所在位置。
Filebeat 带有内部模块auditdApacheNginxSystem 和 MySQL可通过一个指定命令来简化通用日志格式的收集解析和可视化。
FileBeat 不会让你的管道超负荷。FileBeat 如果是向 Logstash 传输数据,当 Logstash 忙于处理数据,会通知 FileBeat 放慢读取速度。一旦拥塞得到解决FileBeat 将恢复到原来的速度并继续传播。
![img](https://www.elastic.co/guide/en/beats/filebeat/current/images/filebeat.png)
### 4.2. Filebeat 原理
Filebeat 有两个主要组件:
- `harvester`:负责读取一个文件的内容。它会逐行读取文件内容,并将内容发送到输出目的地。
- `prospector`:负责管理 harvester 并找到所有需要读取的文件源。比如类型是日志prospector 就会遍历制定路径下的所有匹配要求的文件。
```yaml
filebeat.prospectors:
- type: log
paths:
- /var/log/*.log
- /var/path2/*.log
```
Filebeat 保持每个文件的状态,并经常刷新注册表文件中的磁盘状态。状态用于记住 harvester 正在读取的最后偏移量,并确保发送所有日志行。
Filebeat 将每个事件的传递状态存储在注册表文件中。所以它能保证事件至少传递一次到配置的输出,没有数据丢失。
## 5. 运维
- [ElasticSearch 运维](nosql/elasticsearch/elasticsearch-ops.md)
- [Logstash 运维](nosql/elasticsearch/elastic/elastic-logstash-ops.mdstic/elastic-logstash-ops.md)
- [Kibana 运维](nosql/elasticsearch/elastic/elastic-kibana-ops.mdlastic/elastic-kibana-ops.md)
- [Beats 运维](nosql/elasticsearch/elastic/elastic-beats-ops.mdelastic/elastic-beats-ops.md)
## 6. 参考资料
- **官方资源**
- [Elasticsearch 官网](https://www.elastic.co/cn/products/elasticsearch)
- [Elasticsearch Github](https://github.com/elastic/elasticsearch)
- [Elasticsearch 官方文档](https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html)
- [Logstash 官网](https://www.elastic.co/cn/products/logstash)
- [Logstash Github](https://github.com/elastic/logstash)
- [Logstash 官方文档](https://www.elastic.co/guide/en/logstash/current/index.html)
- [Kibana 官网](https://www.elastic.co/cn/products/kibana)
- [Kibana Github](https://github.com/elastic/kibana)
- [Kibana 官方文档](https://www.elastic.co/guide/en/kibana/current/index.html)
- [Beats 官网](https://www.elastic.co/cn/products/beats)
- [Beats Github](https://github.com/elastic/beats)
- [Beats 官方文档](https://www.elastic.co/guide/en/beats/libbeat/current/index.html)
- **文章**
- [什么是 ELK Stack](https://www.elastic.co/cn/what-is/elk-stack)
- [https://github.com/doocs/advanced-java/blob/master/docs/high-concurrency/es-introduction.md](https://github.com/doocs/advanced-java/blob/master/docs/high-concurrency/es-introduction.md)
- [es-write-query-search](https://github.com/doocs/advanced-java/blob/master/docs/high-concurrency/es-write-query-search.md)

View File

@ -0,0 +1,359 @@
# Elasticsearch API
> **[Elasticsearch](https://github.com/elastic/elasticsearch) 是一个分布式、RESTful 风格的搜索和数据分析引擎**,能够解决不断涌现出的各种用例。 作为 Elastic Stack 的核心,它集中存储您的数据,帮助您发现意料之中以及意料之外的情况。
>
> [Elasticsearch](https://github.com/elastic/elasticsearch) 基于搜索库 [Lucene](https://github.com/apache/lucene-solr) 开发。ElasticSearch 隐藏了 Lucene 的复杂性,提供了简单易用的 REST API / Java API 接口(另外还有其他语言的 API 接口)。
>
> _以下简称 ES_
## 一、REST API
> REST API 最详尽的文档应该参考:[ES 官方 REST API](https://www.elastic.co/guide/en/elasticsearch/reference/current/rest-apis.html)
### 索引
新建 Index可以直接向 ES 服务器发出 `PUT` 请求。
#### 创建索引
示例:直接创建索引
```bash
curl -X POST 'localhost:9200/user'
```
服务器返回一个 JSON 对象,里面的 `acknowledged` 字段表示操作成功。
```javascript
{"acknowledged":true,"shards_acknowledged":true,"index":"user"}
```
示例:创建索引时指定配置
```bash
$ curl -X PUT -H 'Content-Type: application/json' 'localhost:9200/user' -d '
{
"settings" : {
"index" : {
"number_of_shards" : 3,
"number_of_replicas" : 2
}
}
}'
```
示例:创建索引时指定 `mappings`
```bash
$ curl -X PUT -H 'Content-Type: application/json' 'localhost:9200/user' -d '
{
"settings" : {
"index" : {
"number_of_shards" : 3,
"number_of_replicas" : 2
}
}
}'
```
#### 删除索引
然后,我们可以通过发送 `DELETE` 请求,删除这个 Index。
```bash
curl -X DELETE 'localhost:9200/user'
```
#### 查看索引
可以通过 GET 请求查看索引信息
```bash
curl -X GET 'localhost:9200/user'
```
#### 打开/关闭索引
通过在 `POST` 中添加 `_close``_open` 可以打开、关闭索引。
关闭索引
```bash
curl -X POST 'localhost:9200/user/_close'
```
打开索引
```bash
curl -X POST 'localhost:9200/user/_open'
```
### 文档
#### 新增记录
向指定的 `/Index/type` 发送 PUT 请求,就可以在 Index 里面新增一条记录。比如,向 `/user/admin` 发送请求,就可以新增一条人员记录。
```bash
$ curl -X PUT -H 'Content-Type: application/json' 'localhost:9200/user/admin/1' -d '
{
"user": "张三",
"title": "工程师",
"desc": "数据库管理"
}'
```
服务器返回的 JSON 对象,会给出 Index、Type、Id、Version 等信息。
```json
{
"_index": "user",
"_type": "admin",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": { "total": 3, "successful": 1, "failed": 0 },
"_seq_no": 0,
"_primary_term": 2
}
```
如果你仔细看,会发现请求路径是`/user/admin/1`,最后的`1`是该条记录的 Id。它不一定是数字任意字符串比如`abc`)都可以。
新增记录的时候,也可以不指定 Id这时要改成 POST 请求。
```bash
$ curl -X POST -H 'Content-Type: application/json' 'localhost:9200/user/admin' -d '
{
"user": "李四",
"title": "工程师",
"desc": "系统管理"
}'
```
上面代码中,向`/user/admin`发出一个 POST 请求,添加一个记录。这时,服务器返回的 JSON 对象里面,`_id`字段就是一个随机字符串。
```json
{
"_index": "user",
"_type": "admin",
"_id": "WWuoDG8BHwECs7SiYn93",
"_version": 1,
"result": "created",
"_shards": { "total": 3, "successful": 1, "failed": 0 },
"_seq_no": 1,
"_primary_term": 2
}
```
注意,如果没有先创建 Index这个例子是`accounts`直接执行上面的命令Elastic 也不会报错,而是直接生成指定的 Index。所以打字的时候要小心不要写错 Index 的名称。
#### 删除记录
删除记录就是发出 `DELETE` 请求。
```bash
curl -X DELETE 'localhost:9200/user/admin/2'
```
#### 更新记录
更新记录就是使用 `PUT` 请求,重新发送一次数据。
```bash
$ curl -X PUT -H 'Content-Type: application/json' 'localhost:9200/user/admin/1' -d '
{
"user": "张三",
"title": "工程师",
"desc": "超级管理员"
}'
```
#### 查询记录
向`/Index/Type/Id`发出 GET 请求,就可以查看这条记录。
```bash
curl 'localhost:9200/user/admin/1?pretty'
```
上面代码请求查看 `/user/admin/1` 这条记录URL 的参数 `pretty=true` 表示以易读的格式返回。
返回的数据中,`found` 字段表示查询成功,`_source`字段返回原始记录。
```json
{
"_index": "user",
"_type": "admin",
"_id": "1",
"_version": 2,
"found": true,
"_source": {
"user": "张三",
"title": "工程师",
"desc": "超级管理员"
}
}
```
如果 Id 不正确,就查不到数据,`found` 字段就是 `false`
#### 查询所有记录
使用 `GET` 方法,直接请求 `/index/type/_search`,就会返回所有记录。
```bash
$ curl 'localhost:9200/user/admin/_search?pretty'
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 3,
"successful" : 3,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 1.0,
"hits" : [
{
"_index" : "user",
"_type" : "admin",
"_id" : "WWuoDG8BHwECs7SiYn93",
"_score" : 1.0,
"_source" : {
"user" : "李四",
"title" : "工程师",
"desc" : "系统管理"
}
},
{
"_index" : "user",
"_type" : "admin",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"user" : "张三",
"title" : "工程师",
"desc" : "超级管理员"
}
}
]
}
}
```
上面代码中,返回结果的 `took`字段表示该操作的耗时(单位为毫秒),`timed_out`字段表示是否超时,`hits`字段表示命中的记录,里面子字段的含义如下。
- `total`:返回记录数,本例是 2 条。
- `max_score`:最高的匹配程度,本例是`1.0`。
- `hits`:返回的记录组成的数组。
返回的记录中,每条记录都有一个`_score`字段,表示匹配的程序,默认是按照这个字段降序排列。
#### 全文搜索
ES 的查询非常特别,使用自己的[查询语法](https://www.elastic.co/guide/en/elasticsearch/reference/5.5/query-dsl.html),要求 GET 请求带有数据体。
```bash
$ curl -H 'Content-Type: application/json' 'localhost:9200/user/admin/_search?pretty' -d '
{
"query" : { "match" : { "desc" : "管理" }}
}'
```
上面代码使用 [Match 查询](https://www.elastic.co/guide/en/elasticsearch/reference/5.5/query-dsl-match-query.html),指定的匹配条件是`desc`字段里面包含"软件"这个词。返回结果如下。
```javascript
{
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 3,
"successful" : 3,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : 2,
"max_score" : 0.38200712,
"hits" : [
{
"_index" : "user",
"_type" : "admin",
"_id" : "WWuoDG8BHwECs7SiYn93",
"_score" : 0.38200712,
"_source" : {
"user" : "李四",
"title" : "工程师",
"desc" : "系统管理"
}
},
{
"_index" : "user",
"_type" : "admin",
"_id" : "1",
"_score" : 0.3487891,
"_source" : {
"user" : "张三",
"title" : "工程师",
"desc" : "超级管理员"
}
}
]
}
}
```
Elastic 默认一次返回 10 条结果,可以通过`size`字段改变这个设置,还可以通过`from`字段,指定位移。
```bash
$ curl 'localhost:9200/user/admin/_search' -d '
{
"query" : { "match" : { "desc" : "管理" }},
"from": 1,
"size": 1
}'
```
上面代码指定,从位置 1 开始(默认是从位置 0 开始),只返回一条结果。
#### 逻辑运算
如果有多个搜索关键字, Elastic 认为它们是`or`关系。
```bash
$ curl 'localhost:9200/user/admin/_search' -d '
{
"query" : { "match" : { "desc" : "软件 系统" }}
}'
```
上面代码搜索的是`软件 or 系统`。
如果要执行多个关键词的`and`搜索,必须使用[布尔查询](https://www.elastic.co/guide/en/elasticsearch/reference/5.5/query-dsl-bool-query.html)。
```bash
$ curl -H 'Content-Type: application/json' 'localhost:9200/user/admin/_search?pretty' -d '
{
"query": {
"bool": {
"must": [
{ "match": { "desc": "管理" } },
{ "match": { "desc": "超级" } }
]
}
}
}'
```
## 二、Java API
TODO待补充...
## 参考资料
- **官方**
- [Elasticsearch 官网](https://www.elastic.co/cn/products/elasticsearch)
- [Elasticsearch Github](https://github.com/elastic/elasticsearch)
- [Elasticsearch 官方文档](https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html)

View File

@ -0,0 +1,629 @@
## 集群部署
ES 部署情况:
5 节点配置8 核 64 G 1T总计 320 G5 T。
约 10+ 索引5 分片,每日新增数据量约为 2G4000w 条。记录保存 30 天。
## 性能优化
### filesystem cache
你往 es 里写的数据,实际上都写到磁盘文件里去了,**查询的时候**,操作系统会将磁盘文件里的数据自动缓存到 `filesystem cache` 里面去。
[![es-search-process](https://github.com/doocs/advanced-java/raw/master/docs/high-concurrency/images/es-search-process.png)](https://github.com/doocs/advanced-java/blob/master/docs/high-concurrency/images/es-search-process.png)
es 的搜索引擎严重依赖于底层的 `filesystem cache` ,你如果给 `filesystem cache` 更多的内存,尽量让内存可以容纳所有的 `idx segment file`索引数据文件,那么你搜索的时候就基本都是走内存的,性能会非常高。
性能差距究竟可以有多大我们之前很多的测试和压测如果走磁盘一般肯定上秒搜索性能绝对是秒级别的1 秒、5 秒、10 秒。但如果是走 `filesystem cache` ,是走纯内存的,那么一般来说性能比走磁盘要高一个数量级,基本上就是毫秒级的,从几毫秒到几百毫秒不等。
这里有个真实的案例。某个公司 es 节点有 3 台机器每台机器看起来内存很多64G总内存就是 `64 * 3 = 192G` 。每台机器给 es jvm heap 是 `32G` ,那么剩下来留给 `filesystem cache` 的就是每台机器才 `32G` ,总共集群里给 `filesystem cache` 的就是 `32 * 3 = 96G` 内存。而此时,整个磁盘上索引数据文件,在 3 台机器上一共占用了 `1T` 的磁盘容量es 数据量是 `1T` ,那么每台机器的数据量是 `300G` 。这样性能好吗? `filesystem cache` 的内存才 100G十分之一的数据可以放内存其他的都在磁盘然后你执行搜索操作大部分操作都是走磁盘性能肯定差。
归根结底,你要让 es 性能要好,最佳的情况下,就是你的机器的内存,至少可以容纳你的总数据量的一半。
根据我们自己的生产环境实践经验,最佳的情况下,是仅仅在 es 中就存少量的数据,就是你要**用来搜索的那些索引**,如果内存留给 `filesystem cache` 的是 100G那么你就将索引数据控制在 `100G` 以内,这样的话,你的数据几乎全部走内存来搜索,性能非常之高,一般可以在 1 秒以内。
比如说你现在有一行数据。 `id,name,age ....` 30 个字段。但是你现在搜索,只需要根据 `id,name,age` 三个字段来搜索。如果你傻乎乎往 es 里写入一行数据所有的字段,就会导致说 `90%` 的数据是不用来搜索的,结果硬是占据了 es 机器上的 `filesystem cache` 的空间,单条数据的数据量越大,就会导致 `filesystem cahce` 能缓存的数据就越少。其实,仅仅写入 es 中要用来检索的**少数几个字段**就可以了,比如说就写入 es `id,name,age` 三个字段,然后你可以把其他的字段数据存在 mysql/hbase 里,我们一般是建议用 `es + hbase` 这么一个架构。
hbase 的特点是**适用于海量数据的在线存储**,就是对 hbase 可以写入海量数据,但是不要做复杂的搜索,做很简单的一些根据 id 或者范围进行查询的这么一个操作就可以了。从 es 中根据 name 和 age 去搜索,拿到的结果可能就 20 个 `doc id` ,然后根据 `doc id` 到 hbase 里去查询每个 `doc id` 对应的**完整的数据**,给查出来,再返回给前端。
写入 es 的数据最好小于等于,或者是略微大于 es 的 filesystem cache 的内存容量。然后你从 es 检索可能就花费 20ms然后再根据 es 返回的 id 去 hbase 里查询,查 20 条数据,可能也就耗费个 30ms可能你原来那么玩儿1T 数据都放 es会每次查询都是 5~10s现在可能性能就会很高每次查询就是 50ms。
### 数据预热
假如说哪怕是你就按照上述的方案去做了es 集群中每个机器写入的数据量还是超过了 `filesystem cache` 一倍,比如说你写入一台机器 60G 数据,结果 `filesystem cache` 就 30G还是有 30G 数据留在了磁盘上。
其实可以做**数据预热**。
举个例子,拿微博来说,你可以把一些大 V平时看的人很多的数据你自己提前后台搞个系统每隔一会儿自己的后台系统去搜索一下热数据刷到 `filesystem cache` 里去,后面用户实际上来看这个热数据的时候,他们就是直接从内存里搜索了,很快。
或者是电商,你可以将平时查看最多的一些商品,比如说 iphone 8热数据提前后台搞个程序每隔 1 分钟自己主动访问一次,刷到 `filesystem cache` 里去。
对于那些你觉得比较热的、经常会有人访问的数据,最好**做一个专门的缓存预热子系统**,就是对热数据每隔一段时间,就提前访问一下,让数据进入 `filesystem cache` 里面去。这样下次别人访问的时候,性能一定会好很多。
### 冷热分离
es 可以做类似于 mysql 的水平拆分,就是说将大量的访问很少、频率很低的数据,单独写一个索引,然后将访问很频繁的热数据单独写一个索引。最好是将**冷数据写入一个索引中,然后热数据写入另外一个索引中**,这样可以确保热数据在被预热之后,尽量都让他们留在 `filesystem os cache` 里,**别让冷数据给冲刷掉**。
你看,假设你有 6 台机器2 个索引,一个放冷数据,一个放热数据,每个索引 3 个 shard。3 台机器放热数据 index另外 3 台机器放冷数据 index。然后这样的话你大量的时间是在访问热数据 index热数据可能就占总数据量的 10%,此时数据量很少,几乎全都保留在 `filesystem cache` 里面了,就可以确保热数据的访问性能是很高的。但是对于冷数据而言,是在别的 index 里的,跟热数据 index 不在相同的机器上,大家互相之间都没什么联系了。如果有人访问冷数据,可能大量数据是在磁盘上的,此时性能差点,就 10% 的人去访问冷数据90% 的人在访问热数据,也无所谓了。
### document 模型设计
对于 MySQL我们经常有一些复杂的关联查询。在 es 里该怎么玩儿es 里面的复杂的关联查询尽量别用,一旦用了性能一般都不太好。
最好是先在 Java 系统里就完成关联,将关联好的数据直接写入 es 中。搜索的时候,就不需要利用 es 的搜索语法来完成 join 之类的关联搜索了。
document 模型设计是非常重要的很多操作不要在搜索的时候才想去执行各种复杂的乱七八糟的操作。es 能支持的操作就那么多,不要考虑用 es 做一些它不好操作的事情。如果真的有那种操作,尽量在 document 模型设计的时候,写入的时候就完成。另外对于一些太复杂的操作,比如 join/nested/parent-child 搜索都要尽量避免,性能都很差的。
### 分页性能优化
es 的分页是较坑的,为啥呢?举个例子吧,假如你每页是 10 条数据,你现在要查询第 100 页,实际上是会把每个 shard 上存储的前 1000 条数据都查到一个协调节点上,如果你有个 5 个 shard那么就有 5000 条数据,接着协调节点对这 5000 条数据进行一些合并、处理,再获取到最终第 100 页的 10 条数据。
分布式的,你要查第 100 页的 10 条数据,不可能说从 5 个 shard每个 shard 就查 2 条数据,最后到协调节点合并成 10 条数据吧?你**必须**得从每个 shard 都查 1000 条数据过来,然后根据你的需求进行排序、筛选等等操作,最后再次分页,拿到里面第 100 页的数据。你翻页的时候,翻的越深,每个 shard 返回的数据就越多,而且协调节点处理的时间越长,非常坑爹。所以用 es 做分页的时候,你会发现越翻到后面,就越是慢。
我们之前也是遇到过这个问题,用 es 作分页,前几页就几十毫秒,翻到 10 页或者几十页的时候,基本上就要 5~10 秒才能查出来一页数据了。
有什么解决方案吗?
#### 不允许深度分页(默认深度分页性能很差)
跟产品经理说,你系统不允许翻那么深的页,默认翻的越深,性能就越差。
#### 类似于 app 里的推荐商品不断下拉出来一页一页的
类似于微博中,下拉刷微博,刷出来一页一页的,你可以用 `scroll api` ,关于如何使用,自行上网搜索。
scroll 会一次性给你生成**所有数据的一个快照**,然后每次滑动向后翻页就是通过**游标** `scroll_id` 移动,获取下一页下一页这样子,性能会比上面说的那种分页性能要高很多很多,基本上都是毫秒级的。
但是,唯一的一点就是,这个适合于那种类似微博下拉翻页的,**不能随意跳到任何一页的场景**。也就是说,你不能先进入第 10 页,然后去第 120 页,然后又回到第 58 页不能随意乱跳页。所以现在很多产品都是不允许你随意翻页的app也有一些网站做的就是你只能往下拉一页一页的翻。
初始化时必须指定 `scroll` 参数,告诉 es 要保存此次搜索的上下文多长时间。你需要确保用户不会持续不断翻页翻几个小时,否则可能因为超时而失败。
除了用 `scroll api` ,你也可以用 `search_after` 来做, `search_after` 的思想是使用前一页的结果来帮助检索下一页的数据,显然,这种方式也不允许你随意翻页,你只能一页页往后翻。初始化时,需要使用一个唯一值的字段作为 sort 字段。
**1.1、设计阶段调优**
1根据业务增量需求采取基于日期模板创建索引通过 roll over API 滚动索引;
2使用别名进行索引管理
3每天凌晨定时对索引做 force_merge 操作,以释放空间;
4采取冷热分离机制热数据存储到 SSD提高检索效率冷数据定期进行 shrink 操作,以缩减存储;
5采取 curator 进行索引的生命周期管理;
6仅针对需要分词的字段合理的设置分词器
7Mapping 阶段充分结合各个字段的属性,是否需要检索、是否需要存储等。……..
**1.2、写入调优**
1写入前副本数设置为 0
2写入前关闭 refresh_interval 设置为-1禁用刷新机制
3写入过程中采取 bulk 批量写入;
4写入后恢复副本数和刷新间隔
5尽量使用自动生成的 id。
1.3、查询调优
1禁用 wildcard
2禁用批量 terms成百上千的场景
3充分利用倒排索引机制能 keyword 类型尽量 keyword
4数据量大时候可以先基于时间敲定索引再检索
5设置合理的路由机制。
1.4、其他调优
部署调优,业务调优等。
上面的提及一部分,面试者就基本对你之前的实践或者运维经验有所评估了。
## 工作原理
### es 写数据过程
- 客户端选择一个 node 发送请求过去,这个 node 就是 `coordinating node` (协调节点)。
- `coordinating node` 对 document 进行**路由**,将请求转发给对应的 node有 primary shard
- 实际的 node 上的 `primary shard` 处理请求,然后将数据同步到 `replica node`
- `coordinating node` 如果发现 `primary node` 和所有 `replica node` 都搞定之后,就返回响应结果给客户端。
[![es-write](https://github.com/doocs/advanced-java/raw/master/docs/high-concurrency/images/es-write.png)](https://github.com/doocs/advanced-java/blob/master/docs/high-concurrency/images/es-write.png)
### es 读数据过程
可以通过 `doc id` 来查询,会根据 `doc id` 进行 hash判断出来当时把 `doc id` 分配到了哪个 shard 上面去,从那个 shard 去查询。
- 客户端发送请求到**任意**一个 node成为 `coordinate node`
- `coordinate node``doc id` 进行哈希路由,将请求转发到对应的 node此时会使用 `round-robin` **随机轮询算法**,在 `primary shard` 以及其所有 replica 中随机选择一个,让读请求负载均衡。
- 接收请求的 node 返回 document 给 `coordinate node`
- `coordinate node` 返回 document 给客户端。
### es 搜索数据过程
es 最强大的是做全文检索,就是比如你有三条数据:
```
java真好玩儿啊
java好难学啊
j2ee特别牛
```
你根据 `java` 关键词来搜索,将包含 `java``document` 给搜索出来。es 就会给你返回java 真好玩儿啊java 好难学啊。
- 客户端发送请求到一个 `coordinate node`
- 协调节点将搜索请求转发到**所有**的 shard 对应的 `primary shard``replica shard` ,都可以。
- query phase每个 shard 将自己的搜索结果(其实就是一些 `doc id` )返回给协调节点,由协调节点进行数据的合并、排序、分页等操作,产出最终结果。
- fetch phase接着由协调节点根据 `doc id` 去各个节点上**拉取实际**的 `document` 数据,最终返回给客户端。
> 写请求是写入 primary shard然后同步给所有的 replica shard读请求可以从 primary shard 或 replica shard 读取,采用的是随机轮询算法。
### 写数据底层原理
[![es-write-detail](https://github.com/doocs/advanced-java/raw/master/docs/high-concurrency/images/es-write-detail.png)](https://github.com/doocs/advanced-java/blob/master/docs/high-concurrency/images/es-write-detail.png)
先写入内存 buffer在 buffer 里的时候数据是搜索不到的;同时将数据写入 translog 日志文件。
如果 buffer 快满了,或者到一定时间,就会将内存 buffer 数据 `refresh` 到一个新的 `segment file` 中,但是此时数据不是直接进入 `segment file` 磁盘文件,而是先进入 `os cache` 。这个过程就是 `refresh`
每隔 1 秒钟es 将 buffer 中的数据写入一个**新的** `segment file` ,每秒钟会产生一个**新的磁盘文件** `segment file` ,这个 `segment file` 中就存储最近 1 秒内 buffer 中写入的数据。
但是如果 buffer 里面此时没有数据,那当然不会执行 refresh 操作,如果 buffer 里面有数据,默认 1 秒钟执行一次 refresh 操作,刷入一个新的 segment file 中。
操作系统里面,磁盘文件其实都有一个东西,叫做 `os cache` ,即操作系统缓存,就是说数据写入磁盘文件之前,会先进入 `os cache` ,先进入操作系统级别的一个内存缓存中去。只要 `buffer` 中的数据被 refresh 操作刷入 `os cache` 中,这个数据就可以被搜索到了。
为什么叫 es 是**准实时**的? `NRT` ,全称 `near real-time` 。默认是每隔 1 秒 refresh 一次的,所以 es 是准实时的,因为写入的数据 1 秒之后才能被看到。可以通过 es 的 `restful api` 或者 `java api` **手动**执行一次 refresh 操作,就是手动将 buffer 中的数据刷入 `os cache` 中,让数据立马就可以被搜索到。只要数据被输入 `os cache`buffer 就会被清空了,因为不需要保留 buffer 了,数据在 translog 里面已经持久化到磁盘去一份了。
重复上面的步骤,新的数据不断进入 buffer 和 translog不断将 `buffer` 数据写入一个又一个新的 `segment file` 中去,每次 `refresh` 完 buffer 清空translog 保留。随着这个过程推进translog 会变得越来越大。当 translog 达到一定长度的时候,就会触发 `commit` 操作。
commit 操作发生第一步,就是将 buffer 中现有数据 `refresh``os cache` 中去,清空 buffer。然后将一个 `commit point` 写入磁盘文件,里面标识着这个 `commit point` 对应的所有 `segment file` ,同时强行将 `os cache` 中目前所有的数据都 `fsync` 到磁盘文件中去。最后**清空** 现有 translog 日志文件,重启一个 translog此时 commit 操作完成。
这个 commit 操作叫做 `flush` 。默认 30 分钟自动执行一次 `flush` ,但如果 translog 过大,也会触发 `flush` 。flush 操作就对应着 commit 的全过程,我们可以通过 es api手动执行 flush 操作,手动将 os cache 中的数据 fsync 强刷到磁盘上去。
translog 日志文件的作用是什么?你执行 commit 操作之前,数据要么是停留在 buffer 中,要么是停留在 os cache 中,无论是 buffer 还是 os cache 都是内存,一旦这台机器死了,内存中的数据就全丢了。所以需要将数据对应的操作写入一个专门的日志文件 `translog`一旦此时机器宕机再次重启的时候es 会自动读取 translog 日志文件中的数据,恢复到内存 buffer 和 os cache 中去。
translog 其实也是先写入 os cache 的,默认每隔 5 秒刷一次到磁盘中去,所以默认情况下,可能有 5 秒的数据会仅仅停留在 buffer 或者 translog 文件的 os cache 中,如果此时机器挂了,会**丢失** 5 秒钟的数据。但是这样性能比较好,最多丢 5 秒的数据。也可以将 translog 设置成每次写操作必须是直接 `fsync` 到磁盘,但是性能会差很多。
实际上你在这里,如果面试官没有问你 es 丢数据的问题,你可以在这里给面试官炫一把,你说,其实 es 第一是准实时的,数据写入 1 秒后可以搜索到;可能会丢失数据的。有 5 秒的数据,停留在 buffer、translog os cache、segment file os cache 中,而不在磁盘上,此时如果宕机,会导致 5 秒的**数据丢失**。
**总结一下**,数据先写入内存 buffer然后每隔 1s将数据 refresh 到 os cache到了 os cache 数据就能被搜索到(所以我们才说 es 从写入到能被搜索到,中间有 1s 的延迟)。每隔 5s将数据写入 translog 文件(这样如果机器宕机,内存数据全没,最多会有 5s 的数据丢失translog 大到一定程度,或者默认每隔 30mins会触发 commit 操作,将缓冲区的数据都 flush 到 segment file 磁盘文件中。
> 数据写入 segment file 之后,同时就建立好了倒排索引。
### 删除/更新数据底层原理
如果是删除操作commit 的时候会生成一个 `.del` 文件,里面将某个 doc 标识为 `deleted` 状态,那么搜索的时候根据 `.del` 文件就知道这个 doc 是否被删除了。
如果是更新操作,就是将原来的 doc 标识为 `deleted` 状态,然后新写入一条数据。
buffer 每 refresh 一次,就会产生一个 `segment file` ,所以默认情况下是 1 秒钟一个 `segment file` ,这样下来 `segment file` 会越来越多,此时会定期执行 merge。每次 merge 的时候,会将多个 `segment file` 合并成一个,同时这里会将标识为 `deleted` 的 doc 给**物理删除掉**,然后将新的 `segment file` 写入磁盘,这里会写一个 `commit point` ,标识所有新的 `segment file` ,然后打开 `segment file` 供搜索使用,同时删除旧的 `segment file`
### 底层 lucene
简单来说lucene 就是一个 jar 包,里面包含了封装好的各种建立倒排索引的算法代码。我们用 Java 开发的时候,引入 lucene jar然后基于 lucene 的 api 去开发就可以了。
通过 lucene我们可以将已有的数据建立索引lucene 会在本地磁盘上面,给我们组织索引的数据结构。
### 倒排索引
在搜索引擎中,每个文档都有一个对应的文档 ID文档内容被表示为一系列关键词的集合。例如文档 1 经过分词,提取了 20 个关键词,每个关键词都会记录它在文档中出现的次数和出现位置。
那么,倒排索引就是**关键词到文档** ID 的映射,每个关键词都对应着一系列的文件,这些文件中都出现了关键词。
举个栗子。
有以下文档:
| DocId | Doc |
| ----- | ---------------------------------------------- |
| 1 | 谷歌地图之父跳槽 Facebook |
| 2 | 谷歌地图之父加盟 Facebook |
| 3 | 谷歌地图创始人拉斯离开谷歌加盟 Facebook |
| 4 | 谷歌地图之父跳槽 Facebook 与 Wave 项目取消有关 |
| 5 | 谷歌地图之父拉斯加盟社交网站 Facebook |
对文档进行分词之后,得到以下**倒排索引**。
| WordId | Word | DocIds |
| ------ | -------- | ------------- |
| 1 | 谷歌 | 1, 2, 3, 4, 5 |
| 2 | 地图 | 1, 2, 3, 4, 5 |
| 3 | 之父 | 1, 2, 4, 5 |
| 4 | 跳槽 | 1, 4 |
| 5 | Facebook | 1, 2, 3, 4, 5 |
| 6 | 加盟 | 2, 3, 5 |
| 7 | 创始人 | 3 |
| 8 | 拉斯 | 3, 5 |
| 9 | 离开 | 3 |
| 10 | 与 | 4 |
| .. | .. | .. |
另外,实用的倒排索引还可以记录更多的信息,比如文档频率信息,表示在文档集合中有多少个文档包含某个单词。
那么,有了倒排索引,搜索引擎可以很方便地响应用户的查询。比如用户输入查询 `Facebook` ,搜索系统查找倒排索引,从中读出包含这个单词的文档,这些文档就是提供给用户的搜索结果。
要注意倒排索引的两个重要细节:
- 倒排索引中的所有词项对应一个或多个文档;
- 倒排索引中的词项**根据字典顺序升序排列**
> 上面只是一个简单的栗子,并没有严格按照字典顺序升序排列。
## elasticsearch 的倒排索引是什么
面试官:想了解你对基础概念的认知。
解答:通俗解释一下就可以。
传统的我们的检索是通过文章,逐个遍历找到对应关键词的位置。
而倒排索引,是通过分词策略,形成了词和文章的映射关系表,这种词典+映射表即为倒排索引。有了倒排索引,就能实现 o1时间复杂度的效率检索文章了极大的提高了检索效率。
![img](https://pic3.zhimg.com/80/v2-bf18227dc4554da0dcc7b970dbd582ae_720w.jpg)
学术的解答方式:
倒排索引,相反于一篇文章包含了哪些词,它从词出发,记载了这个词在哪些文档中出现过,由两部分组成——词典和倒排表。
加分项倒排索引的底层实现是基于FSTFinite State Transducer数据结构。
lucene 从 4+版本后开始大量使用的数据结构是 FST。FST 有两个优点:
1空间占用小。通过对词典中单词前缀和后缀的重复利用压缩了存储空间
2查询速度快。O(len(str))的查询时间复杂度。
## 3、elasticsearch 索引数据多了怎么办,如何调优,部署
面试官:想了解大数据量的运维能力。
解答:索引数据的规划,应在前期做好规划,正所谓“设计先行,编码在后”,这样才能有效的避免突如其来的数据激增导致集群处理能力不足引发的线上客户检索或者其他业务受到影响。
如何调优,正如问题 1 所说,这里细化一下:
**3.1 动态索引层面**
基于模板+时间+rollover api 滚动创建索引举例设计阶段定义blog 索引的模板格式为blog*index*时间戳的形式,每天递增数据。这样做的好处:不至于数据量激增导致单个索引数据量非常大,接近于上线 2 的 32 次幂-1索引存储达到了 TB+甚至更大。
一旦单个索引很大,存储等各种风险也随之而来,所以要提前考虑+及早避免。
**3.2 存储层面**
冷热数据分离存储,热数据(比如最近 3 天或者一周的数据),其余为冷数据。
对于冷数据不会再写入新数据,可以考虑定期 force_merge 加 shrink 压缩操作,节省存储空间和检索效率。
**3.3 部署层面**
一旦之前没有规划,这里就属于应急策略。
结合 ES 自身的支持动态扩展的特点,动态新增机器的方式可以缓解集群压力,注意:如果之前主节点等规划合理,不需要重启集群也能完成动态新增的。
## 4、elasticsearch 是如何实现 master 选举的
面试官:想了解 ES 集群的底层原理,不再只关注业务层面了。
解答:
前置前提:
1只有候选主节点mastertrue的节点才能成为主节点。
2最小主节点数min_master_nodes的目的是防止脑裂。
核对了一下代码,核心入口为 findMaster选择主节点成功返回对应 Master否则返回 null。选举流程大致描述如下
第一步确认候选主节点数达标elasticsearch.yml 设置的值
discovery.zen.minimum_master_nodes
第二步:比较:先判定是否具备 master 资格,具备候选主节点资格的优先返回;
若两节点都为候选主节点,则 id 小的值会主节点。注意这里的 id 为 string 类型。
题外话:获取节点 id 的方法。
```text
1GET /_cat/nodes?v&h=ip,port,heapPercent,heapMax,id,name
2ip port heapPercent heapMax id name
```
## 详细描述一下 Elasticsearch 索引文档的过程
面试官:想了解 ES 的底层原理,不再只关注业务层面了。
解答:
这里的索引文档应该理解为文档写入 ES创建索引的过程。
文档写入包含:单文档写入和批量 bulk 写入,这里只解释一下:单文档写入流程。
记住官方文档中的这个图。
![img](https://pic3.zhimg.com/80/v2-bf1b23846420eb4fdace5c6415ad7cf2_720w.jpg)
第一步:客户写集群某节点写入数据,发送请求。(如果没有指定路由/协调节点,请求的节点扮演路由节点的角色。)
第二步:节点 1 接受到请求后,使用文档\_id 来确定文档属于分片 0。请求会被转到另外的节点假定节点 3。因此分片 0 的主分片分配到节点 3 上。
第三步:节点 3 在主分片上执行写操作,如果成功,则将请求并行转发到节点 1 和节点 2 的副本分片上,等待结果返回。所有的副本分片都报告成功,节点 3 将向协调节点(节点 1报告成功节点 1 向请求客户端报告写入成功。
如果面试官再问:第二步中的文档获取分片的过程?
回答:借助路由算法获取,路由算法就是根据路由和文档 id 计算目标的分片 id 的过程。
```text
1shard = hash(_routing) % (num_of_primary_shards)
```
## 详细描述一下 Elasticsearch 搜索的过程?
面试官:想了解 ES 搜索的底层原理,不再只关注业务层面了。
解答:
搜索拆解为“query then fetch” 两个阶段。
query 阶段的目的:定位到位置,但不取。
步骤拆解如下:
1假设一个索引数据有 5 主+1 副本 共 10 分片,一次请求会命中(主或者副本分片中)的一个。
2每个分片在本地进行查询结果返回到本地有序的优先队列中。
3第 2步骤的结果发送到协调节点协调节点产生一个全局的排序列表。
fetch 阶段的目的:取数据。
路由节点获取所有文档,返回给客户端。
## Elasticsearch 在部署时,对 Linux 的设置有哪些优化方法
面试官:想了解对 ES 集群的运维能力。
解答:
1关闭缓存 swap;
2堆内存设置为Min节点内存/2, 32GB;
3设置最大文件句柄数
4线程池+队列大小根据业务需要做调整;
5磁盘存储 raid 方式——存储有条件使用 RAID10增加单节点性能以及避免单节点存储故障。
## lucence 内部结构是什么?
面试官:想了解你的知识面的广度和深度。
解答:
![img](https://pic1.zhimg.com/80/v2-576954e3b238870ec089d68abe0de1d4_720w.jpg)
Lucene 是有索引和搜索的两个过程,包含索引创建,索引,搜索三个要点。可以基于这个脉络展开一些。
## Elasticsearch 是如何实现 Master 选举的?
1Elasticsearch 的选主是 ZenDiscovery 模块负责的,主要包含 Ping节点之间通过这个 RPC 来发现彼此)和 Unicast单播模块包含一个主机列表以控制哪些节点需要 ping 通)这两部分;
2对所有可以成为 master 的节点node.master: true根据 nodeId 字典排序,每次选举每个节点都把自己所知道节点排一次序,然后选出第一个(第 0 位)节点,暂且认为它是 master 节点。
3如果对某个节点的投票数达到一定的值可以成为 master 节点数 n/2+1并且该节点自己也选举自己那这个节点就是 master。否则重新选举一直到满足上述条件。
4补充master 节点的职责主要包括集群、节点和索引的管理不负责文档级别的管理data 节点可以关闭 http 功能\*。
## 10、Elasticsearch 中的节点(比如共 20 个),其中的 10 个
选了一个 master另外 10 个选了另一个 master怎么办
1当集群 master 候选数量不小于 3 个时可以通过设置最少投票通过数量discovery.zen.minimum_master_nodes超过所有候选节点一半以上来解决脑裂问题
3当候选数量为两个时只能修改为唯一的一个 master 候选,其他作为 data 节点,避免脑裂问题。
## 客户端在和集群连接时,如何选择特定的节点执行请求的?
TransportClient 利用 transport 模块远程连接一个 elasticsearch 集群。它并不加入到集群中,只是简单的获得一个或者多个初始化的 transport 地址,并以 轮询 的方式与这些地址进行通信。
## 详细描述一下 Elasticsearch 索引文档的过程。
协调节点默认使用文档 ID 参与计算(也支持通过 routing以便为路由提供合适的分片。
```text
shard = hash(document_id) % (num_of_primary_shards)
```
1当分片所在的节点接收到来自协调节点的请求后会将请求写入到 MemoryBuffer然后定时默认是每隔 1 秒)写入到 Filesystem Cache这个从 MomeryBuffer 到 Filesystem Cache 的过程就叫做 refresh
2当然在某些情况下存在 Momery Buffer 和 Filesystem Cache 的数据可能会丢失ES 是通过 translog 的机制来保证数据的可靠性的。其实现机制是接收到请求后,同时也会写入到 translog 中 ,当 Filesystem cache 中的数据写入到磁盘中时,才会清除掉,这个过程叫做 flush
3在 flush 过程中,内存中的缓冲将被清除,内容被写入一个新段,段的 fsync 将创建一个新的提交点,并将内容刷新到磁盘,旧的 translog 将被删除并开始一个新的 translog。
4flush 触发的时机是定时触发(默认 30 分钟)或者 translog 变得太大(默认为 512M
![img](https://pic4.zhimg.com/80/v2-5e0c4bfbd57a4fae4895c480aaaa0a37_720w.jpg)
补充:关于 Lucene 的 Segement
1Lucene 索引是由多个段组成,段本身是一个功能齐全的倒排索引。
2段是不可变的允许 Lucene 将新的文档增量地添加到索引中,而不用从头重建索引。
3对于每一个搜索请求而言索引中的所有段都会被搜索并且每个段会消耗 CPU 的时钟周、文件句柄和内存。这意味着段的数量越多,搜索性能会越低。
4为了解决这个问题Elasticsearch 会合并小段到一个较大的段,提交新的合并段到磁盘,并删除那些旧的小段。
## 详细描述一下 Elasticsearch 更新和删除文档的过程。
1删除和更新也都是写操作但是 Elasticsearch 中的文档是不可变的,因此不能被删除或者改动以展示其变更;
2磁盘上的每个段都有一个相应的.del 文件。当删除请求发送后,文档并没有真的被删除,而是在.del 文件中被标记为删除。该文档依然能匹配查询,但是会在结果中被过滤掉。当段合并时,在.del 文件中被标记为删除的文档将不会被写入新段。
3在新的文档被创建时Elasticsearch 会为该文档指定一个版本号,当执行更新时,旧版本的文档在.del 文件中被标记为删除,新版本的文档被索引到一个新段。旧版本的文档依然能匹配查询,但是会在结果中被过滤掉。
## 详细描述一下 Elasticsearch 搜索的过程。
1搜索被执行成一个两阶段过程我们称之为 Query Then Fetch
2在初始查询阶段时查询会广播到索引中每一个分片拷贝主分片或者副本分片。 每个分片在本地执行搜索并构建一个匹配文档的大小为 from + size 的优先队列。
PS在搜索的时候是会查询 Filesystem Cache 的,但是有部分数据还在 MemoryBuffer所以搜索是近实时的。
3每个分片返回各自优先队列中 所有文档的 ID 和排序值 给协调节点,它合并这些值到自己的优先队列中来产生一个全局排序后的结果列表。
4接下来就是 取回阶段,协调节点辨别出哪些文档需要被取回并向相关的分片提交多个 GET 请求。每个分片加载并 丰 富 文档,如果有需要的话,接着返回文档给协调节点。一旦所有的文档都被取回了,协调节点返回结果给客户端。
5补充Query Then Fetch 的搜索类型在文档相关性打分的时候参考的是本分片的数据这样在文档数量较少的时候可能不够准确DFS Query Then Fetch 增加了一个预查询的处理,询问 Term 和 Document frequency这个评分更准确但是性能会变差。\*
![img](https://pic2.zhimg.com/80/v2-4c25616e623de2aee23bd63ec22a5bfd_720w.jpg)
## 在 Elasticsearch 中,是怎么根据一个词找到对应的倒排索引的?
1Lucene 的索引过程,就是按照全文检索的基本过程,将倒排表写成此文件格式的过程。
2Lucene 的搜索过程,就是按照此文件格式将索引进去的信息读出来,然后计算每篇文档打分(score)的过程。
## Elasticsearch 在部署时,对 Linux 的设置有哪些优化方法?
164 GB 内存的机器是非常理想的, 但是 32 GB 和 16 GB 机器也是很常见的。少于 8 GB 会适得其反。
2如果你要在更快的 CPUs 和更多的核心之间选择,选择更多的核心更好。多个内核提供的额外并发远胜过稍微快一点点的时钟频率。
3如果你负担得起 SSD它将远远超出任何旋转介质。 基于 SSD 的节点查询和索引性能都有提升。如果你负担得起SSD 是一个好的选择。
4即使数据中心们近在咫尺也要避免集群跨越多个数据中心。绝对要避免集群跨越大的地理距离。
5请确保运行你应用程序的 JVM 和服务器的 JVM 是完全一样的。 在 Elasticsearch 的几个地方,使用 Java 的本地序列化。
6通过设置 gateway.recover_after_nodes、gateway.expected_nodes、gateway.recover_after_time 可以在集群重启的时候避免过多的分片交换,这可能会让数据恢复从数个小时缩短为几秒钟。
7Elasticsearch 默认被配置为使用单播发现,以防止节点无意中加入集群。只有在同一台机器上运行的节点才会自动组成集群。最好使用单播代替组播。
8不要随意修改垃圾回收器CMS和各个线程池的大小。
9把你的内存的少于一半给 Lucene但不要超过 32 GB通过 ES_HEAP_SIZE 环境变量设置。
10内存交换到磁盘对服务器性能来说是致命的。如果内存交换到磁盘上一个 100 微秒的操作可能变成 10 毫秒。 再想想那么多 10 微秒的操作时延累加起来。 不难看出 swapping 对于性能是多么可怕。
11Lucene 使用了大 量 的文件。同时Elasticsearch 在节点和 HTTP 客户端之间进行通信也使用了大量的套接字。 所有这一切都需要足够的文件描述符。你应该增加你的文件描述符,设置一个很大的值,如 64,000。
补充:索引阶段性能提升方法
1使用批量请求并调整其大小每次批量数据 515 MB 大是个不错的起始点。
2存储使用 SSD
3段和合并Elasticsearch 默认值是 20 MB/s对机械磁盘应该是个不错的设置。如果你用的是 SSD可以考虑提高到 100200 MB/s。如果你在做批量导入完全不在意搜索你可以彻底关掉合并限流。另外还可以增加 index.translog.flush_threshold_size 设置,从默认的 512 MB 到更大一些的值,比如 1 GB这可以在一次清空触发的时候在事务日志里积累出更大的段。
4如果你的搜索结果不需要近实时的准确度考虑把每个索引的 index.refresh_interval 改到 30s。
5如果你在做大批量导入考虑通过设置 index.number_of_replicas: 0 关闭副本。
## 对于 GC 方面,在使用 Elasticsearch 时要注意什么?
1倒排词典的索引需要常驻内存无法 GC需要监控 data node 上 segmentmemory 增长趋势。
2各类缓存field cache, filter cache, indexing cache, bulk queue 等等,要设置合理的大小,并且要应该根据最坏的情况来看 heap 是否够用,也就是各类缓存全部占满的时候,还有 heap 空间可以分配给其他任务吗?避免采用 clear cache 等“自欺欺人”的方式来释放内存。
3避免返回大量结果集的搜索与聚合。确实需要大量拉取数据的场景可以采用 scan & scroll api 来实现。
4cluster stats 驻留内存并无法水平扩展,超大规模集群可以考虑分拆成多个集群通过 tribe node 连接。
5想知道 heap 够不够,必须结合实际应用场景,并对集群的 heap 使用情况做持续的监控。
6根据监控数据理解内存需求合理配置各类 circuit breaker将内存溢出风险降低到最低
## 18、Elasticsearch 对于大数据量(上亿量级)的聚合如何实现?
Elasticsearch 提供的首个近似聚合是 cardinality 度量。它提供一个字段的基数,即该字段的 distinct 或者 unique 值的数目。它是基于 HLL 算法的。HLL 会先对我们的输入作哈希运算,然后根据哈希运算的结果中的 bits 做概率估算从而得到基数。其特点是:可配置的精度,用来控制内存的使用(更精确 更多内存);小的数据集精度是非常高的;我们可以通过配置参数,来设置去重需要的固定内存使用量。无论数千还是数十亿的唯一值,内存使用量只与你配置的精确度相关。
## 19、在并发情况下Elasticsearch 如果保证读写一致?
1可以通过版本号使用乐观并发控制以确保新版本不会被旧版本覆盖由应用层来处理具体的冲突
2另外对于写操作一致性级别支持 quorum/one/all默认为 quorum即只有当大多数分片可用时才允许写操作。但即使大多数可用也可能存在因为网络等原因导致写入副本失败这样该副本被认为故障分片将会在一个不同的节点上重建。
3对于读操作可以设置 replication 为 sync(默认),这使得操作在主分片和副本分片都完成后才会返回;如果设置 replication 为 async 时,也可以通过设置搜索请求参数\_preference 为 primary 来查询主分片,确保文档是最新版本。
## 20、如何监控 Elasticsearch 集群状态?
Marvel 让你可以很简单的通过 Kibana 监控 Elasticsearch。你可以实时查看你的集群健康状态和性能也可以分析过去的集群、索引和节点指标。
## 21、介绍下你们电商搜索的整体技术架构。
![img](https://pic1.zhimg.com/80/v2-5bdbe7ada0ddee9d8b2f03c0a379e0d4_720w.jpg)
## 介绍一下你们的个性化搜索方案?
基于 word2vec 和 Elasticsearch 实现个性化搜索
1基于 word2vec、Elasticsearch 和自定义的脚本插件,我们就实现了一个个性化的搜索服务,相对于原有的实现,新版的点击率和转化率都有大幅的提升;
2基于 word2vec 的商品向量还有一个可用之处,就是可以用来实现相似商品的推荐;
3使用 word2vec 来实现个性化搜索或个性化推荐是有一定局限性的,因为它只能处理用户点击历史这样的时序数据,而无法全面的去考虑用户偏好,这个还是有很大的改进和提升的空间;
## 是否了解字典树?
常用字典数据结构如下所示:
![img](https://pic2.zhimg.com/80/v2-8bb844c5b8fb944111fa8cecdb0e12d5_720w.jpg)
Trie 的核心思想是空间换时间,利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。它有 3 个基本性质:
1根节点不包含字符除根节点外每一个节点都只包含一个字符。
2从根节点到某一节点路径上经过的字符连接起来为该节点对应的字符串。
3每个节点的所有子节点包含的字符都不相同。
![img](https://pic4.zhimg.com/80/v2-26a48882a8f09a50dfeb79cc25045fcf_720w.jpg)
1可以看到trie 树每一层的节点数是 26^i 级别的。所以为了节省空间,我们还可以用动态链表,或者用数组来模拟动态。而空间的花费,不会超过单词数 × 单词长度。
2实现对每个结点开一个字母集大小的数组每个结点挂一个链表使用左儿子右兄弟表示法记录这棵树
3对于中文的字典树每个节点的子节点用一个哈希表存储这样就不用浪费太大的空间而且查询速度上可以保留哈希的复杂度 O(1)。
## 拼写纠错是如何实现的?
1拼写纠错是基于编辑距离来实现编辑距离是一种标准的方法它用来表示经过插入、删除和替换操作从一个字符串转换到另外一个字符串的最小操作步数
2编辑距离的计算过程比如要计算 batyu 和 beauty 的编辑距离,先创建一个 7×8 的表batyu 长度为 5coffee 长度为 6各加 2接着在如下位置填入黑色数字。其他格的计算过程是取以下三个值的最小值
如果最上方的字符等于最左方的字符,则为左上方的数字。否则为左上方的数字+1。对于 3,3 来说为 0
左方数字+1对于 3,3 格来说为 2
上方数字+1对于 3,3 格来说为 2
最终取右下角的值即为编辑距离的值 3。
![img](https://pic4.zhimg.com/80/v2-66f01f0d578c83274e90a7ddf704b633_720w.jpg)
对于拼写纠错我们考虑构造一个度量空间Metric Space该空间内任何关系满足以下三条基本条件
d(x,y) = 0 -- 假如 x 与 y 的距离为 0则 x=y
d(x,y) = d(y,x) -- x 到 y 的距离等同于 y 到 x 的距离
d(x,y) + d(y,z) >= d(x,z) -- 三角不等式
1根据三角不等式则满足与 query 距离在 n 范围内的另一个字符转 B其与 A 的距离最大为 d+n最小为 d-n。
2BK 树的构造就过程如下:每个节点有任意个子节点,每条边有个值表示编辑距离。所有子节点到父节点的边上标注 n 表示编辑距离恰好为 n。比如我们有棵树父节点是”book”和两个子节点”cake”和”books””book”到”books”的边标号 1”book”到”cake”的边上标号 4。从字典里构造好树后无论何时你想插入新单词时计算该单词与根节点的编辑距离并且查找数值为 d(neweord, root)的边。递归得与各子节点进行比较直到没有子节点你就可以创建新的子节点并将新单词保存在那。比如插入”boo”到刚才上述例子的树中我们先检查根节点查找 d(“book”, “boo”) = 1 的边,然后检查标号为 1 的边的子节点得到单词”books”。我们再计算距离 d(“books”, “boo”)=2则将新单词插在”books”之后边标号为 2。
3查询相似词如下计算单词与根节点的编辑距离 d然后递归查找每个子节点标号为 d-n 到 d+n包含的边。假如被检查的节点与搜索单词的距离 d 小于 n则返回该节点并继续查询。比如输入 cape 且最大容忍距离为 1则先计算和根的编辑距离 d(“book”, “cape”)=4然后接着找和根节点之间编辑距离为 3 到 5 的,这个就找到了 cake 这个节点,计算 d(“cake”, “cape”)=1满足条件所以返回 cake然后再找和 cake 节点编辑距离是 0 到 2 的,分别找到 cape 和 cart 节点,这样就得到 cape 这个满足条件的结果。
![img](https://pic4.zhimg.com/80/v2-79f2a89041e546d9feccf55e4ff1c0d7_720w.jpg)

View File

@ -0,0 +1,208 @@
# Elasticsearch 运维
> [Elasticsearch](https://github.com/elastic/elasticsearch) 是一个分布式、RESTful 风格的搜索和数据分析引擎,能够解决不断涌现出的各种用例。 作为 Elastic Stack 的核心,它集中存储您的数据,帮助您发现意料之中以及意料之外的情况。
## 部署
### 安装步骤
> [Elasticsearch 官方开源版本安装说明](https://www.elastic.co/cn/downloads/elasticsearch-oss)
1下载解压
访问 [官方下载地址](https://www.elastic.co/cn/downloads/elasticsearch-oss) ,选择需要的版本,下载解压到本地。
2运行
运行 `bin/elasticsearch` (Windows 系统上运行 `bin\elasticsearch.bat` )
3访问
执行 `curl http://localhost:9200/` 测试服务是否启动
### 集群规划
ElasticSearch 集群需要根据业务实际情况去合理规划。
需要考虑的问题点:
- 集群部署几个节点?
- 有多少个索引?
- 每个索引有多大数据量?
- 每个索引有多少个分片?
一个参考规划:
- 3 台机器,每台机器是 6 核 64G 的。
- 我们 es 集群的日增量数据大概是 2000 万条,每天日增量数据大概是 500MB每月增量数据大概是 6 亿15G。目前系统已经运行了几个月现在 es 集群里数据总量大概是 100G 左右。
- 目前线上有 5 个索引(这个结合你们自己业务来,看看自己有哪些数据可以放 es 的),每个索引的数据量大概是 20G所以这个数据量之内我们每个索引分配的是 8 个 shard比默认的 5 个 shard 多了 3 个 shard。
## ES 配置
ES 的默认配置文件为 `config/elasticsearch.yml`
基本配置说明如下:
```yml
cluster.name: elasticsearch
#配置es的集群名称默认是elasticsearches会自动发现在同一网段下的es如果在同一网段下有多个集群就可以用这个属性来区分不同的集群。
node.name: 'Franz Kafka'
#节点名默认随机指定一个name列表中名字该列表在es的jar包中config文件夹里name.txt文件中其中有很多作者添加的有趣名字。
node.master: true
#指定该节点是否有资格被选举成为node默认是truees是默认集群中的第一台机器为master如果这台机挂了就会重新选举master。
node.data: true
#指定该节点是否存储索引数据默认为true。
index.number_of_shards: 5
#设置默认索引分片个数默认为5片。
index.number_of_replicas: 1
#设置默认索引副本个数默认为1个副本。
path.conf: /path/to/conf
#设置配置文件的存储路径默认是es根目录下的config文件夹。
path.data: /path/to/data
#设置索引数据的存储路径默认是es根目录下的data文件夹可以设置多个存储路径用逗号隔开
#path.data: /path/to/data1,/path/to/data2
path.work: /path/to/work
#设置临时文件的存储路径默认是es根目录下的work文件夹。
path.logs: /path/to/logs
#设置日志文件的存储路径默认是es根目录下的logs文件夹
path.plugins: /path/to/plugins
#设置插件的存放路径默认是es根目录下的plugins文件夹
bootstrap.mlockall: true
#设置为true来锁住内存。因为当jvm开始swapping时es的效率会降低所以要保证它不swap可以把#ES_MIN_MEM和ES_MAX_MEM两个环境变量设置成同一个值并且保证机器有足够的内存分配给es。同时也要#允许elasticsearch的进程可以锁住内存linux下可以通过`ulimit -l unlimited`命令。
network.bind_host: 192.168.0.1
#设置绑定的ip地址可以是ipv4或ipv6的默认为0.0.0.0。
network.publish_host: 192.168.0.1
#设置其它节点和该节点交互的ip地址如果不设置它会自动判断值必须是个真实的ip地址。
network.host: 192.168.0.1
#这个参数是用来同时设置bind_host和publish_host上面两个参数。
transport.tcp.port: 9300
#设置节点间交互的tcp端口默认是9300。
transport.tcp.compress: true
#设置是否压缩tcp传输时的数据默认为false不压缩。
http.port: 9200
#设置对外服务的http端口默认为9200。
http.max_content_length: 100mb
#设置内容的最大容量默认100mb
http.enabled: false
#是否使用http协议对外提供服务默认为true开启。
gateway.type: local
#gateway的类型默认为local即为本地文件系统可以设置为本地文件系统分布式文件系统hadoop的#HDFS和amazon的s3服务器其它文件系统的设置方法下次再详细说。
gateway.recover_after_nodes: 1
#设置集群中N个节点启动时进行数据恢复默认为1。
gateway.recover_after_time: 5m
#设置初始化数据恢复进程的超时时间默认是5分钟。
gateway.expected_nodes: 2
#设置这个集群中节点的数量默认为2一旦这N个节点启动就会立即进行数据恢复。
cluster.routing.allocation.node_initial_primaries_recoveries: 4
#初始化数据恢复时并发恢复线程的个数默认为4。
cluster.routing.allocation.node_concurrent_recoveries: 2
#添加删除节点或负载均衡时并发恢复线程的个数默认为4。
indices.recovery.max_size_per_sec: 0
#设置数据恢复时限制的带宽如入100mb默认为0即无限制。
indices.recovery.concurrent_streams: 5
#设置这个参数来限制从其它分片恢复数据时最大同时打开并发流的个数默认为5。
discovery.zen.minimum_master_nodes: 1
#设置这个参数来保证集群中的节点可以知道其它N个有master资格的节点。默认为1对于大的集群来说可以设置大一点的值2-4
discovery.zen.ping.timeout: 3s
#设置集群中自动发现其它节点时ping连接超时时间默认为3秒对于比较差的网络环境可以高点的值来防止自动发现时出错。
discovery.zen.ping.multicast.enabled: false
#设置是否打开多播发现节点默认是true。
discovery.zen.ping.unicast.hosts: ['host1', 'host2:port', 'host3[portX-portY]']
#设置集群中master节点的初始列表可以通过这些节点来自动发现新加入集群的节点。
```
## FAQ
### elasticsearch 不允许以 root 权限来运行
**问题:**在 Linux 环境中elasticsearch 不允许以 root 权限来运行。
如果以 root 身份运行 elasticsearch会提示这样的错误
```
can not run elasticsearch as root
```
**解决方法:**使用非 root 权限账号运行 elasticsearch
```bash
# 创建用户组
groupadd elk
# 创建新用户,-g elk 设置其用户组为 elk-p elk 设置其密码为 elk
useradd elk -g elk -p elk
# 更改 /opt 文件夹及内部文件的所属用户及组为 elk:elk
chown -R elk:elk /opt # 假设你的 elasticsearch 安装在 opt 目录下
# 切换账号
su elk
```
### vm.max_map_count 不低于 262144
**问题:**`vm.max_map_count` 表示虚拟内存大小它是一个内核参数。elasticsearch 默认要求 `vm.max_map_count` 不低于 262144。
```
max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]
```
**解决方法:**
你可以执行以下命令,设置 `vm.max_map_count` ,但是重启后又会恢复为原值。
```
sysctl -w vm.max_map_count=262144
```
持久性的做法是在 `/etc/sysctl.conf` 文件中修改 `vm.max_map_count` 参数:
```
echo "vm.max_map_count=262144" > /etc/sysctl.conf
sysctl -p
```
> **注意**
>
> 如果运行环境为 docker 容器,可能会限制执行 sysctl 来修改内核参数。
>
> 这种情况下,你只能选择直接修改宿主机上的参数了。
### nofile 不低于 65536
**问题:** `nofile` 表示进程允许打开的最大文件数。elasticsearch 进程要求可以打开的最大文件数不低于 65536。
```
max file descriptors [4096] for elasticsearch process is too low, increase to at least [65536]
```
**解决方法:**
`/etc/security/limits.conf` 文件中修改 `nofile` 参数:
```
echo "* soft nofile 65536" > /etc/security/limits.conf
echo "* hard nofile 131072" > /etc/security/limits.conf
```
### nproc 不低于 2048
**问题:** `nproc` 表示最大线程数。elasticsearch 要求最大线程数不低于 2048。
```
max number of threads [1024] for user [user] is too low, increase to at least [2048]
```
**解决方法:**
`/etc/security/limits.conf` 文件中修改 `nproc` 参数:
```
echo "* soft nproc 2048" > /etc/security/limits.conf
echo "* hard nproc 4096" > /etc/security/limits.conf
```
## 参考资料
- [Elasticsearch 官网](https://www.elastic.co/cn/products/elasticsearch)
- [Elasticsearch Github](https://github.com/elastic/elasticsearch)
- [Elasticsearch 官方文档](https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html)
- [Install Elasticsearch with RPM](https://www.elastic.co/guide/en/elasticsearch/reference/current/rpm.html#rpm)
- [Elasticsearch 使用积累](http://siye1982.github.io/2015/09/17/es-optimize/)

View File

@ -0,0 +1,234 @@
# Elasticsearch 应用指南
> **[Elasticsearch](https://github.com/elastic/elasticsearch) 是一个分布式、RESTful 风格的搜索和数据分析引擎**,能够解决不断涌现出的各种用例。 作为 Elastic Stack 的核心,它集中存储您的数据,帮助您发现意料之中以及意料之外的情况。
>
> [Elasticsearch](https://github.com/elastic/elasticsearch) 基于搜索库 [Lucene](https://github.com/apache/lucene-solr) 开发。ElasticSearch 隐藏了 Lucene 的复杂性,提供了简单易用的 REST API / Java API 接口(另外还有其他语言的 API 接口)。
>
> *以下简称 ES*
## 一、Elasticsearch 简介
### 什么是 Elasticsearch
**[Elasticsearch](https://github.com/elastic/elasticsearch) 是一个分布式、RESTful 风格的搜索和数据分析引擎**,能够解决不断涌现出的各种用例。 作为 Elastic Stack 的核心,它集中存储您的数据,帮助您发现意料之中以及意料之外的情况。
[Elasticsearch](https://github.com/elastic/elasticsearch) **基于搜索库 [Lucene](https://github.com/apache/lucene-solr) 开发**。ElasticSearch 隐藏了 Lucene 的复杂性,提供了简单易用的 REST API / Java API 接口(另外还有其他语言的 API 接口)。
ElasticSearch 可以视为一个文档存储,它**将复杂数据结构序列化为 JSON 存储**。
**ElasticSearch 是近乎于实时的全文搜素**,这是指:
- 从写入数据到数据可以被搜索,存在较小的延迟(大概是 1s
- 基于 ES 执行搜索和分析可以达到秒级
### 核心概念
```
index -> type -> mapping -> document -> field
```
#### Cluster
集群包含多个节点,每个节点属于哪个集群都是通过一个配置来决定的,对于中小型应用来说,刚开始一个集群就一个节点很正常。
#### Node
Node 是集群中的一个节点,节点也有一个名称,默认是随机分配的。默认节点会去加入一个名称为 `elasticsearch` 的集群。如果直接启动一堆节点,那么它们会自动组成一个 elasticsearch 集群,当然一个节点也可以组成 elasticsearch 集群。
#### Index
**可以认为是文档document的优化集合。**
ES 会为所有字段建立索引经过处理后写入一个反向索引Inverted Index。查找数据的时候直接查找该索引。
所以ES 数据管理的顶层单位就叫做 Index索引。它是单个数据库的同义词。每个 Index (即数据库)的名字必须是小写。
#### Type
每个索引里可以有一个或者多个类型type。`类型type` 是 index 的一个逻辑分类。
不同的 Type 应该有相似的结构schema举例来说`id`字段不能在这个组是字符串,在另一个组是数值。这是与关系型数据库的表的[一个区别](https://www.elastic.co/guide/en/elasticsearch/guide/current/mapping.html)。性质完全不同的数据(比如`products`和`logs`)应该存成两个 Index而不是一个 Index 里面的两个 Type虽然可以做到
> 注意:根据[规划](https://www.elastic.co/blog/index-type-parent-child-join-now-future-in-elasticsearch)Elastic 6.x 版只允许每个 Index 包含一个 Type7.x 版将会彻底移除 Type。
#### Document
Index 里面单条的记录称为 Document文档。许多条 Document 构成了一个 Index。
每个 **`文档document`** 都是字段field的集合。
Document 使用 JSON 格式表示,下面是一个例子。
```javascript
{
"user": "张三",
"title": "工程师",
"desc": "数据库管理"
}
```
同一个 Index 里面的 Document不要求有相同的结构scheme但是最好保持相同这样有利于提高搜索效率。
#### Field
**`字段field`** 是包含数据的键值对。
默认情况下Elasticsearch 对每个字段中的所有数据建立索引,并且每个索引字段都具有专用的优化数据结构。
#### Shard
当单台机器不足以存储大量数据时Elasticsearch 可以将一个索引中的数据切分为多个 **`分片shard`** 。 **`分片shard`** 分布在多台服务器上存储。有了 shard 就可以横向扩展,存储更多数据,让搜索和分析等操作分布到多台服务器上去执行,提升吞吐量和性能。每个 shard 都是一个 lucene index。
#### Replica
任何一个服务器随时可能故障或宕机,此时 shard 可能就会丢失,因此可以为每个 shard 创建多个 **`副本replica`**。replica 可以在 shard 故障时提供备用服务,保证数据不丢失,多个 replica 还可以提升搜索操作的吞吐量和性能。primary shard建立索引时一次设置不能修改默认 5 个replica shard随时修改数量默认 1 个),默认每个索引 10 个 shard5 个 primary shard5 个 replica shard最小的高可用配置是 2 台服务器。
#### ES 核心概念 vs. DB 核心概念
| ES | DB |
| -------- | -------- |
| index | 数据库 |
| type | 数据表 |
| docuemnt | 一行数据 |
## 三、ElasticSearch 基本原理
### ES 写数据过程
- 客户端选择一个 node 发送请求过去,这个 node 就是 `coordinating node`(协调节点)。
- `coordinating node` 对 document 进行**路由**,将请求转发给对应的 node有 primary shard
- 实际的 node 上的 `primary shard` 处理请求,然后将数据同步到 `replica node`
- `coordinating node` 如果发现 `primary node` 和所有 `replica node` 都搞定之后,就返回响应结果给客户端。
[![es-write](https://github.com/doocs/advanced-java/raw/master/docs/high-concurrency/images/es-write.png)](https://github.com/doocs/advanced-java/blob/master/docs/high-concurrency/images/es-write.png)
### ES 读数据过程
可以通过 `doc id` 来查询,会根据 `doc id` 进行 hash判断出来当时把 `doc id` 分配到了哪个 shard 上面去,从那个 shard 去查询。
- 客户端发送请求到**任意**一个 node成为 `coordinate node`
- `coordinate node``doc id` 进行哈希路由,将请求转发到对应的 node此时会使用 `round-robin` **随机轮询算法**,在 `primary shard` 以及其所有 replica 中随机选择一个,让读请求负载均衡。
- 接收请求的 node 返回 document 给 `coordinate node`
- `coordinate node` 返回 document 给客户端。
### es 搜索数据过程
es 最强大的是做全文检索,就是比如你有三条数据:
```
java真好玩儿啊
java好难学啊
j2ee特别牛
```
你根据 `java` 关键词来搜索,将包含 `java``document` 给搜索出来。es 就会给你返回java真好玩儿啊java好难学啊。
- 客户端发送请求到一个 `coordinate node`
- 协调节点将搜索请求转发到**所有**的 shard 对应的 `primary shard``replica shard` ,都可以。
- query phase每个 shard 将自己的搜索结果(其实就是一些 `doc id` )返回给协调节点,由协调节点进行数据的合并、排序、分页等操作,产出最终结果。
- fetch phase接着由协调节点根据 `doc id` 去各个节点上**拉取实际**的 `document` 数据,最终返回给客户端。
> 写请求是写入 primary shard然后同步给所有的 replica shard读请求可以从 primary shard 或 replica shard 读取,采用的是随机轮询算法。
### 写数据底层原理
[![es-write-detail](https://github.com/doocs/advanced-java/raw/master/docs/high-concurrency/images/es-write-detail.png)](https://github.com/doocs/advanced-java/blob/master/docs/high-concurrency/images/es-write-detail.png)
先写入内存 buffer在 buffer 里的时候数据是搜索不到的;同时将数据写入 translog 日志文件。
如果 buffer 快满了,或者到一定时间,就会将内存 buffer 数据 `refresh` 到一个新的 `segment file` 中,但是此时数据不是直接进入 `segment file` 磁盘文件,而是先进入 `os cache` 。这个过程就是 `refresh`
每隔 1 秒钟es 将 buffer 中的数据写入一个**新的** `segment file`,每秒钟会产生一个**新的磁盘文件** `segment file`,这个 `segment file` 中就存储最近 1 秒内 buffer 中写入的数据。
但是如果 buffer 里面此时没有数据,那当然不会执行 refresh 操作,如果 buffer 里面有数据,默认 1 秒钟执行一次 refresh 操作,刷入一个新的 segment file 中。
操作系统里面,磁盘文件其实都有一个东西,叫做 `os cache`,即操作系统缓存,就是说数据写入磁盘文件之前,会先进入 `os cache`,先进入操作系统级别的一个内存缓存中去。只要 `buffer` 中的数据被 refresh 操作刷入 `os cache`中,这个数据就可以被搜索到了。
为什么叫 es 是**准实时**的? `NRT`,全称 `near real-time`。默认是每隔 1 秒 refresh 一次的,所以 es 是准实时的,因为写入的数据 1 秒之后才能被看到。可以通过 es 的 `restful api` 或者 `java api`**手动**执行一次 refresh 操作,就是手动将 buffer 中的数据刷入 `os cache`中,让数据立马就可以被搜索到。只要数据被输入 `os cache`buffer 就会被清空了,因为不需要保留 buffer 了,数据在 translog 里面已经持久化到磁盘去一份了。
重复上面的步骤,新的数据不断进入 buffer 和 translog不断将 `buffer` 数据写入一个又一个新的 `segment file` 中去,每次 `refresh` 完 buffer 清空translog 保留。随着这个过程推进translog 会变得越来越大。当 translog 达到一定长度的时候,就会触发 `commit` 操作。
commit 操作发生第一步,就是将 buffer 中现有数据 `refresh``os cache` 中去,清空 buffer。然后将一个 `commit point` 写入磁盘文件,里面标识着这个 `commit point` 对应的所有 `segment file`,同时强行将 `os cache` 中目前所有的数据都 `fsync` 到磁盘文件中去。最后**清空** 现有 translog 日志文件,重启一个 translog此时 commit 操作完成。
这个 commit 操作叫做 `flush`。默认 30 分钟自动执行一次 `flush`,但如果 translog 过大,也会触发 `flush`。flush 操作就对应着 commit 的全过程,我们可以通过 es api手动执行 flush 操作,手动将 os cache 中的数据 fsync 强刷到磁盘上去。
translog 日志文件的作用是什么?你执行 commit 操作之前,数据要么是停留在 buffer 中,要么是停留在 os cache 中,无论是 buffer 还是 os cache 都是内存,一旦这台机器死了,内存中的数据就全丢了。所以需要将数据对应的操作写入一个专门的日志文件 `translog`一旦此时机器宕机再次重启的时候es 会自动读取 translog 日志文件中的数据,恢复到内存 buffer 和 os cache 中去。
translog 其实也是先写入 os cache 的,默认每隔 5 秒刷一次到磁盘中去,所以默认情况下,可能有 5 秒的数据会仅仅停留在 buffer 或者 translog 文件的 os cache 中,如果此时机器挂了,会**丢失** 5 秒钟的数据。但是这样性能比较好,最多丢 5 秒的数据。也可以将 translog 设置成每次写操作必须是直接 `fsync` 到磁盘,但是性能会差很多。
实际上你在这里,如果面试官没有问你 es 丢数据的问题,你可以在这里给面试官炫一把,你说,其实 es 第一是准实时的,数据写入 1 秒后可以搜索到;可能会丢失数据的。有 5 秒的数据,停留在 buffer、translog os cache、segment file os cache 中,而不在磁盘上,此时如果宕机,会导致 5 秒的**数据丢失**。
**总结一下**,数据先写入内存 buffer然后每隔 1s将数据 refresh 到 os cache到了 os cache 数据就能被搜索到(所以我们才说 es 从写入到能被搜索到,中间有 1s 的延迟)。每隔 5s将数据写入 translog 文件(这样如果机器宕机,内存数据全没,最多会有 5s 的数据丢失translog 大到一定程度,或者默认每隔 30mins会触发 commit 操作,将缓冲区的数据都 flush 到 segment file 磁盘文件中。
> 数据写入 segment file 之后,同时就建立好了倒排索引。
### 删除/更新数据底层原理
如果是删除操作commit 的时候会生成一个 `.del` 文件,里面将某个 doc 标识为 `deleted` 状态,那么搜索的时候根据 `.del` 文件就知道这个 doc 是否被删除了。
如果是更新操作,就是将原来的 doc 标识为 `deleted` 状态,然后新写入一条数据。
buffer 每 refresh 一次,就会产生一个 `segment file`,所以默认情况下是 1 秒钟一个 `segment file`,这样下来 `segment file` 会越来越多,此时会定期执行 merge。每次 merge 的时候,会将多个 `segment file` 合并成一个,同时这里会将标识为 `deleted` 的 doc 给**物理删除掉**,然后将新的 `segment file` 写入磁盘,这里会写一个 `commit point`,标识所有新的 `segment file`,然后打开 `segment file` 供搜索使用,同时删除旧的 `segment file`
### 底层 lucene
简单来说lucene 就是一个 jar 包,里面包含了封装好的各种建立倒排索引的算法代码。我们用 Java 开发的时候,引入 lucene jar然后基于 lucene 的 api 去开发就可以了。
通过 lucene我们可以将已有的数据建立索引lucene 会在本地磁盘上面,给我们组织索引的数据结构。
### 倒排索引
在搜索引擎中,每个文档都有一个对应的文档 ID文档内容被表示为一系列关键词的集合。例如文档 1 经过分词,提取了 20 个关键词,每个关键词都会记录它在文档中出现的次数和出现位置。
那么,倒排索引就是**关键词到文档** ID 的映射,每个关键词都对应着一系列的文件,这些文件中都出现了关键词。
举个栗子。
有以下文档:
| DocId | Doc |
| ----- | ---------------------------------------------- |
| 1 | 谷歌地图之父跳槽 Facebook |
| 2 | 谷歌地图之父加盟 Facebook |
| 3 | 谷歌地图创始人拉斯离开谷歌加盟 Facebook |
| 4 | 谷歌地图之父跳槽 Facebook 与 Wave 项目取消有关 |
| 5 | 谷歌地图之父拉斯加盟社交网站 Facebook |
对文档进行分词之后,得到以下**倒排索引**。
| WordId | Word | DocIds |
| ------ | -------- | --------- |
| 1 | 谷歌 | 1,2,3,4,5 |
| 2 | 地图 | 1,2,3,4,5 |
| 3 | 之父 | 1,2,4,5 |
| 4 | 跳槽 | 1,4 |
| 5 | Facebook | 1,2,3,4,5 |
| 6 | 加盟 | 2,3,5 |
| 7 | 创始人 | 3 |
| 8 | 拉斯 | 3,5 |
| 9 | 离开 | 3 |
| 10 | 与 | 4 |
| .. | .. | .. |
另外,实用的倒排索引还可以记录更多的信息,比如文档频率信息,表示在文档集合中有多少个文档包含某个单词。
那么,有了倒排索引,搜索引擎可以很方便地响应用户的查询。比如用户输入查询 `Facebook`,搜索系统查找倒排索引,从中读出包含这个单词的文档,这些文档就是提供给用户的搜索结果。
要注意倒排索引的两个重要细节:
- 倒排索引中的所有词项对应一个或多个文档;
- 倒排索引中的词项**根据字典顺序升序排列**
> 上面只是一个简单的栗子,并没有严格按照字典顺序升序排列。
## 参考资料
- **官方**
- [Elasticsearch 官网](https://www.elastic.co/cn/products/elasticsearch)
- [Elasticsearch Github](https://github.com/elastic/elasticsearch)
- [Elasticsearch 官方文档](https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html)
- **文章**
- [Install Elasticsearch with RPM](https://www.elastic.co/guide/en/elasticsearch/reference/current/rpm.html#rpm)
- [https://www.ruanyifeng.com/blog/2017/08/elasticsearch.html](https://www.ruanyifeng.com/blog/2017/08/elasticsearch.html)
- [es-introduction](https://github.com/doocs/advanced-java/blob/master/docs/high-concurrency/es-introduction.md)
- [es-write-query-search](https://github.com/doocs/advanced-java/blob/master/docs/high-concurrency/es-write-query-search.md)

View File

@ -1,6 +1,6 @@
# Nosql 技术选型
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200209020702.png)
![img](http://dunwu.test.upcdn.net/snap/20200209020702.png)
[TOC]
@ -16,7 +16,7 @@
随着大数据时代的到来,越来越多的网站、应用系统需要支撑海量数据存储,高并发请求、高可用、高可扩展性等特性要求。传统的关系型数据库在应付这些调整已经显得力不从心,暴露了许多能以克服的问题。由此,各种各样的 NoSQLNot Only SQL数据库作为传统关系型数据的一个有力补充得到迅猛发展。
![nosql-history](https://raw.githubusercontent.com/dunwu/images/master/snap/20200209005228.png)
![nosql-history](http://dunwu.test.upcdn.net/snap/20200209005228.png)
**NoSQL泛指非关系型的数据库**,可以理解为 SQL 的一个有力补充。
@ -45,7 +45,7 @@
将表放入存储系统中有两种方法,而我们绝大部分是采用行存储的。 行存储法是将各行放入连续的物理位置,这很像传统的记录和文件系统。 列存储法是将数据按照列存储到数据库中,与行存储类似,下图是两种存储方法的图形化解释:
![按行存储和按列存储模式](https://raw.githubusercontent.com/dunwu/images/master/snap/20200209005316.png)
![按行存储和按列存储模式](http://dunwu.test.upcdn.net/snap/20200209005316.png)
### 列式数据库产品
@ -69,13 +69,13 @@
列式数据库由于其针对不同列的数据特征而发明的不同算法,使其**往往有比行式数据库高的多的压缩率**,普通的行式数据库一般压缩率在 31 到 51 左右,而列式数据库的压缩率一般在 81 到 301 左右。 比较常见的,通过字典表压缩数据: 下面中才是那张表本来的样子。经过字典表进行数据压缩后,表中的字符串才都变成数字了。正因为每个字符串在字典表里只出现一次了,所以达到了压缩的目的(有点像规范化和非规范化 Normalize 和 Denomalize)
![通过字典表压缩数据](https://raw.githubusercontent.com/dunwu/images/master/snap/20200209005406.png)
![通过字典表压缩数据](http://dunwu.test.upcdn.net/snap/20200209005406.png)
- **查询效率高**
读取多条数据的同一列效率高,因为这些列都是存储在一起的,一次磁盘操作可以数据的指定列全部读取到内存中。 下图通过一条查询的执行过程说明列式存储(以及数据压缩)的优点
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200209005611.png)
![img](http://dunwu.test.upcdn.net/snap/20200209005611.png)
```
执行步骤如下:
@ -116,19 +116,19 @@ KV 存储非常适合存储**不涉及过多数据关系业务关系的数据**
- Redis
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200209010410.png)
![img](http://dunwu.test.upcdn.net/snap/20200209010410.png)
Redis 是一个使用 ANSI C 编写的开源、支持网络、基于内存、可选持久性的键值对存储数据库。从 2015 年 6 月开始Redis 的开发由 Redis Labs 赞助,而 2013 年 5 月至 2015 年 6 月期间,其开发由 Pivotal 赞助。在 2013 年 5 月之前,其开发由 VMware 赞助。根据月度排行网站 DB-Engines.com 的数据显示Redis 是最流行的键值对存储数据库。
- Cassandra
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200209010451.png)
![img](http://dunwu.test.upcdn.net/snap/20200209010451.png)
Apache Cassandra社区内一般简称为 C\*)是一套开源分布式 NoSQL 数据库系统。它最初由 Facebook 开发,用于储存收件箱等简单格式数据,集 Google BigTable 的数据模型与 Amazon Dynamo 的完全分布式架构于一身。Facebook 于 2008 将 Cassandra 开源,此后,由于 Cassandra 良好的可扩展性和性能,被 Apple, Comcast,Instagram, Spotify, eBay, Rackspace, Netflix 等知名网站所采用,成为了一种流行的分布式结构化数据存储方案。
- LevelDB
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200209011140.png)
![img](http://dunwu.test.upcdn.net/snap/20200209011140.png)
LevelDB 是一个由 Google 公司所研发的键值对Key/Value Pair嵌入式数据库管理系统编程库 以开源的 BSD 许可证发布。
@ -157,23 +157,21 @@ KV 存储非常适合存储**不涉及过多数据关系业务关系的数据**
## 四、文档数据库
文档数据库(也称为文档型数据库)是**旨在将半结构化数据存储为文档的一种数据库**。文档数据库**通常以 JSON 或 XML 格式存储数据**。
文档数据库(也称为文档型数据库)是**旨在将半结构化数据存储为文档的一种数据库,它可以解决关系型数据库表结构 schema 扩展不方便的问题**。文档数据库**通常以 JSON 或 XML 格式存储数据**。
由于文档数据库的 no-schema 特性,可以存储和读取任意数据。
由于使用的数据格式是 JSON 或者 BSON因为 JSON 数据是自描述的,无需在使用前定义字段,读取一个 JSON 中不存在的字段也不会导致 SQL 那样的语法错误,**可以解决关系型数据库表结构 schema 扩展不方便的问题**
由于文档数据库的 no-schema 特性,可以存储和读取任意数据。由于使用的数据格式是 JSON 或者 XML无需在使用前定义字段读取一个 JSON 中不存在的字段也不会导致 SQL 那样的语法错误。
### 文档数据库产品
- MongoDB
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200209012320.png)
![img](http://dunwu.test.upcdn.net/snap/20200209012320.png)
**MongoDB**是一种面向文档的数据库管理系统,由 C++ 撰写而成以此来解决应用程序开发社区中的大量现实问题。2007 年 10 月MongoDB 由 10gen 团队所发展。2009 年 2 月首度推出。
- CouchDB
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200209012418.png)
![img](http://dunwu.test.upcdn.net/snap/20200209012418.png)
Apache CouchDB 是一个开源数据库,专注于易用性和成为"**完全拥抱 web 的数据库**"。它是一个使用 JSON 作为存储格式JavaScript 作为查询语言MapReduce 和 HTTP 作为 API 的 NoSQL 数据库。其中一个显著的功能就是多主复制。CouchDB 的第一个版本发布在 2005 年,在 2008 年成为了 Apache 的项目。
@ -192,13 +190,13 @@ KV 存储非常适合存储**不涉及过多数据关系业务关系的数据**
- **部分支持事务**
- Atomicity(原子性) 仅支持单行/文档级原子性,不支持多行、多文档、多语句原子性。
- Isolation(隔离性) 隔离级别仅支持已提交读Read committed级别可能导致不可重复读幻读的问题。
- **不支持复杂查询** - 例如 join 查询,如果需要 join 查询,需要多次操作数据库
- **不支持复杂查询** - 例如 join 查询,如果需要 join 查询,需要多次操作数据库
MongonDB 还是支持多文档事务的 Consistency(一致性)和 Durability(持久性)
虽然官方宣布 MongoDB 将在 4.0 版本中正式推出多文档 ACID 事务支持,最后落地情况还有待见证。
### 文档数据库场景
### 文档数据库使用场景
**适用场景**
@ -215,21 +213,21 @@ MongonDB 还是支持多文档事务的 Consistency(一致性)和 Durability(持
传统关系型数据库主要通过索引来达到快速查询的目的,在全文搜索的业务下,索引也无能为力,主要体现在:
- 全文搜索的条件可以随意排列组合,如果通过索引来满足,则索引的数量非常多
- 全文搜索的模糊匹配方式,索引无法满足,只能用 like 查询,而 like 查询是整表扫描,效率非常低
- 全文搜索的模糊匹配方式,索引无法满足,只能用 `LIKE` 查询,而 `LIKE` 查询是整表扫描,效率非常低
而全文搜索引擎的出现,正是**解决关系型数据库全文搜索功能较弱的问题**
而全文搜索引擎的出现,正是**解决关系型数据库全文搜索功能较弱的问题**
### 搜索引擎原理
全文搜索引擎的技术原理称为“倒排索引”inverted index,是一种索引方法,其基本原理是建立单词到文档的索引。与之相对是,是“正排索引”,其基本原理是建立文档到单词的索引。
全文搜索引擎的技术原理称为 **`倒排索引inverted index`**,是一种索引方法,其基本原理是建立单词到文档的索引。与之相对是,是“正排索引”,其基本原理是建立文档到单词的索引。
现在有如下文档集合:
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200209014530.png)
![img](http://dunwu.test.upcdn.net/snap/20200209014530.png)
正排索引得到索引如下:
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200209014723.png)
![img](http://dunwu.test.upcdn.net/snap/20200209014723.png)
可见,正排索引适用于根据文档名称查询文档内容
@ -239,7 +237,7 @@ MongonDB 还是支持多文档事务的 Consistency(一致性)和 Durability(持
带有单词频率信息的倒排索引如下:
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200209014842.png)
![img](http://dunwu.test.upcdn.net/snap/20200209014842.png)
可见,倒排索引适用于根据关键词来查询文档内容
@ -253,7 +251,7 @@ MongonDB 还是支持多文档事务的 Consistency(一致性)和 Durability(持
- Solr
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200209014947.png)
![img](http://dunwu.test.upcdn.net/snap/20200209014947.png)
Solr 是 Apache Lucene 项目的开源企业搜索平台。其主要功能包括全文检索、命中标示、分面搜索、动态聚类、数据库集成,以及富文本(如 Word、PDF的处理。Solr 是高度可扩展的,并提供了分布式搜索和索引复制
@ -287,7 +285,7 @@ MongonDB 还是支持多文档事务的 Consistency(一致性)和 Durability(持
## 六、图数据库
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200209015751.png)
![img](http://dunwu.test.upcdn.net/snap/20200209015751.png)
**图形数据库应用图论存储实体之间的关系信息**。最常见例子就是社会网络中人与人之间的关系。关系型数据库用于存储“关系型”数据的效果并不好,其查询复杂、缓慢、超出预期,而图形数据库的独特设计恰恰弥补了这个缺陷,解决关系型数据库存储和处理复杂关系型数据功能较弱的问题。
@ -295,19 +293,19 @@ MongonDB 还是支持多文档事务的 Consistency(一致性)和 Durability(持
- Neo4j
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200209015817.png)
![img](http://dunwu.test.upcdn.net/snap/20200209015817.png)
Neo4j 是由 Neo4jInc。开发的图形数据库管理系统。由其开发人员描述为具有原生图存储和处理的符合 ACID 的事务数据库,根据 DB-Engines 排名, Neo4j 是最流行的图形数据库。
- ArangoDB
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200209015858.png)
![img](http://dunwu.test.upcdn.net/snap/20200209015858.png)
ArangoDB 是由 triAGENS GmbH 开发的原生多模型数据库系统。数据库系统支持三个重要的数据模型(键/值,文档,图形),其中包含一个数据库核心和统一查询语言 AQLArangoDB 查询语言。查询语言是声明性的允许在单个查询中组合不同的数据访问模式。ArangoDB 是一个 NoSQL 数据库系统,但 AQL 在很多方面与 SQL 类似。
- Titan
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200209015923.png)
![img](http://dunwu.test.upcdn.net/snap/20200209015923.png)
Titan 是一个可扩展的图形数据库针对存储和查询包含分布在多机群集中的数百亿个顶点和边缘的图形进行了优化。Titan 是一个事务性数据库,可以支持数千个并发用户实时执行复杂的图形遍历。

View File

@ -8,21 +8,21 @@
### [Redis 数据类型和应用](redis-datatype.md)
![Redis 数据类型](https://raw.githubusercontent.com/dunwu/images/master/snap/20200226113813.png)
![Redis 数据类型](http://dunwu.test.upcdn.net/snap/20200226113813.png)
### [Redis 持久化](redis-persistence.md)
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200224214047.png)
![img](http://dunwu.test.upcdn.net/snap/20200224214047.png)
### [Redis 集群](redis-cluster.md)
### [Redis 复制](redis-replication.md)
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200224220328.png)
![img](http://dunwu.test.upcdn.net/snap/20200224220328.png)
### [Redis 哨兵](redis-sentinel.md)
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200224221812.png)
![img](http://dunwu.test.upcdn.net/snap/20200224221812.png)
### [Redis 运维 🔨](redis-ops.md)

View File

@ -6,7 +6,7 @@
## Redis 基本数据类型
![Redis 数据类型](https://raw.githubusercontent.com/dunwu/images/master/snap/20200226113813.png)
![Redis 数据类型](http://dunwu.test.upcdn.net/snap/20200226113813.png)
| 数据类型 | 可以存储的值 | 操作 |
| -------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------- |
@ -315,7 +315,7 @@ OK
使用 `HASH` 类型存储文章信息。其中key 是文章 IDfield 是文章的属性 keyvalue 是属性对应值。
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200225143038.jpg)
![img](http://dunwu.test.upcdn.net/snap/20200225143038.jpg)
操作:
@ -327,7 +327,7 @@ OK
使用 `ZSET` 类型分别存储按照时间排序和按照评分排序的文章 ID 集合。
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200225145742.jpg)
![img](http://dunwu.test.upcdn.net/snap/20200225145742.jpg)
操作:
@ -337,7 +337,7 @@ OK
3为了防止重复投票使用 `SET` 类型记录每篇文章 ID 对应的投票集合。
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200225150105.jpg)
![img](http://dunwu.test.upcdn.net/snap/20200225150105.jpg)
操作:
@ -346,7 +346,7 @@ OK
4假设 user:115423 给 article:100408 投票,分别需要高更新评分排序集合以及投票集合。
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200225150138.jpg)
![img](http://dunwu.test.upcdn.net/snap/20200225150138.jpg)
当需要对一篇文章投票时,程序需要用 ZSCORE 命令检查记录文章发布时间的有序集合,判断文章的发布时间是否超过投票有效期(比如:一星期)。
@ -462,7 +462,7 @@ OK
取出群组里的文章:
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200225214210.jpg)
![img](http://dunwu.test.upcdn.net/snap/20200225214210.jpg)
- 通过对存储群组文章的集合和存储文章评分的有序集合执行 `ZINTERSTORE` 命令,可以得到按照文章评分排序的群组文章。
- 通过对存储群组文章的集合和存储文章发布时间的有序集合执行 `ZINTERSTORE` 命令,可以得到按照文章发布时间排序的群组文章。

View File

@ -7,19 +7,19 @@
- Redis 数据类型有哪些?
- Redis 各种数据类型适用于什么样的场景?
------
---
解答:
Redis 基本数据类型:
| 数据类型 | 可以存储的值 | 操作 |
| -------- | ---------------------- | ------------------------------------------------------------ |
| STRING | 字符串、整数或者浮点数 | 对整个字符串或者字符串的其中一部分执行操作</br> 对整数和浮点数执行自增或者自减操作 |
| LIST | 列表 | 从两端压入或者弹出元素</br> 读取单个或者多个元素</br> 进行修剪,只保留一个范围内的元素 |
| 数据类型 | 可以存储的值 | 操作 |
| -------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------- |
| STRING | 字符串、整数或者浮点数 | 对整个字符串或者字符串的其中一部分执行操作</br> 对整数和浮点数执行自增或者自减操作 |
| LIST | 列表 | 从两端压入或者弹出元素</br> 读取单个或者多个元素</br> 进行修剪,只保留一个范围内的元素 |
| SET | 无序集合 | 添加、获取、移除单个元素</br> 检查一个元素是否存在于集合中</br> 计算交集、并集、差集</br> 从集合里面随机获取元素 |
| HASH | 包含键值对的无序散列表 | 添加、获取、移除单个键值对</br> 获取所有键值对</br> 检查某个键是否存在 |
| ZSET | 有序集合 | 添加、获取、删除元素</br> 根据分值范围或者成员来获取元素</br> 计算一个键的排名 |
| HASH | 包含键值对的无序散列表 | 添加、获取、移除单个键值对</br> 获取所有键值对</br> 检查某个键是否存在 |
| ZSET | 有序集合 | 添加、获取、删除元素</br> 根据分值范围或者成员来获取元素</br> 计算一个键的排名 |
Redis 各种数据类型的应用比较繁杂,详情可以参考:[Redis 数据类型](https://github.com/dunwu/db-tutorial/blob/master/docs/nosql/redis/redis-datatype.md)
@ -37,7 +37,7 @@ Redis 各种数据类型的应用比较繁杂,详情可以参考:[Redis 数
解答:
Redis 提供了下面几种内存淘汰策略供用户选
Redis 内存淘汰策略:
- **`noeviction`** - 当内存使用达到阈值的时候,所有引起申请内存的命令会报错。这是 Redis 默认的策略。
- **`allkeys-lru`** - 在主键空间中,优先移除最近未使用的 key。
@ -58,6 +58,10 @@ Redis 删除失效主键的方法主要有两种:
- 消极方法passive way在主键被访问时如果发现它已经失效那么就删除它。
- 主动方法active way周期性地从设置了失效时间的主键中选择一部分失效的主键删除。
LRU 算法实现思路:
`HashMap` + `LinkedList`
## Redis 持久化
问题:
@ -89,11 +93,14 @@ AOF(Append Only File) 是以文本日志形式将所有写命令追加到 AOF
- Redis 集群如何扩展?
- Redis 集群如何保证数据一致?
- Redis 集群如何规划?你们公司的生产环境上如何部署 Redis 集群?
- Redis 的并发竞争问题如何解决?
---
解答:
Redis 为单进程单线程模式,采用队列模式将并发访问变为串行访问。
Redis 单机吞吐量也很高,能达到几万 QPS但需要格外注意的是**Redis 是单线程模型**。很多人可能会奇怪Redis 是单线程模型,如何能处理高并发请求呢?
原因在于:
@ -134,7 +141,7 @@ Redis 的高可用是通过哨兵来实现Raft 协议的 Redis 实现。Se
由一个或多个 Sentinel 实例组成的 Sentinel 系统可以监视任意多个主服务器,以及这些主服务器的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器的某个从服务器升级为新的主服务器,然后由新的主服务器代替已下线的主服务器继续处理命令请求。
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200131135847.png)
![img](http://dunwu.test.upcdn.net/snap/20200131135847.png)
更详细的特性及原理说明请参考:[Redis 哨兵](https://github.com/dunwu/db-tutorial/blob/master/docs/nosql/redis/redis-sentinel.md)
@ -199,3 +206,27 @@ Redis 不支持回滚的理由:
- **[`WATCH`](https://redis.io/commands/watch) 命令可以为 Redis 事务提供 check-and-set CAS行为。**被 WATCH 的键会被监视,并会发觉这些键是否被改动过了。 如果有至少一个被监视的键在 EXEC 执行之前被修改了, 那么整个事务都会被取消, EXEC 返回 nil-reply 来表示事务已经失败。
Redis 是一种基于 C/S 模型以及请求/响应协议的 TCP 服务。Redis 支持管道技术。管道技术允许请求以异步方式发送即旧请求的应答还未返回的情况下允许发送新请求。这种方式可以大大提高传输效率。使用管道发送命令时Redis Server 会将部分请求放到缓存队列中(占用内存),执行完毕后一次性发送结果。如果需要发送大量的命令,会占用大量的内存,因此应该按照合理数量分批次的处理。
## Redis vs. Memcached
Redis 不仅仅支持简单的 k/v 类型的数据,同时还提供 listsetzsethash 等数据结构的存储。memcache 支持简单的数据类型String。
Redis 支持数据的备份,即 master-slave 模式的数据备份。
Redis 支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用,而 Memecache 把数据全部存在内存之中
redis 的速度比 memcached 快很多
Memcached 是多线程,非阻塞 IO 复用的网络模型Redis 使用单线程的 IO 复用模型。
![Redis与Memcached的区别与比较](https://user-gold-cdn.xitu.io/2018/4/18/162d7773080d4570?imageView2/0/w/1280/h/960/format/webp/ignore-error/1)
如果想要更详细了解的话,可以查看慕课网上的这篇手记(非常推荐) **:《脚踏两只船的困惑 - Memcached 与 Redis》**[www.imooc.com/article/23549](https://www.imooc.com/article/23549)
### Redis 与 Memcached 的选择
**终极策略:** 使用 Redis 的 String 类型做的事,都可以用 Memcached 替换,以此换取更好的性能提升; 除此以外,优先考虑 Redis
## 参考资料
- [面试中关于 Redis 的问题看这篇就够了](https://juejin.im/post/5ad6e4066fb9a028d82c4b66)

View File

@ -177,7 +177,7 @@ AOF 重写并非读取和分析现有 AOF 文件的内容,而是直接从数
- 由于彼此不是在同一个进程中工作AOF 重写不影响 AOF 写入和同步。当子进程完成创建新 AOF 文件的工作之后,服务器会将重写缓冲区中的所有内容追加到新 AOF 文件的末尾,使得新旧两个 AOF 文件所保存的数据库状态一致。
- 最后,服务器用新的 AOF 文件替换就的 AOF 文件,以此来完成 AOF 重写操作。
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200130153716.png)
![img](http://dunwu.test.upcdn.net/snap/20200130153716.png)
可以通过设置 `auto-aof-rewrite-percentage``auto-aof-rewrite-min-size`,使得 Redis 在满足条件时,自动执行 `BGREWRITEAOF`
@ -269,7 +269,7 @@ Redis 的容灾备份基本上就是对数据进行备份,并将这些备份
## 五、要点总结
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200224214047.png)
![img](http://dunwu.test.upcdn.net/snap/20200224214047.png)
## 参考资料

View File

@ -418,7 +418,7 @@ Redis 基于 Reactor 模式开发了自己的网络时间处理器。
文件事件处理器有四个组成部分套接字、I/O 多路复用程序、文件事件分派器、事件处理器。
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200130172525.png)
![img](http://dunwu.test.upcdn.net/snap/20200130172525.png)
### 时间事件

View File

@ -37,7 +37,7 @@ Redis 的复制功能分为同步sync和命令传播command propagate
3. 主服务器执行 `BGSAVE` 完毕后,主服务器会将生成的 RDB 文件发送给从服务器。从服务器接收并载入 RDB 文件,更新自己的数据库状态。
4. 主服务器将记录在缓冲区中的所有写命令发送给从服务器,从服务器执行这些写命令,更新自己的数据库状态。
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200224220353.png)
![img](http://dunwu.test.upcdn.net/snap/20200224220353.png)
### 命令传播
@ -260,7 +260,7 @@ REPLCONF ACK <replication_coffset>
## 七、要点总结
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200224220328.png)
![img](http://dunwu.test.upcdn.net/snap/20200224220328.png)
## 参考资料

View File

@ -4,7 +4,7 @@ Redis 哨兵Sentinel是 Redis 的**高可用性**Hight Availability
**Sentinel 本质上是一个运行在特殊状模式下的 Redis 服务器**。
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200131135847.png)
![img](http://dunwu.test.upcdn.net/snap/20200131135847.png)
## 一、哨兵简介
@ -75,7 +75,7 @@ Sentinel 模式下 Redis 服务器主要功能的使用情况:
对于每个与 Sentinel 连接的服务器Sentinel 既会向服务器的 `__sentinel__:hello` 频道发送消息,也会订阅服务器的 `__sentinel__:hello` 频道的消息。
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200131153842.png)
![img](http://dunwu.test.upcdn.net/snap/20200131153842.png)
### 向服务器发送消息
@ -97,7 +97,7 @@ Sentinel 对 `__sentinel__:hello` 频道的订阅会一直持续到 Sentinel 与
> Redis Sentinel 系统选举 Leader 的算法是 [Raft](https://ramcloud.atlassian.net/wiki/download/attachments/6586375/raft.pdf) 的实现。
>
> Raft 是一种共识性算法,想了解其原理,可以参考 [深入剖析共识性算法 Raft](https://github.com/dunwu/blog/blob/master/source/_posts/distributed/raft.md)。
> Raft 是一种共识性算法,想了解其原理,可以参考 [深入剖析共识性算法 Raft](https://github.com/dunwu/blog/blob/master/source/_posts/theory/raft.md)。
当一个主服务器被判断为客观下线时,监视这个下线主服务器的各个 Sentinel 会进行协商,选举出一个领头的 Sentinel并由领头 Sentinel 对下线主服务器执行故障转移操作。
@ -173,7 +173,7 @@ Sentinel 对 `__sentinel__:hello` 频道的订阅会一直持续到 Sentinel 与
## 七、要点总结
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200224221812.png)
![img](http://dunwu.test.upcdn.net/snap/20200224221812.png)
## 参考资料

View File

@ -1 +0,0 @@
# Redis 事务

View File

@ -8,7 +8,7 @@
### SQL
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200115160512.png)
![img](http://dunwu.test.upcdn.net/snap/20200115160512.png)
- [SQL Cheat Sheet](sql-cheat-sheet.md) - SQL 速查手册

View File

@ -274,7 +274,7 @@ MyISAM 存储引擎支持空间数据索引R-Tree可以用于地理数
- **聚集索引**(`Clustered`):表中各行的物理顺序与键值的逻辑(索引)顺序相同,每个表只能有一个。
- **非聚集索引**(`Non-clustered`):非聚集索引指定表的逻辑顺序,也可以视为二级索引。数据存储在一个位置,索引存储在另一个位置,索引中包含指向数据存储位置的指针。可以有多个,小于 249 个。
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200304235424.jpg)
![img](http://dunwu.test.upcdn.net/snap/20200304235424.jpg)
如上图所示InnoDB 的聚簇索引,其叶子节点包含了行的全部数据,而非叶子节点则包含了索引列。

View File

@ -6,7 +6,7 @@
很多的查询优化工作实际上就是遵循一些原则让 MySQL 的优化器能够按照预想的合理方式运行而已。
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200227201908.jpg)
![img](http://dunwu.test.upcdn.net/snap/20200227201908.jpg)
### 1客户端/服务端通信协议

View File

@ -2,7 +2,7 @@
## 逻辑架构
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200229184651.png)
![img](http://dunwu.test.upcdn.net/snap/20200229184651.png)
MySQL 逻辑架构整体分为三层,最上层为客户端层,并非 MySQL 所独有,诸如:连接处理、授权认证、安全等功能均在这一层处理。

View File

@ -4,7 +4,7 @@
>
> 本文语法主要针对 Mysql。
![img](https://raw.githubusercontent.com/dunwu/images/master/snap/20200115160512.png)
![img](http://dunwu.test.upcdn.net/snap/20200115160512.png)
## 一、基本概念