Elastic Stack (一)

Elastic Stack 简介

ELK是一个免费开源的日志分析架构技术栈总称,官网https://www.elastic.co/cn。ELK包含但不限于Elasticsearch(简称es)、Logstash、Kibana 三个开源软件的组成的一个整体。是用于数据抽取(Logstash)、搜索分析(Elasticsearch)、数据展现(Kibana)的一整套解决方案,所以也称作ELK stack。
但实际上ELK不仅仅适用于日志分析,它还可以支持其它任何数据搜索、分析和收集的场景,日志分析和收集只是更具有代表性。并非唯一性。下面是ELK架构:

随着elk的发展,又有新成员Beats、elastic cloud的加入,所以就形成了Elastic Stack。所以说,ELK是旧的称呼,Elastic Stack是新的名字。

https://www.elastic.co/cn/what-is/elk-stack

特色

  • 处理方式灵活:elasticsearch是目前最流行的准实时全文检索引擎,具有高速检索大数据的能力。

  • 配置简单:安装elk的每个组件,仅需配置每个组件的一个配置文件即可。修改处不多,因为大量参数已经默认配在系统中,修改想要修改的选项即可。

  • 接口简单:采用json形式RESTFUL API接受数据并响应,无关语言。

  • 性能高效:elasticsearch基于优秀的全文搜索技术Lucene,采用倒排索引,可以轻易地在百亿级别数据量下,搜索出想要的内容,并且是秒级响应。

  • 灵活扩展:elasticsearch和logstash都可以根据集群规模线性拓展,elasticsearch内部自动实现集群协作。

  • 数据展现华丽:kibana作为前端展现工具,图表华丽,配置简单。

组件介绍

Elasticsearch

Elasticsearch 是使用java开发,基于Lucene、分布式、通过Restful方式进行交互的近实时搜索平台框架。它的特点有:分布式,零配置,自动发现,索引自动分片,索引副本机制,restful风格接口,多数据源,自动搜索负载等。

Logstash

Logstash 基于java开发,是一个数据抽取转化工具。一般工作方式为c/s架构,client端安装在需要收集信息的主机上,server端负责将收到的各节点日志进行过滤、修改等操作在一并发往elasticsearch或其他组件上去。

Kibana

Kibana 基于nodejs,也是一个开源和免费的可视化工具。Kibana可以为 Logstash 和 ElasticSearch 提供的日志分析友好的 Web 界面,可以汇总、分析和搜索重要数据日志。

Beats

Beats 平台集合了多种单一用途数据采集器。它们从成百上千或成千上万台机器和系统向 Logstash 或 Elasticsearch 发送数据。

Elasticsearch和Lucene 的关系

Lucene:最先进、功能最强大的搜索库,直接基于lucene开发,非常复杂,api复杂

Elasticsearch:基于lucene,封装了许多lucene底层功能,提供简单易用的restful api接口和许多语言的客户端,如java的高级客户端(Java High Level REST Client)和底层客户端(Java Low Level REST Client

Elasticsearch 的 核心概念

倒排索引

正向索引:
传统数据库(如MySQL)采用正向索引,例如给下表(tb_goods) 中的id创建索引:

根据字段局部内容做检索的时候效率比较差:

倒排索引:

elasticsearch 采用倒排索引:

  • 文档(document):每条数据就是个文档
  • 词条(tearm):文档按照语义分成的词语

查找过程:
根据词条查找到对应的id

NRT(Near Realtime):近实时

两方面:

  • 写入数据时,过1秒才会被搜索到,因为内部在分词、录入索引。

  • es搜索时:搜索和分析数据需要秒级出结果。

Cluster:集群

包含一个或多个启动着es实例的机器群。通常一台机器起一个es实例。同一网络下,集名一样的多个es实例自动组成集群,自动均衡分片等行为。默认集群名为“elasticsearch”。

Node:节点

每个es实例称为一个节点。节点名自动分配,也可以手动配置。

Index:索引

包含一堆有相似结构的文档数据。

索引创建规则:

  • 仅限小写字母

  • 不能包含\、/、 *、?、"、<、>、|、#以及空格符等特殊符号

  • 从7.0版本开始不再包含冒号

  • 不能以-、_或+开头

  • 不能超过255个字节(注意它是字节,因此多字节字符将计入255个限制)

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"
}

