⑴ Elasticsearch如何保证数据不丢失
[TOC]
数据写入请求达到时,以需要的数据格式组织并写入磁盘的过程叫做数据提交,对应es就是创建倒排索引,维护segment文件
如果我们同步的方式,来处理上述过程,那么系统的吞吐量将很低
如果我们以异步的方式,先写入内存,然后再异步提交到磁盘,则有可能因为机器故障而而丢失还未写入到磁盘中的数据
为了解决这个问题,一般的存储系统都会设计transag log (事务日志)或这write ahead log(预写式日志)。它的作用时,将最近的写入数据或操作以日志的形式直接落盘,从而使得即便系统崩溃后,依然可以基于这些磁盘日志进行数据恢复。
Mysql有redo undo log ,而HBASE、LevelDB,RockDB等采用的LSM tree则提供了write ahead log 这样的设计,来保证数据的不丢失
上述论述中,数据以同步方式落盘会有性能问题,为什么将translog和wal直接落盘不影响性能?原因如下:
es默认是每个请求都会同步落盘translog ,即配置 index.translog.rability 为 request 。当然对于一些可以丢数据的场景,我们可以将 index.translog.rability 配置为 async 来提升写入translog的性能,该配置会异步写入translog到磁盘。具体多长时间写一次磁盘,则通过 index.translog.sync_interval 来控制
前面说了,为了保证translog足够小,所以translog不能无限扩张,需要在一定量后,将其对应的真实业务数据以其最终数据结构(es是倒排索引)提交到磁盘,这个动作称为flush ,它会实际的对底层Lucene 进行一次commit。我们可以通过 index.translog.flush_threshold_size 来配置translog多大时,触发一次flush。每一次flush后,原translog将被删除,重新创建一个新的translog
elasticsearch本身也提供了flush api来触发上述commit动作,但无特殊需求,尽量不要手动触发
对每个shard采用副本机制。保证写入每个shard的数据不丢
前述translog只是保证数据不丢,为了其记录的高效性,其本身并不维护复杂的数据结构。 实际的业务数据的会先写入到in-memory buffer中,当调用refresh后,该buffer中的数据会被清空,转而reopen一个segment,使得其数据对查询可见。但这个segment本身也还是在内存中,如果系统宕机,数据依然会丢失。需要通过translog进行恢复
其实这跟lsm tree非常相似,新写入内存的业务数据存放在内存的MemTable(对应es的in-memory buffer),它对应热数据的写入,当达到一定量并维护好数据结构后,将其转成内存中的ImmutableMemTable(对应es的内存segment),它变得可查询。
https://www.cnblogs.com/niceshot/p/14321372.html
https://ezlippi.com/blog/2018/04/elasticsearch-translog.html
https://stackoverflow.com/questions/19963406/refresh-vs-flush
https://qbox.io/blog/refresh-flush-operations-elasticsearch-guide/
https://www.elastic.co/guide/en/elasticsearch/reference/current/index-moles-translog.html#index-moles-translog-retention
https://www.elastic.co/guide/cn/elasticsearch/guide/current/translog.html
⑵ ES (elasticsearch)集群数据冷热分离实现
导语
这种打标签的操作可以通过滚动,重启集群实例,因为涉及到重启后的数据恢复问题,可能滚动重启的时间会比较长(根据数据量大小和分片数量决定),可以通过如下的方式,增加数据恢复的最大并行度和数据恢复的最大带宽进行调整,逐步调大到不影响集群业务性能为止。
1、ES 集群异构,机器硬件资源配置不一,有高性能 CPU 和 SSD 存储集群,也有大容量的机械磁盘集群,比如我们的场景就是存放冷数据的集群,服务器都是多年前买的一批满配的 4T Dell R70,但是新扩容的热节点机器均为 DELL 高性能 SSD 磁盘和 CPU 的 R740 机器。
2、对于时间型数据来说,一般是当前的数据,写入和查询较为集中,所以高性能的资源应该优先提供给这些数据使用。
3、集群的搜索和写入性能,取决于最慢节点的性能。
1、ES 的索引已经按照天或者月的时间维度生成索引。
2、 历史 数据相对于近期数据来说没有高频度的查询需求。
本文实现策略:最新的天和月索引均为热数据,其他索引根据查询周期不同,调整为冷数据。当然业务不同策略不同,具体实现策略还是需要根据实际的业务场景来决定。
前置条件
需要修改 ES 集群配置文件,对节点进行打标签操作,配置如下:
热数据实例:
冷数据实例:
修改集群配置需要进行重启实例生效
这种打标签的操作可以通过滚动,重启集群实例,因为涉及到重启后的数据恢复问题,可能滚动重启的时间会比较长(根据数据量大小和分片数量决定),可以通过如下的方式,增加数据恢复的最大并行度和数据恢复的最大带宽进行调整,逐步调大到不影响集群业务性能为止。
设置数据恢复的最大并行度
设置数据恢复的最大带宽
新增索引实现冷热数据分离
集群滚动重启完成之后,已经具备了冷热数据分离的条件,那么如何让新增索引自动成为热数据呢?
答案就是修改 ES 索引的模板,为 ES 索引打 tag,配置实例如下:
只要在索引模板中打了热标签的索引,就会在创建的时候自动分布在集群中实例打了热标签的节点上。
历史 索引实现冷热数据迁移
那么 历史 的 ES 数据如何让其从热节点迁移到冷节点呢?
答案就是,通过 api 修改 ES 索引的标签,将其变更为冷标签,这样 ES 索引就会自动迁移到集群中打了冷标签的实例上,配置如下:
实际生产中会将制定好的冷热数据规则编写成脚本,放到计划任务中,来定时定点的运行,达到热数据自动迁移为冷数据的目的。
熟悉 ES 的同学知道,JVM heap 分配不能超过 32GB,对于使用物理机部署 ES 的环境来说,一台机器的内存往往就动辄 192G 或者 256G,如果只跑一个 ES 实例,只能利用到 32G 的 heap,而且还无法充分发挥 CPU 和 IO 资源,这样显然是不经济的。
因为我们常常会部署单机多实例的 ES 节点,在多实例配置中除了要隔离日志和数据目录之外,还需要增加以下两个配置,不然一台物理机宕机,可能会因为多个副本存在一个 ES 物理机上面导致业务受到影响。
# 执行检查以防止基于主机名和主机地址在单个主机上分配同一分片的多个实例。 默认为 false,表示默认情况下不执行检查。 此设置仅适用于在同一台计算机上启动多个节点的情况。这个我的理解是如果设置为 false,则同一个节点上多个实例可以存储同一个 shard 的多个副本没有容灾作用了。
⑶ es可以一天存百万条数据么
es不可以一天存百万条数据。es一天最大的存储量是90万条数据,所以es不可以一天存百万条数据。es全称ElasticSearch,是一个基于Lucene的搜索服务器。
⑷ ES中的索引生命周期管理
ILM :索引生命周期管理,即 Manage the index lifecycle 。
索引的生命周期有四个阶段:
索引的生命周期策略指定了适用于哪些阶段、在每个阶段中执行哪些操作以及何时在各个阶段之间进行转换。
当索引满足一定条件之后,将不再写入数据,而是自动创建一个索引,所有的数据将写入新的索引。
使用滚动索引能够:
官方推荐使用 data stream 数据流来管理时间序列数据。每个数据流都需要一个 索引模板 ,其中包括:
数据流专为追加数据而设计,其中数据流名称可用作操作(读取、写入、翻转、收缩等)目标。如果需要更新数据,可以使用 索引别名 来管理时间序列数据。
ILM 会根据你的配置: 索引大小 、 文档数量 、 所在阶段 ,当满足这些条件时,自动实现 rollover 。
要让 ILM 管理索引,必须要在 index.lifecycle.name 索引设置中指定有效的策略。
要为滚动索引创建生命周期策略,你要创建该策略并把它加入到 索引模板 中。
可以通过 Kibana 管理页面设置,也可以通过API设置。
可以通过 Kibana 管理页面设置,也可以通过API设置。
如果要给滚动索引设置策略,需要手动创建第一个被该策略管理的索引,并指定为可写索引。
索引的名称必须跟索引模板里定义的模式相匹配,并且以数字结尾。
你可以在创建索引的时候指定一个策略,也可以直接将策略应用到一个已经存在的索引上通过 Kibana 管理或者更新设置的API。一旦你应用了策略, ILM 立即会开始管理该索引。
查看错误:
重新运行报错的一步:
查看 ILM 状态:
终止 ILM :
开启 ILM :
设置 index.lifecycle.indexing_complete 为 true 。
举个例子,如果你要改变一系列新索引的名称,并保留之前根据你配置的策略产生的索引数据,你可以:
相关连接: https://www.elastic.co/guide/en/elasticsearch/reference/7.9/index-lifecycle-management.html
获取最新文章,可关注博客地址: https://jenkinwang.github.io/
⑸ ES聚合分析一网打尽(二) 数据统计相关操作
Cardinality Aggregation
类似于mysql的distinct,不过精度达不到100%
计算总共有多少个制造商
控制数据的准确度
计算制造商和类别的所有搭配的个数
返回结果
如上所见,manufacturer类别为21,category类别为6,但是组合类别为64,验证了制造商并不是做所有的类别的商品。
missing value
可以对不存在该field的值做统计,将所有不存在的作为一个单独的处理
Extended Stats Aggregation
扩展统计结果,增加了平方和、方差、标准差、标准差区间(std_deviation_bounds)
通过sigma控制std_deviation_bounds返回几个标准差间隔,默认为2,可以通过具体值为[avg+std_deviation*sigma,avg-std_deviation*sigma]
script、value script、missing与avg基本相同,简单示例如下
script:
value script:
missing:
⑹ es加节点会平衡数据吗
es加节点会平衡数据。一个集群cluster由一个或者多个节点组成,具有相同的cluster.name,协同工作,分项数据和负载。当有新的节点加入或者删除了一个节点时,集群回感知到并能够平衡数据。es集群会自动做负载均衡,如果我们现在加一个es节点到集群中来的话,es会按照一定的规则将部分shard分配到新的节点上去。
es主节点作用
主节点的主要职责是负责集群层面的相关操作,管理集群变更,如创建或删除索引,跟踪哪些节点是群集的一部分,并决定哪些分片分配给相关的节点。主节点也可以作为数据节点,但稳定的主节点对集群的健康是非常重要的,默认情况下任何一个集群中的节点都有可能被选为主节点。
⑺ ES笔记—基础之数据类型篇
描述:检测给定变量的数据类型,结果如下:
描述:只有一个值,即特殊的 undefined,表示变量未初始化。
包含 undefined 值的变量与尚未定义的变量还是不一样的
令人困惑的是:对未初始化的变量执行 typeof 操作符会返回 undefined 值,而对未声明的变量执行 typeof 操作符同样也会返回 undefined 值。
描述:只有一个值,即特殊的值是 null。
从逻辑角度来看, null 值表示一个空对象指针,而这也正是使用 typeof 操作符检测 null 值时会返回"object"的原因。
定义的变量准备在将来用于保存对象,那么最好将该变量初始化为 null 而不是其他值。
实际上, undefined 值是派生自 null 值的,因此 ECMA-262 规定对它们的相等性测试要返回 true:
描述:该类型只有两个字面值: true 和 false。
Boolean()函数,接受一个参数,将该值转换成布尔值。事实上,很多情况都会隐式的调用该函数,比如判断语句、循环语句、以及比较运算等等。
下表给出了各种数据类型及其对应的转换规则。
描述:使用 IEEE754 格式来表示整数和浮点数值。 支持二进制(010101)、十进制(100)、十六进制(0XFFAA)
浮点数值,就是该数值中必须包含一个小数点,并且小数点后面必须至少有一位数字。
对于那些极大或极小的数值,可以用 e 表示法(即科学计数法)表示的浮点数值表示。
浮点数值的最高精度是 17 位小数,但在进行算术计算时其精确度远远不如整数。
isFinite(num)函数,接受一个数值作为参数,若该值在最小值与最大值之间,则返回布尔值true。
NaN(非数值),一个特殊数值,自身也不相等,用于表示一个本来要返回数值的操作数未返回数值的情况。
isNaN(param)函数,接受一个参数,该参数可以是任何数据类型,而函数会帮我们确定这个参数是否“不是数值”(会执行类型转换),任何不能被转换为数值的值都会返回布尔值true。
Number(param)函数,接受一个参数,将其转为Number类型,规则如下:
parseInt(param1, param2)函数,接受两个参数,第一个是转为整数的值,第一个是基数类型(十进制、十六进制、二进制等等)。
parseFloat(param1, param2)函数,同上,区别是遇到第一个(.)会解析成小数点。
描述:用于表示由零或多个 16 位 Unicode 字符组成的字符序列,即字符串。
字符串可以由双引号(")或单引号(')表示,因此下面两种字符串的写法都是有效的:
String 数据类型包含一些特殊的字符字面量,也叫转义序列,用于表示非打印字符,或者具有其
他用途的字符。
ECMAScript 中的字符串是不可变的,也就是说,字符串一旦创建,它们的值就不能改变。要改变某个变量保存的字符串,首先要销毁原来的字符串,然后再用另一个包含新值的字符串填充该变量。
把一个值转换为一个字符串有两种方式。第一种是使用几乎每个值都有的 toString()方法。
通过传递基数, toString()可以输出以二进制、八进制、十六进制,乃至其他任意有效进制格式表示的字符串值。
转型函数 String(),这个函数能够将任何类型的值转换为字符串。 String()函数遵循下列转换规则:
描述:对象其实就是一组数据和功能的集合。对象可以通过执行 new 操作符后跟要创建的对象类型的名称来创建。而创建 Object 类型的实例并为其添加属性和(或)方法,就可以创建自定义对象。
Object 类型是所有它的实例的基础,Object 类型所具有的任何属性和方法也同样存在于更具体的对象中。
⑻ excel如何把一年的数据,以连续7天为周期,可以迅速取出每个周期的数据
打开excel,选中需要按周汇总的数据。如图中数据需要按周汇总,表中选取周一到周日,需要统计各人每周的工作量。
excel如何按周统计汇总数据(任意周期/步长)
在插入选项卡中 选插入数据透视表,选中待分析待数据(这里选中表中3列)。
excel如何按周统计汇总数据(任意周期/步长)
3
设计数据透视表,在行中选择日期(默认会出现按月汇总,需要删掉)。
⑼ ES数据副本模型
ES里面的每一个索引(Index)由多个shard组成,每一个shard有多个副本。这些副本被称为"同步组"。当增加或者删除文档时,这些副本之间必须保持同步,以便让所有副本都能包含相同的文档。如果同步失败,有可能会导致从一个副本读的结果和从另外一个副本上读的结果不一致。在shard的所有副本之间保持数据同步并同时对外提供一致的读服务,我们这样的处理过程称之为“数据复制模型"。
ES的“数据复制模型”是一种“主-备”式的模型,这种模型在微软的研究论文中有专门的介绍。基于这种模型,“同步组" 的所有副本中间会有一个专门的“Primary shard”角色,除了”Primary shard“之外的其余副本都被称为”replica shard“。 Primary shard是所有文档的索引操作(文档写操作)的入口点, 其负责索引操作的校验,确保这些索引操作是正确且合法的。当索引操作校验通过后, primary shard会负责把索引操作复制并传递给replica shard,让“同步组”里面所有副本会进行相同的写操作,进而保持所有副本上包含的文档是一致的。
根据文档的doc ID,ES首先会识别出来一个文档的索引操作应该由哪个“同步组”来执行,这个“同步组”也就是存储该文档的目的容器。在“同步组"被识别出来后,该文档的索引操作就被传递给“同步组”中的当前primary shard。Primary shard 负责校验并传递同样的文档索引操作给其他的relica shard。因为replica shard有可能会因为各种可能原因造成离线,所以ES并不要求primary shard一定要复制操作给所有的replica shard。事实上,primary shard维护了一个可以接收索引操作的replica shard列表。这个列表被称为“in-sync 副本列表”, 列表数据由master node来维护。 primary shard需要把文档的索引操作复制传递给in-sync列表中每一个relica shard。
下面是primary shard处理的基本流程:
1.校验操作请求,如果有结构类的错误(例如,object filed 却存储了一个数字),就拒绝此请求
2.如果校验通过,本地先执行索引操作,例如索引或者删除文档。在本地操作过程中,也会做一些校验,如果校验失败(例如keyword字段的值太长,超过Lucene索引长度限制),也会拒绝请求。
3.转发索引操作给当前in-sync里面的所有replica shard。如果有多个replica shard,转发操作会并行来执行
4.当所有replica 都成功执行了和本地一样的索引操作,并且给primary shard 发回了成功确认,primary shard 就会发成功确认给客户端。
在执行索引操作的过程中,每一步都可能会出现问题,比如磁盘坏了、node down掉了、node之间网络不通了、或者配置错误了等等,也许会导致索引操作在primary shard执行成功,在一个或者多个replica shard 却执行失败了。这些都是失败的情况,虽然并不是经常出现,但是primary shard必须处理各种异常的情况。
一种场景是primary shard自己出问题了,在这种情况下 ,primary shard 所在的node会发消息给master node告知这种异常情况出现了 。索引操作会等待master node选出新的primary shard并把索引操作转发给新的primary shard。当然这种等待不是无限期的,缺省会等待1分钟。当然master node也不是被动等待通知,master node会主动持续监测node的健康状态,并根据健康状态来决定是否选出新的primary shard。一种典型的情况就是当primary shard所在node 网络不通的时候,master node会认为 primary shard所在node可能down死掉了,就会选出新的primary shard,并更新in-sync 列表。
另外一种场景就是索引操作在primary shard上执行成功,但是在replica shard执行却失败了。当然被定义失败的各种情况有很多,比如索引操作在replica上的确失败了(比如replica shard所在硬盘出问题了)、primary shard和replica shard之间网络原因导致索引操作请求没有到达replica shard、或者primary shard没有收到replica shard的成功确认等等。这些复杂的情况导致的共同结果就是:primary shard 没有收到in-sync列表里面的所有replica shard的索引操作成功确认。为了解决这样的问题,primary shard 会发消息给master node ,请求master node 删除出问题的replica shard。当primary shard 收到master node 成功删除问题replica shard的确认消息时,primary shard会发索引操作成功确认给客户端。要注意的是,master node同时会通知另外一个node会构建一个新的replica shard,以保证系统处在一个健康状态。
当转发操作请求给replica shards的时候,primary shard会根据replica shard的响应情况来确认自己仍然是活跃的primary shard。某些情况下,因为网络原因,primary shard 也许已经被master node给降级了,但是primary shard还没收到这种降级通知,所以会继续处理进来的索引操作请求。当老的primary shard把索引操作请求转发给其他replica shard时,replica shard发现请求来自于一个已经不合法的primary shard,就会拒绝请求并发响应给这个不合法的primary shard。当这个不合法的primary shard收到拒绝的响应时候,就会和master node联系,获取最新的状态信息。在从master node发回的信息中,老的primary shard发现自己已经被“推翻统治”,就会把索引操作请求转发给新的primary shard。
因为各种原因,所有的replica shards可能都会失效。在这种情况下,primary 会自己处理索引操作,而不会等待任何外部的确认(因为没有replica shards了)。看起来似乎有点怪怪的,这主要是因为primary shards不能自己定义而只能依赖master nodereplica shards是否失败。这就意味着,master node知道primary shards 是唯一的正常工作的副本。我们要保证master node不会把其他任何过期的shard 副本定义成新的primary,也保证发到primary shard的索引操作请求不会丢失。但是不可否认,primary shard上的物理硬件出问题了,肯定也会导致数据丢失。
ES中的读可以是通过ID的轻量级查找,也可以是重量级的非常消耗CPU的复杂聚合计算。ES的“主-备”模型的优雅之处在于它保持所有副本的数据一致的,这样“同步组”中的任何单个副本都可以对外提供读服务。
当集群中的一个node收到读请求时,该node负责转发读请求给相关的shards、聚合shards的响应并把响应发送给客户端。我们这样的node称之为本次请求的协调node。协调node上的基本读的处理流程如下:
1.根据请求,解析出来要转发的“同步组”。多数搜索需要查询多个“同步组",每个"同步组”是可能包含了搜索结果的一部分数据。但是如果是根据id检索一个文档,可以根据routing算法,计算出一个包含该文档的“同步组”。
2.从每一个要转发“同步组”里面选出一个活跃的shard。这个shard可以是primary,也可以是replica。缺省情况下,ES使用round robin的策略在“同步组"里面选择shard。把请求转发给选出来的shards
3.合并各个shard的响应并发响应给客户端。要注意的是,如果根据id检索文档,因为转发shard是一个,所以就不存在合并的过程了。
当一个shard没有成功执行读请求、转发响应给协调node时,协调node会从该shard所在的”同步组“中选择另外一个shard,然后把读请求转发给它。重复性的“失败-选择”可能会导致最后“同步组"里面没有shard 可用。在某些情况下,ES更青睐快速响应,而不是搜索结果的完整性,例如_search。即使缺失了部分查询结果,ES也希望能快速响应给客户端,而不是等待问题解决(搜索结果是否完整会在响应头有体现)。
基本读、基本写流程定义了ES作为一个系统,是如何支持读和写操作的。但是实践中,读写操作可能是同时并发执行的,所以读、写流程是相互影响的。此模型有一些优雅的点,如下:
1.高效读
正常情况下,每次读请求操作只会被“同步组”里面shard执行一次。在异常情况下,有可能会出现“同步组”里面的多个shard执行了多次读操作,例如协调node在shard没有响应的情况下,会重新选择另外一个shard,再次发出读请求操作。
2.未确认读
因为primary shard首先在本地执行索引操作,然后才转发索引操作给replica shard。在索引操作完全确认之前,primary shard执行了一个读请求操作,就能读到还没确认的数据。
3.缺省两个副本
在一些基于投票的系统中,要实现容错,有可能最少需要的副本数是3. 但是基于ES的模型,仅维护两个副本,就可以实现容错。
失败的时候,可能会出现下面的情况:
1.单个shard有可能会让索引操作执行的更慢
因为primary shard需要等待in-sync里面所有replica shard执行完并响应才能发确认给客户端,所以任何一个处理慢的shard都会拉低本次索引操作的处理速度。这是为了实现前面提到的高效读而付出的成本代价。当然,单个慢的shard也会拉低路由到此shard上的读请求操作处理速度,进而影响那次search(因为search是由多个shard的读请求组成)。
2.脏读
一个孤立的primary shard可能会暴露将不会被确认的但是已经被写到本地的数据。这是因为孤立的primary只有在发索引操作请求给replica或者跟master node时才能知道自己已经被孤立了。因为数据已经被写入本地了,如果此时有读请求过来,读请求就可能会读到刚刚已经写进去的数据。为了降低这种风险,primary 会定期(缺省每1秒)ping master node,如果发现已经找不到master了,就会拒绝索引操作。