● ELK是包含但不限于ElasticSearch(简称es)、Logstash、Kibana三个开源软件组成的一个整体。这三个软件合称ELK。是用于数据抽取(Logstash)、搜索分析(ElasticSearch)、数据展现(Kibana)的一整套解决方案,所以也称为ELK stack。
● 本文从ES底层对文档、索引、搜索、聚合、集群进行介绍,从搜索和聚合分析实例来展现ES的魅力。Logstash从内部如何采集数据到指定地方来展现它数据采集的功能。Kibana则从数据绘图展现数据可视化的功能。
● ELK是一个免费开源的日志分析架构技术栈的总称,官网。包含了三大基础组件,分别是ElasticSearch、Logstash、Kibana。但是实际上ELK不仅仅适用于日志分析,它还可以支持其它任何数据搜索、分析和收集的场景,日志分析和收集只是更具有代表性,并非唯一性。
随着ELK的发展,又有新成员Beats、Elastic Cloud的加入,所以就形成了Elastic Stack。所以说,ELK是旧称,Elastic Stack是新的名字。
● 处理方式灵活:ElasticSearch是目前最流行的准实时的全文检索引擎,具有高速检索大数据的能力。
● 配置简单:安装ELK的每个组件,仅需要配置每个组件的一个配置文件即可,修改处不多,因为大量参数已经默认在系统中,修改想要的选项即可。
● 接口简单:采用JSON形式的REST API接受数据并响应,和语言无关。
● 性能高效:ElasticSearch基于优秀的全文检索技术Lucene,采用倒排索引,可以轻易的在百亿级别数据量下,搜索出想要的内容,并且是秒级响应。
● 灵活扩展:ElasticSearch和Logstash都可以根据集群规模性拓展,ElasticSearch内部自动实现集群协作。
● 数据展现华丽:Kibana作为前端展现工具,图表华丽,配置简单。
● ElasticSearch:ElasticSearch是使用Java开发,基于Lucene、分布式、通过REST方式进行交互的近实时搜索平台框架。它的特点有:分布式、零配置、自动发现、索引自动分片、索引副本机制,REST风格接口、多数据源、自动搜索负载等等。
● Logstash:Logstash基于Java开发,是一个数据抽取转换工具。一般工作方式为C/S架构,Client端安装在需要收集信息的主机上,Server端负责将收到的各节点日志进行过、修改等操作,再发往ElasticSearch或其他组件上去。
● Kibana:Kibana基于nodejs,也是一个开源和免费的可视化工具。Kibana可以为Logstash和ElasticSearch提供日志分析友好的Web界面,可以汇总、分析和搜索重要数据日志。
● Beats:Beats平台集合了多种单一用途数据采集器。它们从成百上千或成千上万台机器和系统向Logstach或ElasticSearch发送数据。Beats有以下组件组成:
○ Packetbeat:轻量级网络数据采集器,用于深挖网线上传输的数据,了解应用程序动态。Packetbeat是一款轻量型网络数据包分析器,能够将数据发送至Logstash或ElasticSearch。其支持ICMP(v4和v6)、DNS、HTTP、MySQL、PostgreSQL、Redis、MongoDB、Memcache等协议。
○ Filebeat:轻量级日志采集器。当你要面对成百上千、甚至成千上万的服务器、虚拟机和容器生成的日志时,请告别SSH,Filebeat将为你提供一种轻量型方法,用于转发和汇总日志和文件,让简单的事情不再复杂。
○ Metricbeat:轻量型指标采集器。Metricbeat能够以一种轻量型的方式,输送各种系统和服务统计数据,从CPU到内存,从Redis到Nginx,不一而足。可定期获取外部系统的监控指标信息,其可以监控、收集Apache http、HAProxy、MongoDB、MySQL、Nginx、PostgreSQL、Redis、System、Zookeeper等服务。
○ Winlogbeat:轻量型Windows事件日志采集器。用于密切监控基于Windows的基础设施上发生的事件。Winlogbeat能够以一种轻量型的方式,将Windows事件日志实时地流式传输至ElasticSearch和Logstash。
○ Auditbeat:轻量型审计日志采集器。收集Linux审计框架的数据,监控文件完整性。Auditbeat实时采集这些事件,然后发送到Elastic Stack其他部分做进一步分析。
○ Heartbeat:面向运行状态监控的轻量型采集器。通过主动探测来监测服务的可用性。通过给定URL列表,Heartbeat仅仅询问:网站运行正常吗?Heartbeat会将此信息和响应时间发送至Elastic Stack其他部分做进一步分析。
○ Functionbeat:面向云端数据的无服务器采集器。在作为一项功能部署在云服务提供商的功能即服务(Fass)平台上后,Functionbeat能收集、传送并监测来自云服务的相关数据。
● Elastic Cloud:基于ElasticSearch的软件即服务解决方案。通过Elastic的官方合作伙伴使用托管的ElasticSearch服务。
● 概念:用户输入想要的关键词,返回含有该关键词的所有信息。
● 场景:
○ 互联网搜索:谷歌、百度、各种新闻首页。
○ 站内搜索(垂直搜索):企业OA查询订单、人员和部门,电商网站内部搜索商品。
● 数据量小,简单搜索,可以使用数据库。
● 问题出现:
○ 存储问题:电商网站商品上亿条时,涉及到单表数据过大必须拆分表,数据库磁盘占用多大必须分库。
○ 性能问题:解决上面问题后,查询“笔记本电脑”等关键词时,上亿条数据的商品名称字段逐行扫描,性能跟不上。
○ 不能分词:如搜索“笔记本电脑”,只能搜索完全和关键词一样的数据,那么数据量小的时候,搜索“笔记电脑”,“电脑”数据要不要给用户。
● 肯定不会使用数据库搜索,数据量太大,PB级。
● 倒排索引。数据存储的时候,经过分词term建立索引库。
倒排索引源于实际应用中需要根据属性的值来查找记录。这种索引表中的每一项都包括一个属性值和具有该属性值的各记录的地址。由于不是由记录来确定属性值,而是由属性值来确定记录的位置,因而称为倒排索引。带有倒排索引的文件我们称之为倒排索引文件,简称倒排文件。
Lucene是一个jar包,里面封装了全文检索的引擎、搜索的算法代码。开发的时候,只需要引入Lucene的jar包,通过API开发搜索相关业务。底层会在磁盘中建立索引库。
ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于REST web接口。
● 分布式的搜索引擎和数据分析引擎:
○ 搜索:互联网搜索,电商网站站内搜索,OA系统查询。
○ 数据分析:电商网站查询近一周哪些品类的图书销售前十;新闻网站,最近3天阅读量最高的十个关键词、舆情分析。
● 全文检索、结构化检索、数据分析:
○ 全文检索:搜索商品名称包含java的图书select * from books where book_name like ‘%java%’。
○ 结构化检索:搜索商品分类为spring的图书select * from books where category_id = ‘spring’。
○ 数据分析:分析每一个分类下有多少种图书select category_id,count(*) from books group by category_id。
● 对海量数据进行近实时的处理:
○ 分布式:ES自动可以将海量数据分散到多台服务器上去存储和检索,经过并行查询,提高搜索效率。相对的,Lucene是单机应用。
○ 近实时:数据库上亿条数据查询,搜索一条耗时几个小时,是批处理。而ES只需要秒级即可查询海量数据,所
以叫近实时,秒级。
● 国外:
○ 维基百科:类似于百度百科,“网络七层协议”的维基百科,全文检索,高亮,搜索推荐。
○ Stack Overflow(国外的程序讨论论坛),相当于程序员的贴吧。遇到IT问题去上面发帖,热心网友下面回帖解答。
○ GitHub(开源代码管理):搜索上千亿行代码。
○ 电商网络:检索商品。
○ 日志数据分析:Logstash采集日志,ES进行复杂的数据分析。
○ 商品价格监控网站:用户设定某商品的价格阈值,当低于该阈值的时候,发送通知消息给用户,比如订阅《Java编程思想》的监控,如果价格低于27元,就通知我,我再去买。
○ BI系统(商业智能):大型连锁超市,分析全国网点传回的数据,分析各个商铺在什么季节的销售量最高、利润最高。成本管理、店面租金、员工工资、负债等信息进行分析,从而部署下一阶段的战略目标。
● 国内:
○ 百度搜索:第一次搜索,使用ES。
○ OA、ERP系统站内搜索。
● 可拓展性:大型分布式集群(数百台服务器)技术,处理PB级数据,大公司可以 使用。小公司数据量小,也可以部署在单机。大数据领域使用广泛。
● 技术整合:将全文检索、数据分析、分布式相关技术整合在一起:Lucene(全文检索)、商用的数据分析软件(BI软件)、分布式数据库中间件(mycat)。
● 部署简单:开箱即用,很多默认配置无需关心,解压即可直接运行。拓展时,只需多部署几个实例即可,负载均衡、分片迁移集群内部自己实施。
● 接口简单:使用REST API进行交互,跨语言。
● 功能强大:ElasticSearch作为传统数据库的一个补充,提供了数据库所不能提供的很多功能,如全文检索、同义
词处理、相关度排名。
● Lucene:最先进、功能最强大的搜索库,直接基于Lucene开发,非常复杂,API复杂。
● ElasticSearch:基于Lucene,封装了许多Lucene底层功能,提供简单易用的REST API接口和许多语言的客户端,如Java的高级客户端(Java High Level RET Client)和底层客户端(Java Low Level REST Client)。
● NRT(Near Realtime):近实时。
○ 写入数据时,过1秒才会被搜索到,因为内部在分词,录入索引。
○ ES搜索时搜索和分析数据需要秒级才能出结果。
● Cluster:集群。
○ 包含一个或多个启动ES实例的机器群。通常一台机器起一个ES实例。同一网络下,集群名一样的多个ES实例自动组成集群,自动均衡切片等行为。默认集群名为"elasticsearch"。
● Node:节点。
○ 每个ES实例称为一个节点,节点名自动分配,也可以手动配置。
● Document:文档。
○ ES中的最小数据单元。一个document就像数据库中的一条记录。通常以JSON格式显示。多个document存储
于一个索引(Index)中。
book document
{
"book_id": "1",
"book_name": "java编程思想",
"book_desc": "从Java的基础语法到最高级特性(深入的[面向对象](https://baike.baidu.com/item/面向对象)概念、多线程、自动项目构建、单元测试和调试等),本书都能逐步指导你轻松掌握。",
"category_id": "2",
"category_name": "java"
}
● Index:索引。
○ 包含一堆相似结构的文档数据。
○ 索引创建规则:
■ 仅限于小写字母。
■ 不能包含\、/、 *、?、"、<、>、|、#以及空格符等特殊符号。
■ 从7.0版本开始不再包含冒号。
■ 不能以-、_或+开头。
■ 不能超过255个字节(注意它是字节,因此多字节字符将计入255个限制)。
● Field:字段。
○ 就像数据库中的列,定义每个document应该有的字段。
● Type:类型。
○ 每个索引里面都可以有一个或多个type,type是index中的一个逻辑数据分类。一个type下的document都有相同的field。
○ 注意:6.0之前的版本有type(类型)的概念,type相当于关系数据库的表,ES官方将在ES9.0版本中彻底删除type。7.0版本的type默认为_doc。
● shard:分片。
○ index数据过大的时候,将index里面的数据,分为多个shard,分布式存储在各个服务器上面。可以支持海量数据和高并发,提高性能和吞吐量,充分利用多台机器的CPU。
● replica:副本。
○ 在分布式环境下,任何一台机器都会随时宕机,如果宕机,index的一个分片没有,导致此index不能搜索。所以,为了保证数据的安全,我们会将每个index的分片经过备份,存储在另外的机器上。保证少数机器宕机ES集群依然可以搜索。
○ 能正常提供查询和插入的分片我们称为主分片(primary shard),其余的我们就叫做备份的分片(replica shard)。
○ ES6默认新建索引时,5分片,1副本,也就是一主一备,共10个分片。所以,ES集群最小规模为2台。ES7,1分片,1副本,一共2分片。
关系型数据库(如MySQL) | 非关系型数据库(如ElasticSearch) |
---|---|
数据库Database | 索引Index |
表Table | 索引Index(原来为Type) |
数据行Row | 文档Document |
数据列Column | 字段Field |
约束Schema | 映射Mapping |
● 应用系统的数据结构都是面向对象的,具有复杂的数据结构。
● 对象存储到数据库,需要将关联的复杂对象属性插入到另一张表,查询时再拼接起来。
● ES是面向文档,文档中存储的数据和对象一致。所以一个对象可以直接保存成一个文档。
● ES的Document用JSON数据格式来表达。
● 示例:
● Java描述学生和班级的关系:
//学生表
public class Student{
private String id;
private String name;
private String classInfoId;
}
//班级表
public class ClassInfo{
private String id;
private String className;
}
● 数据库中要设计所谓的一对多,多对一的两张表、外键等。查询出来的时候,还需要关联,Mybatis写映射文件,很繁琐。
● ES中,一个学生的文档如下:
{
"id":"1",
"name":"张三",
"last_name":"zhang",
"classInfo":{
"id":"1",
"className":"三年二班",
}
}
● 有一个售卖图书的网站,需要为其基于ES构建一个后台系统,提供如下功能:
● 对商品信息进行CRUD(增删改查)操作。
● 执行简单的结构化查询。
● 可以执行简单的全文检索,以及复杂的phrase(短语)检索。
● 对于全文检索的结果,可以进行高亮显示。
● 对数据进行简单的聚合分析。
GET /_cat/health?v
如何快速的了解集群的健康状况?green、yellow、red?
GET /_cat/indices?v
PUT /demo_index?pretty
DELETE /demo_index?pretty
PUT /index
PUT /book
PUT /index/type/id
{
}
PUT /book/_doc/1
{
"name": "Bootstrap开发",
"description": "Bootstrap是由Twitter推出的一个前台页面开发css框架,是一个非常流行的开发框架,此框架集成了多种页面效果。此开发框架包含了大量的CSS、JS程序代码,可以帮助开发者(尤其是不擅长css页面开发的程序人员)轻松的实现一个css,不受浏览器限制的精美界面css效果。",
"studymodel": "201002",
"price":38.6,
"timestamp":"2019-08-25 19:11:35",
"pic":"group1/M00/00/00/wKhlQFs6RCeAY0pHAAJx5ZjNDEM428.jpg",
"tags": [ "bootstrap", "dev"]
}
PUT /book/_doc/2
{
"name": "java编程思想",
"description": "java语言是世界第一编程语言,在软件开发领域使用人数最多。",
"studymodel": "201001",
"price":68.6,
"timestamp":"2019-08-25 19:11:35",
"pic":"group1/M00/00/00/wKhlQFs6RCeAY0pHAAJx5ZjNDEM428.jpg",
"tags": [ "java", "dev"]
}
PUT /book/_doc/3
{
"name": "spring开发基础",
"description": "spring 在java领域非常流行,java程序员都在用。",
"studymodel": "201001",
"price":88.6,
"timestamp":"2019-08-24 19:11:35",
"pic":"group1/M00/00/00/wKhlQFs6RCeAY0pHAAJx5ZjNDEM428.jpg",
"tags": [ "spring", "java"]
}
GET /index/type/id
GET /book/_doc/1
PUT /index/type/id
{
}
PUT /book/_doc/1
{
"name": "Bootstrap开发教程1",
"description": "Bootstrap是由Twitter推出的一个前台页面开发css框架,是一个非常流行的开发框架,此框架集成了多种页面效果。此开发框架包含了大量的CSS、JS程序代码,可以帮助开发者(尤其是不擅长css页面开发的程序人员)轻松的实现一个css,不受浏览器限制的精美界面css效果。",
"studymodel": "201002",
"price":38.6,
"timestamp":"2019-08-25 19:11:35",
"pic":"group1/M00/00/00/wKhlQFs6RCeAY0pHAAJx5ZjNDEM428.jpg",
"tags": [ "bootstrap", "开发"]
}
POST /index/type/id/_update
{
}
POST /index/_update/id
{
}
POST /book/_update/1
{
"doc": {
"name": " Bootstrap开发教程高级"
}
}
DELETE /index/type/id
DELETE /book/_doc/1
GET /book/_doc/2
{
"_index" : "book",
"_type" : "_doc",
"_id" : "2",
"_version" : 1,
"_seq_no" : 1,
"_primary_term" : 1,
"found" : true,
"_source" : {
"name" : "java编程思想",
"description" : "java语言是世界第一编程语言,在软件开发领域使用人数最多。",
"studymodel" : "201001",
"price" : 68.6,
"timestamp" : "2019-08-25 19:11:35",
"pic" : "group1/M00/00/00/wKhlQFs6RCeAY0pHAAJx5ZjNDEM428.jpg",
"tags" : [
"java",
"dev"
]
}
}
● 含义:此文档属于哪个索引。
● 原则:类似数据放在一个索引中。和数据库中的表的定义规则类似。如图书信息放在book索引中,员工信息放在employee索引中。各个索引存储和搜索互不影响。
● 定义规则:英文小写。尽量不要使用特殊字符,如order、user等。
● 含义:类别。
● 注意:以后的ES9将彻底删除此字段,所以当前版本在不断的弱化type。不需要关心,见到的_type都是_doc。
● 含义:文档的唯一标识。类似表中的主键。_id和_index结合起来可以标识和定义一个文档。
● 生成:手动(PUT /index/_doc/id)、自动
● 场景:数据从其他系统导入的时候,本身就有唯一主键。如数据库中的图书、员工信息等。
● 语法:
PUT /index/type/id
示例:
PUT /test_index/_doc/1
{
"test_filed":"test"
}
POST /index/type
POST /test_index/_doc
{
"test_filed":"test1"
}
自动生成id的特点:长度为20个字符,URL安全,base64编码,GUID,分布式生成不冲突。
● 含义:插入数据时候的所有字段和值,在GET获取数据的时候,在_source中原样返回。
● 就像SQL一样,不使用select * from book,而使用select id,name from book。
● 语法:
GET /index/type/id?_source_includes=字段1,字段2
示例:
GET /book/_doc/2?_source_includes=name,description
● 执行两次PUT,返回结果中的版本号(_version)在不断的上升。此过程为全量替换。
● 示例:
PUT /test_index/_doc/1
{
"test_filed":"test"
}
实际上,旧文档的内容不会立即删除,只是标记为deleted。适当的时机,集群会将这些旧文档删除
为了防止覆盖原有数据,我们在新增的时候,设置为强制创建,不会覆盖原有文档(因为点击2次以上,就会报错)。
语法:
PUT /index/type/id/_create
{
}
示例:
PUT /test_index/_doc/2/_create
{
"test_filed":"test2"
}
● 语法:
DELETE /index/type/id
实际上旧文档的内容不会立即删除,只是标记为deleted。适当的时机,集群会将这些旧文档删除。
● 使用PUT语法是文档全量替换,需要将文档所有数据提交:
PUT /index/type/id
{
}
使用POST命令可以进行局部替换:
POST /index/_update/id
{
}
POST /index/type/id/_update
{
}
● 全量更新的步骤:
○ 用户发送数据到Java程序中,Java程序获取到用户发送的数据。
○ Java程序根据id去ES集群中查询到对应的文档数据,如果查询到,那么就将从ES集群中查询到的对应的文档数据替换用户发送数据的指定字段的值。
○ Java程序将替换后的数据发送到ES集群中。
● 局部更新的步骤:
○ 用户发送数据到Java程序中,Java程序获取到用户发送的数据。
○ Java程序直接将用户发送的数据,发送给ES集群,由集群内部自动替换相应文档的对应字段的值。
局部更新和全量更新一样,都是旧文档被标记为deleted,新建一个文档。适当的时机,集群会将这些旧文档删除。
局部更新的优点:
如同秒杀,多线程情况下,ES同样会出现并发冲突问题。
● 为控制并发问题,我们通常采用锁机制,分为悲观锁和乐观锁。
● 悲观锁:
○ 很悲观,所有情况都上锁。此时只有一个线程可用操作数据。具体的例子为数据库中的行锁、表锁、读锁和写锁等。
○ 特点:
■ 优点:方便,直接加锁,对程序透明。
■ 缺点:效率低。
● 乐观锁:
○ 很乐观,对数据本身不加锁。提交数据的时候,通过一种机制验证是否存在冲突,如ES中通过版本号验证。
○ 特点:
■ 优点:并发能力高。
■ 缺点:操作繁琐,在提交数据的时候,可能反复重试多次。
● ES对于文档的增删改都是基于版本号的。
● 示例:
①新增多次文档:返回版本号递增
PUT /test_index/_doc/3
{
"test_field": "test"
}
②删除此文档:
DELETE /test_index/_doc/3
返回:
DELETE /test_index/_doc/3
{
"_index" : "test_index",
"_type" : "_doc",
"_id" : "2",
"_version" : 6,
"result" : "deleted",
"_shards" : {
"total" : 2,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 7,
"_primary_term" : 1
}
③再新增:
PUT /test_index/_doc/3
{
"test_field": "test"
}
可以看到版本号依然新增,验证延迟删除策略。
如果删除一条数据,所有分片和副本都要立即删除,对ES集群的压力太大。
● ES内部主从同步的时候,是多线程异步同步,基于乐观锁机制。
● 已经有数据在ES中,需要自己手动维护版本号,可以使用external version。
● 修改的时候external version要大于当前文档的的_version。
put /index/type/id?version=xx&version_type=external
{
}
● 示例:
● ①新增文档:
PUT /test_index2/_doc/1
{
"test":"test"
}
②客户端1更新文档:
PUT /test_index2/_doc/1?version=2&version_type=external
{
"test":"test1"
}
②客户端2更新文档:
PUT /test_index2/_doc/1?version=2&version_type=external
{
"test":"test2"
}
POST /index/_upadte/id?retry_on_conflict=3
{
"doc": {
}
}
POST /test_index2/_update/1?retry_on_conflict=3&version=22&version_type=external
{
"doc": {
"test":"test5"
}
}
GET /_mget
{
"docs":[
{
"_index":"xxx",
"_id":"xxxx"
},
{
"_index":"xxx",
"_id":"xxxx"
}
]
}
GET /_mget
{
"docs":[
{
"_index":"test_index",
"_id":1
} ,
{
"_index":"test_index",
"_id":2
}
]
}
GET /index/_mget
{
"docs":[
{
"_id":"xxxx"
},
{
"_id":"xxxx"
}
]
}
GET /test_index/_mget
{
"docs": [
{
"_id": 1
},
{
"_id": 2
}
]
}
POST /index/_doc/_search
{
"query":{
"ids":{
"values":["xx","xx"]
}
}
}
POST /test_index/_doc/_search
{
"query":{
"ids":{
"values":["1","2"]
}
}
}
● bulk操作结束将文档的增删改一些列操作,通过一次请求全部做完,减少了网络传输次数。
● 语法:
POST /_bulk
{"action":"metadata"}
{"data"}
格式:每个json不能换行,相邻的json必须换行。
隔离:每个操作互不影响。操作失败会返回其失败信息。
实际用法:bulk请求不要一次太大,否则一下积压到内存中,会造成性能下降,所以,一次请求几千个操作,大小在几M正好。
POST /_bulk
{ "delete": { "_index": "test_index", "_id": "5" }}
{ "create": { "_index": "test_index", "_id": "14" }}
{ "test_field": "test14" }
{ "update": { "_index": "test_index", "_id": "2"} }
{ "doc" : {"test_field" : "bulk test"} }