Field:字段

就像数据库中的列(Columns),定义每个document应该有的字段。

Type:类型

每个索引里都可以有一个或多个type,type是index中的一个逻辑数据分类,一个type下的document,都有相同的field。

注意:6.0之前的版本有type(类型)概念,type相当于关系数据库的表,ES官方将在ES9.0版本中彻底删除type。本教程typy都为_doc。

shard:分片

index数据过大时,将index里面的数据,分为多个shard,分布式的存储在各个服务器上面。可以支持海量数据和高并发,提升性能和吞吐量,充分利用多台机器的cpu。

replica:副本

在分布式环境下,任何一台机器都会随时宕机,如果宕机,index的一个分片没有,导致此index不能搜索。所以,为了保证数据的安全,我们会将每个index的分片经行备份,存储在另外的机器上。保证少数机器宕机es集群仍可以搜索。

能正常提供查询和插入的分片我们叫做主分片(primary shard),其余的我们就管他们叫做备份的分片(replica shard)。

Elasticsearch vs. MYSQL

核心概念:

架构:
Mysql: 擅长事务类型操作,可以确保数据的安全和一致性
Elasticsearch:擅长海量数据的搜索、分析、计算

Elasticsearch 快速入门

Windows 搭建环境 - Elasticsearch

运行elasticsearch.bat 出现以下问题:

解决:

讲一下配置改为false,默认是true
# Enable security features
xpack.security.enabled: false

地址栏访问:http://localhost:9200/,返回以下信息代表启动成功:

{
  "name" : "DESKTOP-9PANV23",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "yoCqdOBGS2SppfEwPXgbMg",
  "version" : {
    "number" : "8.4.2",
    "build_flavor" : "default",
    "build_type" : "zip",
    "build_hash" : "89f8c6d8429db93b816403ee75e5c270b43a940a",
    "build_date" : "2022-09-14T16:26:04.382547801Z",
    "build_snapshot" : false,
    "lucene_version" : "9.3.0",
    "minimum_wire_compatibility_version" : "7.17.0",
    "minimum_index_compatibility_version" : "7.0.0"
  },
  "tagline" : "You Know, for Search"
}

Windows 搭建环境 - Kibanan

  1. 下载解压直接运行kibana.bat ,访问

  2. 访问http://localhost:5601/

文档(document)的数据格式

(1)应用系统的数据结构都是面向对象的,具有复杂的数据结构

(2)对象存储到数据库,需要将关联的复杂对象属性插到另一张表,查询时再拼接起来。

(3)es面向文档,文档中存储的数据结构,与对象一致。所以一个对象可以直接存成一个文档。

(4)es的document用json数据格式来表达。

例如:班级和学生关系

public class Student {
  private String id;
  private String name;
  
  private String classInfoId;  
}

private class ClassInfo {
  private String id;
  private String className;
。。。。。

}

数据库中要设计所谓的一对多,多对一的两张表,外键等。查询出来时,还要关联,mybatis写映射文件,很繁琐。

而在es中,一个学生存成文档如下:

{
    "id":"1",
    "name": "张三",
    "last_name": "zhang",
    "classInfo": {
        "id": "1",
        "className": "三年二班",     
    }
}

RESTful API

在Elasticsearch中,提供了功能丰富的RESTful API的操作,包括基本的CRUD、创建索引、删除索引等操作。

快速检查集群的健康状况

GET _cat/health?v

如何快速了解集群的健康状况?

green:每个索引的primary shard和replica shard都是active状态的

yellow:每个索引的primary shard都是active状态的,但是部分replica shard不是active状态,处于不可用的状态

red:不是所有索引的primary shard都是active状态的,部分索引有数据丢失了

创建空索引

POST /book
{
  "acknowledged": true,
  "shards_acknowledged": true,
  "index": "book"
}

删除索引

DELETE /book
{
  "acknowledged": true
}

插入数据

URL规则: POST /{索引}/{类型}/

PUT/POST /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"]
}


返回:
{
  "_index": "book",
  "_id": "1",
  "_version": 1,
  "result": "created",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 0,
  "_primary_term": 1
}

