elk 一

elasticsearch

ELK

Elastic Stack

ELK是一个免费开源的日志分析架构技术栈总称,官网https://www.elastic.co/cn

组件

  • Elasticsearch

  • Logstash

  • Kibana

  • Beats

  • Elastic cloud

功能

  • 数据搜索

  • 分析和收集

  • 日志分析

Elasticsearch

搜索

用户输入想要的关键词,返回含有该关键词的所有信息

互联网搜索

谷歌、百度、各种新闻首页

站内搜索(垂直搜索)

企业OA查询订单、人员、部门,电商网站内部搜索商品

数据库做搜索的弊端

  • 存储问题

  • 性能问题

  • 不能分词

站内搜索(垂直搜索)数据量小,简单搜索,可以使用数据库

互联网搜索,肯定不会使用数据库搜索。数据量太大。PB级

全文检索 倒排索引 Lucene

数据存储时,经行分词建立term索引库

全局检索AND倒排索引

倒排索引源于实际应用中需要根据属性的值来查找记录。这种索引表中的每一项都包括一个属性值和具有该属性值的各记录的地址。由于不是由记录来确定属性值,而是由属性值来确定记录的位置,因而称为倒排索引(inverted index)。带有倒排索引的文件我们称为倒排索引文件,简称倒排文件(inverted file)

  • Lucene

一个jar包,封装了全文检索的引擎、搜索的算法代码。底层会在磁盘建立索引库

Elasticsearch功能

分布式的搜索引擎和数据分析引擎

  • 搜索

互联网搜索,站内搜索,OA系统查询

  • 数据分析

销量前10,最近7天搜索最高的关键字,热点话题分析

全文检索,结构化检索,数据分析

  • 全文检索

搜索一个商品包含某个关键字

  • 结构化检索

搜索一个分类的商品

  • 数据分析

搜索一个分类下的商品数量

海量数据进行近实时的处理

  • 分布式

ES自动将海量数据分散到多台服务器上去存储和检索,经行并行查询,提高搜索效率。相对的,Lucene是单机应用

  • 近实时

数据库上亿条数据查询,搜索一次耗时几个小时,是批处理,而es只需秒级即可查询海量数据,所以叫近实时。秒级

Elasticserch场景

  • 百度搜索

第一次查询,使用es

  • OA、ERP系统站内搜索

Elasticserch特点

  • 可扩展

  • 技术整合

  • 部署简单

  • 接口简单

  • 功能强大

Elasticsearch核心概念

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

Elasticsearch 基于lucene,封装了许多lucene底层功能,提供简单易用的restful api接口和许多语言的客户端

NRT(近实时)

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

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

Cluster(集群)

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

Node(节点)

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

Index(索引)

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

Document(文档)

es中的最小数据单元。一个document就像数据库中的一条记录。通常以json格式显示。多个document存储于一个索引(Index)中

Field(字段)

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

Type(类型)

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

Shard(分片)

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

replica(副本)

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

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

es6默认新建索引时,5分片,2副本,也就是一主一备,共10个分片。所以,es集群最小规模为两台

Elasticsearch 对比 关系型数据库

关系型数据库 Elasticsearch
数据库Database 索引Index
表Table 索引Index(type)
数据行Row 文档Document
数据列Column 字段Field
约束 Schema 映射Mapping

Elasticsearch安装

这里用到jdk 版本高于1.8.0_73

下载地址
https://www.elastic.co/cn/

我在这里学习的版本是7.3.0

目录介绍

bin:脚本目录

config:配置文件目录

data:索引目录,存放索引文件的地方

logs:日志目录

modules:模块目录,包括了es的功能模块

plugins :插件目录,es支持插件机制

修改配置

  • elasticsearch.yml中添加
1
2
3
4
5
node.name: node-1  
cluster.initial_master_nodes: ["node-1"]
xpack.ml.enabled: false
http.cors.enabled: true
http.cors.allow-origin: /.*/

启动

bin目录中执行脚本文件elasticsearch.bat

访问 http://localhost:9200/ 即可查看

es启动信息查看

访问 http://localhost:9200/_cluster/health 查询集群状态

es集群状态

集群状态介绍

Status 集群状态

Green 所有分片可用

Yellow 所有主分片可用。Red主分片不可用,集群不可用

Kibana安装

、kibana是es数据的前端展现,数据分析时,可以方便地看到数据。作为开发人员,可以方便访问es

下载地址同上,一个旗下的产品

目录结构相似,也可以对其修改配置

i18n.locale: "zh-CN" 支持中文,配置里这个改下国际化就行

访问地址 http://localhost:5601

kibana查看

es详细

文档(document)的数据格式

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

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

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

  • es的document用json数据格式来表达

对象

1
2
3
4
5
6
7
8
9
10
11
public class Student {
private String id;
private String name;

private String classInfoId;
}

public class ClassInfo {
private String id;
private String className;
}

es

1
2
3
4
5
6
7
8
9
{
"id":"1",
"name": "张三",
"last_name": "zhang",
"classInfo": {
"id": "1",
"className": "三年二班",
}
}