查询索引

语法:GET /{索引}/{类型}/

GET /book/_doc/1

返回:
{
  "_index": "book",
  "_id": "1",
  "_version": 1,
  "_seq_no": 0,
  "_primary_term": 1,
  "found": true,
  "_source": {
    "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"
    ]
  }
}

局部更新数据

在Elasticsearch中,文档数据是不为修改的,但是可以通过覆盖的方式进行更新。

语法:POST /{index}/_update/

POST /book/_update/1/
{
  "doc": {
   "name": " Bootstrap开发教程高级"
  }
}

返回:
{
  "_index": "book",
  "_id": "1",
  "_version": 2,    => 版本加1
  "result": "updated",
  "_shards": { 
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 3,
  "_primary_term": 1
}

Kibanan 中查看索引

在Discover 面板中创建一个 data view

创建完毕后便可以看到匹配到所有book开头的索引的document

Document 入门

_index

  • 含义:此文档属于哪个索引
  • 原则:类似数据放在一个索引中。数据库中表的定义规则。如图书信息放在book索引中,员工信息放在employee索引中。各个索引存储和搜索时互不影响。
  • 定义规则:英文小写。尽量不要使用特殊字符。order user

_type

  • 含义:类别。book java node
  • 注意:以后的es9将彻底删除此字段,所以当前版本在不断弱化type。不需要关注。见到_type都为doc。

_id

  • 含义:文档的唯一标识。就像表的id主键。结合索引可以标识和定义一个文档。

  • 生成:手动(put /index/_doc/id)、自动

生成文档id 的两种方式

  • 手动

场景:数据从其他系统导入时,本身有唯一主键。如数据库中的图书、员工信息等。
用法:put /{index}/_doc/{id}

PUT /test_index/_doc/1
{
  "test_field": "test"
}
  • 自动
    用法: POST /{index}/_doc
    自动id特点:长度为20个字符,URL安全,base64编码,GUID,分布式生成不冲突
POST /test_index/_doc
{
  "test_filed":"abc"
}

返回:
{
  "_index": "test_index",
  "_id": "eEZtbYMBoa2T73yXVPlu",
  "_version": 1,
  "result": "created",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 0,
  "_primary_term": 1
}

_source

GET 请求返回的JSON数据中都包含有一个_source字段,该字段有什么用?

含义:储存插入数据时的所有字段和值。在get获取数据时,在_source字段中原样返回。

也可以定制返回字段,就像sql不要select *,而要select name,price from book …一样。

GET /book/_doc/1?_source_includes=name,price

观察_source的返回,只有name和price的返回
{
  "_index": "book",
  "_id": "1",
  "_version": 3,
  "_seq_no": 4,
  "_primary_term": 1,
  "found": true,
  "_source": {
    "name": " Bootstrap开发教程高级22222",
    "price": 38.6
  }
}

全量替换

执行两次,返回结果中版本号(_version)在不断上升,result 由create变为update 的过程为全量替换。
实质:旧文档的内容不会立即删除,只是标记为deleted。适当的时机,集群会将这些文档删除。

执行第一次:
PUT /test_index/_doc/1
{
  "test_filed":"aaaa"
}
返回:
{
  "_index": "test_index",
  "_id": "1",
  "_version": 1,
  "result": "created",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 4,
  "_primary_term": 1
}

执行第二次返回:
{
  "_index": "test_index",
  "_id": "1",
  "_version": 2,
  "result": "updated",   <= 变为update
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  },
  "_seq_no": 5,
  "_primary_term": 1
}

强制创建

为防止覆盖原有数据,我们在新增时,设置为强制创建,则在之后再次创建时会报错,不会创建成功

语法:PUT /{index}/_doc/{id}/_create

PUT /test_index/_doc/1/_create
{
  "test_field": "test"
}

返回:
{
  "error": {
    "root_cause": [
      {
        "type": "version_conflict_engine_exception",
        "reason": "[2]: version conflict, document already exists (current version [1])",
        "index_uuid": "lqzVqxZLQuCnd6LYtZsMkg",
        "shard": "0",
        "index": "test_index"
      }
    ],
    "type": "version_conflict_engine_exception",
    "reason": "[2]: version conflict, document already exists (current version [1])",
    "index_uuid": "lqzVqxZLQuCnd6LYtZsMkg",
    "shard": "0",
    "index": "test_index"
  },
  "status": 409
}

删除文档

语法:DELETE /{index}/_doc/

实质:旧文档的内容不会立即删除,只是标记为deleted。适当的时机,集群会将这些文档删除。lazy delete

全量更新和局部更新的区别

局部更新即: POST /{index}/_update/{id}/

内部与全量替换是一样的,旧文档标记为删除,新建一个文档。

优点:

  • 大大减少网络传输次数和流量,提升性能
  • 减少并发冲突发生的概率。

ES内部机制

shard & replica 机制

(1)每个index包含一个或多个shard

(2)每个shard都是一个最小工作单元,承载部分数据,lucene实例,完整的建立索引和处理请求的能力

(3)增减节点时,shard会自动在nodes中负载均衡

(4)primary shard和replica shard,每个document肯定只存在于某一个primary shard以及其对应的replica shard中,不可能存在于多个primary shard

(5)replica shard是primary shard的副本,负责容错,以及承担读请求负载

(6)primary shard的数量在创建索引的时候就固定了,replica shard的数量可以随时修改

(7)primary shard的默认数量是1,replica默认是1,默认共有2个shard,1个primary shard,1个replica shard

注意:es7以前primary shard的默认数量是5,replica默认是1,默认有10个shard,5个primary shard,5个replica shard

(8)primary shard不能和自己的replica shard放在同一个节点上(否则节点宕机,primary shard和副本都丢失,起不到容错的作用),但是可以和其他primary shard的replica shard放在同一个节点上

单节点创建index

(1)单node环境下,创建一个index,有3个primary shard,3个replica shard
(2)集群status是yellow
(3)这个时候,只会将3个primary shard分配到仅有的一个node上去,另外3个replica shard是无法分配的
(4)集群可以正常工作,但是一旦出现节点宕机,数据全部丢失,而且集群不可用,无法承接任何请求

PUT /test_index1
{
   "settings" : {
      "number_of_shards" : 3,
      "number_of_replicas" : 1
   }
}

数据路由

一个文档,最终会落在主分片的一个分片上,到底应该在哪一个分片?这就是数据路由。

路由算法:

哈希值对主分片数取模: shard = hash(routing) % number_of_primary_shards

举例:

对一个文档经行crud时,都会带一个路由值 routing number。默认为文档_id(可能是手动指定,也可能是自动生成)。

存储1号文档,经过哈希计算,哈希值为2,此索引有3个主分片,那么计算2%3=2,就算出此文档在P2分片上。

决定一个document在哪个shard上,最重要的一个值就是routing值,默认是_id,也可以手动指定,相同的routing值,每次过来,从hash函数中,产出的hash值一定是相同的

无论hash值是几,无论是什么数字,对number_of_primary_shards求余数,结果一定是在0~number_of_primary_shards-1之间这个范围内的。0,1,2。

涉及到以往数据的查询搜索,所以一旦建立索引,主分片数不可变。

文档增删改的内部流程

增删改可以看做update,都是对数据的改动。一个改动请求发送到es集群,经历以下四个步骤:

(1)客户端选择一个node发送请求过去,这个node就是coordinating node(协调节点)

(2)coordinating node,对document进行路由,将请求转发给对应的node(有primary shard)

(3)实际的node上的primary shard处理请求,然后将数据同步到replica node。

(4)coordinating node,如果发现primary node和所有replica node都搞定之后,就返回响应结果给客户端。

文档查询的内部机制

1、客户端发送请求到任意一个node,成为coordinate node

2、coordinate node对document进行路由,将请求转发到对应的node,此时会使用round-robin随机轮询算法,在primary shard以及其所有replica中随机选择一个,让读请求负载均衡

3、接收请求的node返回document给coordinate node

4、coordinate node返回document给客户端

5、特殊情况:document如果还在建立索引过程中,可能只有primary shard有,任何一个replica shard都没有,此时可能会导致无法读取到document,但是document完成索引建立之后,primary shard和replica shard就都有了。

posted @ 2022-09-23 21:05  chuangzhou  阅读(50)  评论(0编辑  收藏  举报