集群管理

快速检查集群的健康状况

1
GET /_cat/health?v

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

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

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

快速查看集群中有哪些索引

1
GET /_cat/indices?v

document CRUD操作

新建索引

1
PUT /index

新建文档

语法:PUT /index/type/id

1
2
3
4
5
6
7
8
9
10
11
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"]
}

检索文档

语法:GET /index/type/id

1
GET /book/_doc/1 

修改文档 替换

语法:PUT /book/type/id

1
2
3
4
5
6
7
8
9
10
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}

1
2
3
4
5
6
POST /book/_update/1/ 
{
"doc": {
"name": " Bootstrap开发教程高级"
}
}

删除文档

语法:DELETE /index/type/id

1
DELETE /book/_doc/1

document详细

字段解析

  • _index

此文档属于哪个索引

类似数据放在一个索引中。数据库中表的定义规则。各个索引存储和搜索时互不影响

  • _type

类别

以后es9将彻底删除此字段,所以当前版本在不断弱化type。见到_type都为doc。

  • _id

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

手动生成id

1
put /index/_doc/id

自动生成id

1
POST /index/_doc

长度为20个字符,URL安全,base64编码,GUID,分布式生成不冲突

_source 字段

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

定制返回字段

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

文档的替换与删除

全量替换

执行两次,返回结果中版本号version在不断上升。此过程为全量替换

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

1
2
3
4
PUT /test_index/_doc/1
{
"test_field": "test"
}

强制创建

为防止覆盖原有数据,我们在新增时,设置为强制创建,不会覆盖原有文档
PUT /index/ _doc/id/_create

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

删除

DELETE /index/_doc/id

1
DELETE  /test_index/_doc/1/

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

全局替换

全量替换,需要将文档所有数据提交

重新发一份给es
每次修改都将新的数据发给es

1
2
3
4
5
6
post /index/type/id/
{
"doc": {
"field":"value"
}
}

局部替换

局部替换则只修改变动字段

es内部获取旧文档
将传来的文档field更新到旧数据
将旧文档标记为delete
创建的新文档
都是在es内部完成的

1
2
3
4
5
6
post /index/type/id/_update 
{
"doc": {
"field":"value"
}
}
  • 优点

减少网络请求次数

减少网络开销

减少并发冲突

脚本更新

es可以内置脚本执行复杂操作。例如painless脚本

这里不太使用,举个例子

1
2
3
4
5
PUT /test_index/_doc/6
{
"num": 0,
"tags": []
}
1
2
3
4
POST /test_index/_doc/6/_update
{
"script" : "ctx._source.num+=1"
}

es并发问题

就是假如现在有两个下单的线程,下单不得减库存吗,现在有100件库存,线程1要减库存了,100-1=99,但是线程2也要减库存了100-1=99,正常顺序不是线程1,减完然后线程2在减吗,但是这是线程2先到了,就会出现问题

插入数据没有问题,例如日志,但是修改数据会有问题,出现数据不准确的问题,发生并发冲突

悲观锁与乐观锁机制

悲观锁

就是在特殊情况下对数据上锁,只能有一个线程来操作数据,不同场景有不同的锁机制,行级锁、表级锁、读锁、写锁

现在还是以刚才的下单说明,两个线程,使用悲观锁了,这时我们把线程1锁住了,这个时候线程2就卡住了,因为得等待线程1对数据做完操作以后,线程2才能读取到数据

  • 优点

方便,对程序将不需要额外操作

  • 缺点

并发能力弱,相当于单线程了

乐观锁

乐观锁不用锁机制,一般使用版本来进行控制

这样一开始version=1,当一个线程修改数据时,都带着version=1去修改,这个时候就有一个线程修改了,version就会变成version=2了,所以另一个还带着version=1呢,所以他就会重新获取数据,然后进行修改数据,并且重新带着version=2去修改了

  • 优点

并发能力高,不加锁,所以相当于多线程了

  • 缺点

麻烦,每次要对比version,高并发下重复次数较多

es内部基于version乐观锁控制

es内部的主从同步是异步多线程的,所以会出现混乱

举个例子,就好比P0要同步到R0,先修改的线程1带着version1,然后线程2带着version2过来了,我们当然希望按着顺序来了,可是没有控制的话就不一定了

所以es内部使用了version乐观锁控制,es对于文档的增删改都是基于版本号

如果后修改的线程先到了,副本分片先把数据修改咯,然后version+1,然后本应该先修改的线程到了在判断version,这个时候就会判断到你现在这个version过时了,就会自动丢掉这个请求

模拟一下就是你先创建,然后删咯,然后在创建 你看下version,肯定会一直在增

es内部乐观锁

正确的开始 微小的长进 然后持续 嘿 我是小博 带你一起看我目之所及的世界……

-------------本文结束 感谢您的阅读-------------

本文标题:elk 一

文章作者:小博

发布时间:2022年11月04日 - 00:15

最后更新:2022年11月04日 - 00:16

原始链接:https://codexiaobo.github.io/posts/441140627/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。