首页 文章 精选 留言 我的

精选列表

搜索[搜索引擎平台],共10006篇文章
优秀的个人博客,低调大师

分布式搜索引擎Elasticsearch的架构分析

一、写在前面 ES(Elasticsearch下文统一称为ES)越来越多的企业在业务场景是使用ES存储自己的非结构化数据,例如电商业务实现商品站内搜索,数据指标分析,日志分析等,ES作为传统关系型数据库的补充,提供了关系型数据库不具备的一些能力。 ES最先进入大众视野的是其能够实现全文搜索的能力,也是由于基于Lucene的实现,内部有一种倒排索引的数据结构。 本文作者将介绍ES的分布式架构,以及ES的存储索引机制,本文不会详细介绍ES的API,会从整体架构层面进行分析,后续作者会有其他文章对ES的使用进行介绍。 二、什么是倒排索引 要讲明白什么是倒排索引,首先我们先梳理下什么索引,比如一本书,书的目录页,有章节,章节名称,我们想看哪个章节,我们通过目录页,查到对应章节和页码,就能定位到具体的章节内容,通过目录页的章节名称查到章节的页码,进而看到章节内容,这个过程就是一个索引的过程,那么什么是倒排索引呢? 比如查询《java编程思想》这本书的文章,翻开书本可以看到目录页,记录这个章节名字和章节地址页码,通过查询章节名字“继承”可以定位到“继承”这篇章节的具体地址,查看到文章的内容,我们可以看到文章内容中包含很多“对象”这个词。 那么如果我们要在这本书中查询所有包含有“对象”这个词的文章,那该怎么办呢? 按照现在的索引方式无疑大海捞针,假设我们有一个“对象”--→文章的映射关系,不就可以了吗?类似这样的反向建立映射关系的就叫倒排索引。 如图1所示,将文章进行分词后得到关键词,在根据关键词建立倒排索引,关键词构建成一个词典,词典中存放着一个个词条(关键词),每个关键词都有一个列表与其对应,这个列表就是倒排表,存放的是章节文档编号和词频等信息,倒排列表中的每个元素就是一个倒排项,最后可以看到,整个倒排索引就像一本新华字典,所有单词的倒排列表往往顺序地存储在磁盘的某个文件里,这个文件被称之为倒排文件。 (图1) 词典和倒排文件是Lucene的两种基本数据结构,但是存储方式不同,词典在内存中存储,倒排文件在磁盘上。本文不会去介绍分词,tf-idf,BM25,向量空间相似度等构建倒排索引和查询倒排索引所用到的技术,读者只需要对倒排索引有个基本的认识即可。 三、ES的集群架构 1.集群节点 一个ES集群可以有多个节点构成,一个节点就是一个ES服务实例,通过配置集群名称cluster.name加入集群。那么节点是如何通过配置相同的集群名称加入集群的呢?要搞明白这个问题,我们必须先搞清楚ES集群中节点的角色。 ES中节点有角色的区分的,通过配置文件conf/elasticsearch.yml中配置以下配置进行角色的设定。 node.master: true/false node.data: true/false 集群中单个节点既可以是候选主节点也可以是数据节点,通过上面的配置可以进行两两组合形成四大分类: (1)仅为候选主节点 (2)既是候选主节点也是数据节点 (3)仅为数据节点 (4)既不是候选主节点也不是数据节点 候选主节点:只有是候选主节点才可以参与选举投票,也只有候选主节点可以被选举为主节点。 主节点:负责索引的添加、删除,跟踪哪些节点是群集的一部分,对分片进行分配、收集集群中各节点的状态等,稳定的主节点对集群的健康是非常重要。 数据节点:负责对数据的增、删、改、查、聚合等操作,数据的查询和存储都是由数据节点负责,对机器的CPU,IO以及内存的要求比较高,一般选择高配置的机器作为数据节点。 此外还有一种节点角色叫做协调节点,其本身不是通过设置来分配的,用户的请求可以随机发往任何一个节点,并由该节点负责分发请求、收集结果等操作,而不需要主节点转发。这种节点可称之为协调节点,集群中的任何节点都可以充当协调节点的角色。每个节点之间都会保持联系。 (图2) 2.发现机制 前文说到通过设置一个集群名称,节点就可以加入集群,那么ES是如何做到这一点的呢? 这里就要讲一讲ES特殊的发现机制ZenDiscovery。 ZenDiscovery是ES的内置发现机制,提供单播和多播两种发现方式,主要职责是集群中节点的发现以及选举Master节点。 多播也叫组播,指一个节点可以向多台机器发送请求。生产环境中ES不建议使用这种方式,对于一个大规模的集群,组播会产生大量不必要的通信。 单播,当一个节点加入一个现有集群,或者组建一个新的集群时,请求发送到一台机器。当一个节点联系到单播列表中的成员时,它就会得到整个集群所有节点的状态,然后它会联系Master节点,并加入集群。 只有在同一台机器上运行的节点才会自动组成集群。ES 默认被配置为使用单播发现,单播列表不需要包含集群中的所有节点,它只是需要足够的节点,当一个新节点联系上其中一个并且通信就可以了。如果你使用 Master 候选节点作为单播列表,你只要列出三个就可以了。 这个配置在 elasticsearch.yml 文件中: discovery.zen.ping.unicast.hosts: ["host1", "host2:port"] 集群信息收集阶段采用了 Gossip 协议,上面配置的就相当于一个seed nodes,Gossip协议这里就不多做赘述了。 ES官方建议unicast.hosts配置为所有的候选主节点,ZenDiscovery 会每隔ping_interval(配置项)ping一次,每次超时时间是discovery.zen.ping_timeout(配置项),3次(ping_retries配置项)ping失败则认为节点宕机,宕机的情况下会触发failover,会进行分片重分配、复制等操作。 如果宕机的节点不是Master,则Master会更新集群的元信息,Master节点将最新的集群元信息发布出去,给其他节点,其他节点回复Ack,Master节点收到discovery.zen.minimum_master_nodes的值-1个 候选主节点的回复,则发送Apply消息给其他节点,集群状态更新完毕。如果宕机的节点是Master,则其他的候选主节点开始Master节点的选举流程。 2.1 选主 Master的选主过程中要确保只有一个master,ES通过一个参数quorum的代表多数派阈值,保证选举出的master被至少quorum个的候选主节点认可,以此来保证只有一个master。 选主的发起由候选主节点发起,当前候选主节点发现自己不是master节点,并且通过ping其他节点发现无法联系到主节点,并且包括自己在内已经有超过minimum_master_nodes个节点无法联系到主节点,那么这个时候则发起选主。 选主流程图 (图3) 选主的时候按照集群节点的参数<stateVersion, id> 排序。stateVersion从大到小排序,以便选出集群元信息较新的节点作为Master,id从小到大排序,避免在stateVersion相同时发生分票无法选出 Master。 排序后第一个节点即为Master节点。当一个候选主节点发起一次选举时,它会按照上述排序策略选出一个它认为的Master。 2.2 脑裂 提到分布式系统选主,不可避免的会提到脑裂这样一个现象,什么是脑裂呢?如果集群中选举出多个Master节点,使得数据更新时出现不一致,这种现象称之为脑裂。 简而言之集群中不同的节点对于 Master的选择出现了分歧,出现了多个Master竞争。 一般而言脑裂问题可能有以下几个原因造成: 网络问题:集群间的网络延迟导致一些节点访问不到Master,认为Master 挂掉了,而master其实并没有宕机,而选举出了新的Master,并对Master上的分片和副本标红,分配新的主分片。 节点负载:主节点的角色既为Master又为Data,访问量较大时可能会导致 ES 停止响应(假死状态)造成大面积延迟,此时其他节点得不到主节点的响应认为主节点挂掉了,会重新选取主节点。 内存回收:主节点的角色既为Master又为Data,当Data节点上的ES进程占用的内存较大,引发JVM的大规模内存回收,造成ES进程失去响应。 如何避免脑裂:我们可以基于上述原因,做出优化措施: 适当调大响应超时时间,减少误判。通过参数 discovery.zen.ping_timeout 设置节点ping超时时间,默认为 3s,可以适当调大。 选举触发,我们需要在候选节点的配置文件中设置参数 discovery.zen.munimum_master_nodes 的值。这个参数表示在选举主节点时需要参与选举的候选主节点的节点数,默认值是 1,官方建议取值(master_eligibel_nodes/2)+1,其中 master_eligibel_nodes 为候选主节点的个数。这样做既能防止脑裂现象的发生,也能最大限度地提升集群的高可用性,因为只要不少于 discovery.zen.munimum_master_nodes 个候选节点存活,选举工作就能正常进行。当小于这个值的时候,无法触发选举行为,集群无法使用,不会造成分片混乱的情况。 角色分离,即是上面我们提到的候选主节点和数据节点进行角色分离,这样可以减轻主节点的负担,防止主节点的假死状态发生,减少对主节点宕机的误判。 四、索引如何写入的 1. 写索引原理 1.1 分片 ES支持PB级全文搜索,通常我们数据量很大的时候,查询性能都会越来越慢,我们能想到的一个方式的将数据分散到不同的地方存储,ES也是如此,ES通过水平拆分的方式将一个索引上的数据拆分出来分配到不同的数据块上,拆分出来的数据库块称之为一个分片Shard,很像MySQL的分库分表。 不同的主分片分布在不同的节点上,那么在多分片的索引中数据应该被写入哪里?肯定不能随机写,否则查询的时候就无法快速检索到对应的数据了,这需要有一个路由策略来确定具体写入哪一个分片中,怎么路由我们下文会介绍。在创建索引的时候需要指定分片的数量,并且分片的数量一旦确定就不能修改。 1.2 副本 副本就是对分片的复制,每个主分片都有一个或多个副本分片,当主分片异常时,副本可以提供数据的查询等操作。主分片和对应的副本分片是不会在同一个节点上的,避免数据的丢失,当一个节点宕机的时候,还可以通过副本查询到数据,副本分片数的最大值是 N-1(其中 N 为节点数)。 对doc的新建、索引和删除请求都是写操作,这些写操作是必须在主分片上完成,然后才能被复制到对应的副本上。ES为了提高写入的能力这个过程是并发写的,同时为了解决并发写的过程中数据冲突的问题,ES通过乐观锁的方式控制,每个文档都有一个 _version号,当文档被修改时版本号递增。 一旦所有的副本分片都报告写成功才会向协调节点报告成功,协调节点向客户端报告成功。 (图4) 1.3 Elasticsearch 的写索引流程 上面提到了写索引是只能写在主分片上,然后同步到副本分片,那么如图4所示,这里有四个主分片分别是S0、S1、S2、S3,一条数据是根据什么策略写到指定的分片上呢?这条索引数据为什么被写到S0上而不写到 S1 或 S2 上?这个过程是根据下面这个公式决定的。 shard = hash(routing) % number_of_primary_shards 以上公式的值是在0到number_of_primary_shards-1之间的余数,也就是数据档所在分片的位置。routing通过Hash函数生成一个数字,然后这个数字再除以number_of_primary_shards(主分片的数量)后得到余数。routing是一个可变值,默认是文档的_id ,也可以设置成一个自定义的值。 在一个写请求被发送到某个节点后,该节点按照前文所述,会充当协调节点,会根据路由公式计算出写哪个分片,当前节点有所有其他节点的分片信息,如果发现对应的分片是在其他节点上,再将请求转发到该分片的主分片节点上。 在ES集群中每个节点都通过上面的公式知道数据的在集群中的存放位置,所以每个节点都有接收读写请求的能力。 那么为什么在创建索引的时候就确定好主分片的数量,并且不可修改?因为如果数量变化了,那么所有之前路由计算的值都会无效,数据也就再也找不到了。 (图5) 如上图5所示,当前一个数据通过路由计算公式得到的值是 shard=hash(routing)%4=0,则具体流程如下: (1)数据写请求发送到 node1 节点,通过路由计算得到值为1,那么对应的数据会应该在主分片S1上。 (2)node1节点将请求转发到 S1 主分片所在的节点node2,node2 接受请求并写入到磁盘。 (3)并发将数据复制到三个副本分片R1上,其中通过乐观并发控制数据的冲突。一旦所有的副本分片都报告成功,则节点 node2将向node1节点报告成功,然后node1节点向客户端报告成功。 这种模式下,只要有副本在,写入延时最小也是两次单分片的写入耗时总和,效率会较低,但是这样的好处也很明显,避免写入后单个机器硬件故障导致数据丢失,在数据完整性和性能方面,一般都是优先选择数据,除非一些允许丢数据的特殊场景。 在ES里为了减少磁盘IO保证读写性能,一般是每隔一段时间(比如30分钟)才会把数据写入磁盘持久化,对于写入内存,但还未flush到磁盘的数据,如果发生机器宕机或者掉电,那么内存中的数据也会丢失,这时候如何保证? 对于这种问题,ES借鉴数据库中的处理方式,增加CommitLog模块,在ES中叫transLog,在下面的ES存储原理中会介绍。 2. 存储原理 上面介绍了在ES内部的写索引处理流程,数据在写入到分片和副本上后,目前数据在内存中,要确保数据在断电后不丢失,还需要持久化到磁盘上。 我们知道ES是基于Lucene实现的,内部是通过Lucene完成的索引的创建写入和搜索查询,Lucene 工作原理如下图所示,当新添加一片文档时,Lucene进行分词等预处理,然后将文档索引写入内存中,并将本次操作写入事务日志(transLog),transLog类似于mysql的binlog,用于宕机后内存数据的恢复,保存未持久化数据的操作日志。 默认情况下,Lucene每隔1s(refresh_interval配置项)将内存中的数据刷新到文件系统缓存中,称为一个segment(段)。一旦刷入文件系统缓存,segment才可以被用于检索,在这之前是无法被检索的。 因此refresh_interval决定了ES数据的实时性,因此说ES是一个准实时的系统。segment 在磁盘中是不可修改的,因此避免了磁盘的随机写,所有的随机写都在内存中进行。随着时间的推移,segment越来越多,默认情况下,Lucene每隔30min或segment 空间大于512M,将缓存中的segment持久化落盘,称为一个commit point,此时删掉对应的transLog。 当我们在进行写操作的测试的时候,可以通过手动刷新来保障数据能够被及时检索到,但是不要在生产环境下每次索引一个文档都去手动刷新,刷新操作会有一定的性能开销。一般业务场景中并不都需要每秒刷新。 可以通过在 Settings 中调大 refresh_interval = "30s" 的值,来降低每个索引的刷新频率,设值时需要注意后面带上时间单位,否则默认是毫秒。当 refresh_interval=-1 时表示关闭索引的自动刷新。 (图6) 索引文件分段存储并且不可修改,那么新增、更新和删除如何处理呢? 新增,新增很好处理,由于数据是新的,所以只需要对当前文档新增一个段就可以了。 删除,由于不可修改,所以对于删除操作,不会把文档从旧的段中移除而是通过新增一个 .del 文件,文件中会列出这些被删除文档的段信息,这个被标记删除的文档仍然可以被查询匹配到, 但它会在最终结果被返回前从结果集中移除。 更新,不能修改旧的段来进行文档的更新,其实更新相当于是删除和新增这两个动作组成。会将旧的文档在 .del 文件中标记删除,然后文档的新版本中被索引到一个新的段。可能两个版本的文档都会被一个查询匹配到,但被删除的那个旧版本文档在结果集返回前就会被移除。 segment被设定为不可修改具有一定的优势也有一定的缺点。 优点: 不需要锁。如果你从来不更新索引,你就不需要担心多进程同时修改数据的问题。 一旦索引被读入内核的文件系统缓存,便会留在哪里,由于其不变性。只要文件系统缓存中还有足够的空间,那么大部分读请求会直接请求内存,而不会命中磁盘。这提供了很大的性能提升. 其它缓存(像 Filter 缓存),在索引的生命周期内始终有效。它们不需要在每次数据改变时被重建,因为数据不会变化。 写入单个大的倒排索引允许数据被压缩,减少磁盘 I/O 和需要被缓存到内存的索引的使用量。 缺点: 当对旧数据进行删除时,旧数据不会马上被删除,而是在 .del 文件中被标记为删除。而旧数据只能等到段更新时才能被移除,这样会造成大量的空间浪费。 若有一条数据频繁的更新,每次更新都是新增新的,标记旧的,则会有大量的空间浪费。 每次新增数据时都需要新增一个段来存储数据。当段的数量太多时,对服务器的资源例如文件句柄的消耗会非常大。 在查询的结果中包含所有的结果集,需要排除被标记删除的旧数据,这增加了查询的负担。 2.1 段合并 由于每当刷新一次就会新建一个segment(段),这样会导致短时间内的段数量暴增,而segment数目太多会带来较大的麻烦。大量的segment会影响数据的读性能。每一个segment都会消耗文件句柄、内存和CPU 运行周期。 更重要的是,每个搜索请求都必须轮流检查每个segment然后合并查询结果,所以segment越多,搜索也就越慢。 因此Lucene会按照一定的策略将segment合并,合并的时候会将那些旧的已删除文档从文件系统中清除。被删除的文档不会被拷贝到新的大segment中。 合并的过程中不会中断索引和搜索,倒排索引的数据结构使得文件的合并是比较容易的。 段合并在进行索引和搜索时会自动进行,合并进程选择一小部分大小相似的段,并且在后台将它们合并到更大的段中,这些段既可以是未提交的也可以是已提交的。 合并结束后老的段会被删除,新的段被刷新到磁盘,同时写入一个包含新段且排除旧的和较小的段的新提交点,新的段被打开,可以用来搜索。段合并的计算量庞大,而且还要吃掉大量磁盘 I/O,并且段合并会拖累写入速率,如果任其发展会影响搜索性能。 ES在默认情况下会对合并流程进行资源限制,所以搜索性能可以得到保证。 (图7) 五、写在最后 作者对ES的架构原理和索引存储和写机制进行介绍,ES的整体架构体系相对比较巧妙,我们在进行系统设计的时候可以借鉴其设计思路,本文只介绍ES整体架构部分,更多的内容,后续作者会在其他文章中继续分享。 作者:vivo官网商城开发团队

优秀的个人博客,低调大师

向量搜索引擎 Milvus 发布新版本 0.7.0

版本兼容 新增功能 向量删除 新增了对单条或多条向量的删除功能。如果您对一个集合进行了向量删除操作,后续对这个集合的搜索操作仅支持一部分索引类型,包括在CPU上运行的 Flat、IVFlat、IVFSQ8 等。Milvus 的后续版本将为其他索引类型提供支持。#86 向量读取 新增了通过向量 ID 读取对应的向量值的功能。#861 数据落盘与压缩 新增了数据落盘与压缩功能。您可以设置定时落盘或者手动落盘,从而避免数据丢失。如果一个段中的向量数据被删除,被删除的向量数据占据的空间并不会自动释放。您可以对集合中的段进行压缩操作以释放多余空间。#861#1426 运行时更改 Milvus 服务端参数 新增了运行时更改 Milvus 服务端参数的功能。您可以通过 Milvus 客户端对 Milvus 服务端参数进行更改,部分参数更改后可即时生效,无需重启 Milvus。#665 预写式日志(Write-Ahead Logging, WAL) 新增了 WAL 功能,可以大大提高数据操作的可靠性。您可以在 Milvus 服务端配置文件(server_config.yaml)中对 WAL 进行设置。#830 RESTful API 新增了 RESTful API。详细信息请参考RESTful API Readme。 Go SDK 新增了 Go SDK,详细信息请参考https://github.com/milvus-io/milvus-sdk-go。 HNSW 索引的支持 新增了对 HNSW 索引类型的支持。关于 HNSW 的详细介绍请参考向量索引算法 HNSW 和 NSG 的比较。#853 Jaccard/Hamming/Tanimoto 距离的支持 新增了对 Jaccard、Hamming、Tanimoto 距离的支持。#823 Prometheus 中 Pushgateway 的支持 新增了在 Prometheus 中 Pushgateway 的支持。Pushgateway 使生命周期短、批量的 metric 能够被 Prometheus 提取。#813 AVX 512 指令集的支持 新增了对 AVX 512 指令集的支持。Milvus 理论上可支持所有包含 AVX 512 指令集的 CPU。#1122 变更说明 创建索引与搜索的接口更新 从 Milvus 0.7.0开始,所有客户端创建索引与搜索的接口中的部分参数使用 JSON 字符串进行传值。 Milvus 服务端配置文件更新 从 Milvus 0.7.0开始,Milvus 服务端配置文件(server_config.yaml)版本更新为0.2。配置文件的参数也发生了变化。 术语更新 从0.7.0开始,Milvus 的 Table(表) 正式改名为 Collection(集合)。 Bug 修复 解决了插入向量时使用自动生成的ID 时可能产生重复ID的问题。#1508 对新版本有问题吗?下周二(3.17.2020)晚上八点的线上问答将进行 v.0.7.0 相关专题, 有任何问题或是建议都可以来与我们聊聊!

优秀的个人博客,低调大师

【Elasticsearch全文搜索引擎实战】之Filebeat快速入门

0. 背景 用过ELK(Elasticsearch, Logstash, Kibana)的人应该都面临过同样的问题,Logstash虽然功能强大:支持许多的input/output plugin、强大的filter功能。但是确内存占用会非常大。还有种情况(我就是orz...),在Logstash 5.2+版本中,input plugin使用Log4j,必须使用filebeat,并且只支持log4j 1.x版本。了解到filebeat已经支持filter和不少的output plugin,果断转投fielbeat阵营。 1. 简介 Filebeat官方介绍是这样的: Filebeat is a log data shipper for local files. Installed as an agent on your servers, Filebeat monitors the log directories or specific log files, tails the files, and forwards them either to Elasticsearch or Logstash for indexing. Here’s how Filebeat works: When you start Filebeat, it starts one or more prospectors that look in the local paths you’ve specified for log files. For each log file that the prospector locates, Filebeat starts a harvester. Each harvester reads a single log file for new content and sends the new log data to libbeat, which aggregates the events and sends the aggregated data to the output that you’ve configured for Filebeat. 翻译成中文大意就是: Filebeat是一个日志数据收集工具,在服务器上安装客户端后,filebeat会监控日志目录或者指定的日志文件,追踪读取这些文件(追踪文件的变化,不停的读),并且转发这些信息到elasticsearch或者logstarsh中存放。 以下是filebeat的工作流程:当你开启filebeat程序的时候,它会启动一个或多个探测器(prospectors)去检测你指定的日志目录或文件,对于探测器找出的每一个日志文件,filebeat启动收割进程(harvester),每一个收割进程读取一个日志文件的新内容,并发送这些新的日志数据到处理程序(spooler),处理程序会集合这些事件,最后filebeat会发送集合的数据到你指定的地点。 更关于探测器(prospectors)和收割进程(harvester)信息,请查看官网How Filebeat works. 1.2 核心功能 1.2.1 性能稳健,不错过任何检测信号 无论在任何环境中,随时都潜伏着应用程序中断的风险。Filebeat 能够读取并转发日志行,如果出现中断,还会在一切恢复正常后,从中断前停止的位置继续开始。 1.2.2 Filebeat 不会让通道过载 考虑到数据量较大,Filebeat 使用压力敏感协议向 Logstash 或 Elasticsearch 发送数据。如果 Logstash 正在繁忙地处理数据,它会告知 Filebeat 减慢读取速度。拥塞解决后,Filebeat 将恢复初始速度并继续输送数据。 1.2.3 不需要重载管道 当将数据发送到 Logstash 或 Elasticsearch 时,Filebeat 使用背压敏感协议,以考虑更多的数据量。如果 Logstash 正在忙于处理数据,则可以让 Filebeat 知道减慢读取速度。一旦拥堵得到解决,Filebeat 就会恢复到原来的步伐并继续运行。 1.2.4 输送至 Elasticsearch 或 Logstash。在 Kibana 中实现可视化。 Filebeat 是 Elastic Stack 的一部分,因此能够与 Logstash、Elasticsearch 和 Kibana 无缝协作。无论您要使用 Logstash 转换或充实日志和文件,还是在 Elasticsearch 中随意处理一些数据分析,亦或在 Kibana 中构建和分享仪表板,Filebeat 都能轻松地将您的数据发送至最关键的地方。 2. 性能 运行环境: OS 内存 CPU Filebeat版本 Logstash版本 CentOS 32g 6核Intel(R) Xeon(R) CPU E5-2620 v3 @ 2.40GHz 6.1 5.6.5 Logstash内存占用 [root@dde /]# cat /proc/20085/status /proc/20085/status | grep -i vm VmPeak: 9837428 kB VmSize: 9835376 kB VmLck: 0 kB VmHWM: 798364 kB VmRSS: 798360 kB VmData: 9677292 kB VmStk: 88 kB VmExe: 4 kB VmLib: 16520 kB VmPTE: 2568 kB VmSwap: 0 kB VmPeak: 9837428 kB VmSize: 9835376 kB VmLck: 0 kB VmHWM: 798364 kB VmRSS: 798360 kB VmData: 9677292 kB VmStk: 88 kB VmExe: 4 kB VmLib: 16520 kB VmPTE: 2568 kB VmSwap: 0 kB Filebeat内存占用 [root@dde /]# cat /proc/22207/status /proc/22207/status | grep -i vm VmPeak: 452796 kB VmSize: 410180 kB VmLck: 0 kB VmHWM: 16008 kB VmRSS: 16008 kB VmData: 376332 kB VmStk: 88 kB VmExe: 24764 kB VmLib: 1804 kB VmPTE: 184 kB VmSwap: 0 kB VmPeak: 452796 kB VmSize: 410180 kB VmLck: 0 kB VmHWM: 16008 kB VmRSS: 16008 kB VmData: 376332 kB VmStk: 88 kB VmExe: 24764 kB VmLib: 1804 kB VmPTE: 184 kB VmSwap: 0 kB Logstash因为是运行是JVM中的,可以看到Logstash内存占用比Filebeat大的多。 3. 安装 Filebeat官方提供了以下几种安装方式: (deb for Debian/Ubuntu, rpm for Redhat/Centos/Fedora, mac for OS X, docker for any Docker platform, and win for Windows). deb: curl -L -O https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-6.1.2-amd64.deb sudo dpkg -i filebeat-6.1.2-amd64.deb rpm: curl -L -O https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-6.1.2-x86_64.rpm sudo rpm -vi filebeat-6.1.2-x86_64.rpm mac curl -L -O https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-6.1.2-darwin-x86_64.tar.gz tar xzvf filebeat-6.1.2-darwin-x86_64.tar.gz docker: docker pull docker.elastic.co/beats/filebeat:6.1.2 windows: 1.下载zip包,地址。 2.解压到:C:\Program Files。 3.重命名文件夹为以下格式:filebeat-<version>-windows。 4.以管理员身份运行Shell。 5.使用如下命令,讲Filebeat安装为一个Windows Service: PS > cd 'C:\Program Files\Filebeat' PS C:\Program Files\Filebeat> .\install-service-filebeat.ps1 4. 配置 Elastic提供了一个配合ELK(Elasticsearch + Logstash + Kibana)的快速配置方式,不过我们不需要配合ELK使用Filebeat。直接配置filebeat根目录下filebeat.yml文件: filebeat.prospectors: - type: log enabled: true paths: - /var/log/*.log #- c:\programdata\elasticsearch\logs\* 需要配合elasticsearch使用时,增加以下配置: output.elasticsearch: hosts: ["192.168.1.42:9200"] 需要配合kibana使用时,增加以下配置: setup.kibana: host: "localhost:5601" Output Filebeat现在已经支持丰富的output类型: Elasticsearch Logstash Kafka Redis File Console Output codec Cloud output到kafka的配置类似: output.kafka: # initial brokers for reading cluster metadata hosts: ["kafka1:9092", "kafka2:9092", "kafka3:9092"] # message topic selection + partitioning topic: '%{[fields.log_topic]}' partition.round_robin: reachable_only: false required_acks: 1 compression: gzip max_message_bytes: 1000000 当事件的大小超过max_message_bytes的值的时候,会被直接丢弃不处理,所以要尽量控制filebeat产生的事件小于max_message_bytes的值。 上面示例中字段含义如下:enable: 该output是否生效;hosts:kafka broker集群地址;topic: kafka接收事件的topic;partition: kafka output的partioning 策略,可能值为:random, round_robin, hash。默认为hash;官方关于这几个可选值解释如下: random.group_events: Sets the number of events to be published to the same partition, before the partitioner selects a new partition by random. The default value is 1 meaning after each event a new partition is picked randomly. round_robin.group_events: Sets the number of events to be published to the same partition, before the partitioner selects the next partition. The default value is 1 meaning after each event the next partition will be selected. hash.hash: List of fields used to compute the partitioning hash value from. If no field is configured, the events key value will be used. hash.random: Randomly distribute events if no hash or key value can be computed. required_acks: kafka broker ACK可靠级别: 0=不需要响应, 1=等待本地commit, -1=等待所有的 replicascommit. 默认值为 1. Note: 如果设置为0,kafka将没有ACK返回,也许会有消息丢失或者错误。 5.运行 sudo ./filebeat -e -c filebeat.yml Filebeat目前已经支持Docker和Kubernetes。 5.1 Docker (1)pull image docker pull docker.elastic.co/beats/filebeat:6.1.2 (2) run image docker run \ -v ~/filebeat.yml:/usr/share/filebeat/filebeat.yml \ docker.elastic.co/beats/filebeat:6.1.2 (3) Configuration FROM docker.elastic.co/beats/filebeat:6.1.2 COPY filebeat.yml /usr/share/filebeat/filebeat.yml USER root RUN chown filebeat /usr/share/filebeat/filebeat.yml USER filebeat 5.2 Kubernetes (1)Deploy manifests curl -L -O https://raw.githubusercontent.com/elastic/beats/6.1/deploy/kubernetes/filebeat-kubernetes.yaml (2)Setting - name: ELASTICSEARCH_HOST value: elasticsearch - name: ELASTICSEARCH_PORT value: "9200" - name: ELASTICSEARCH_USERNAME value: elastic - name: ELASTICSEARCH_PASSWORD value: changeme (3)Deploy kubectl create -f filebeat-kubernetes.yaml check status $ kubectl --namespace=kube-system get ds/filebeat NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE-SELECTOR AGE filebeat 32 32 0 32 0 <none> 1m 6. 参考资料 Elastic Filebeat Reference

优秀的个人博客,低调大师

Elastic Search搜索引擎在SpringBoot中的实践

实验环境 ES版本:5.3.0 spring bt版本:1.5.9 首先当然需要安装好elastic search环境,最好再安装上可视化插件 elasticsearch-head来便于我们直观地查看数据。 当然这部分可以参考本人的帖子:《centos7上elastic search安装填坑记》https://www.jianshu.com/p/04f4d7b4a1d3 我的ES安装在http://113.209.119.170:9200/这个地址(该地址需要配到springboot项目中去) Spring工程创建 这部分没有特殊要交代的,但有几个注意点一定要当心 注意在新建项目时记得勾选web和NoSQL中的Elasticsearch依赖,来张图说明一下吧: 项目自动生成以后pom.xml中会自动添加spring-boot-starter-data-elasticsearch的依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency> 本项目中我们使用开源的基于restful的es java客户端jest,所以还需要在pom.xml中添加jest依赖: <dependency> <groupId>io.searchbox</groupId> <artifactId>jest</artifactId> </dependency> 除此之外还必须添加jna的依赖: <dependency> <groupId>net.java.dev.jna</groupId> <artifactId>jna</artifactId> </dependency> 否则启动spring项目的时候会报JNA not found. native methods will be disabled.的错误: 项目的配置文件application.yml中需要把es服务器地址配置对 server: port: 6325 spring: elasticsearch: jest: uris: - http://113.209.119.170:9200 # ES服务器的地址! read-timeout: 5000 代码组织 我的项目代码组织如下: 各部分代码详解如下,注释都有: Entity.java package com.hansonwang99.springboot_es_demo.entity; import java.io.Serializable; import org.springframework.data.elasticsearch.annotations.Document; public class Entity implements Serializable{ private static final long serialVersionUID = -763638353551774166L; public static final String INDEX_NAME = "index_entity"; public static final String TYPE = "tstype"; private Long id; private String name; public Entity() { super(); } public Entity(Long id, String name) { this.id = id; this.name = name; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } TestService.java package com.hansonwang99.springboot_es_demo.service; import com.hansonwang99.springboot_es_demo.entity.Entity; import java.util.List; public interface TestService { void saveEntity(Entity entity); void saveEntity(List<Entity> entityList); List<Entity> searchEntity(String searchContent); } TestServiceImpl.java package com.hansonwang99.springboot_es_demo.service.impl; import java.io.IOException; import java.util.List; import com.hansonwang99.springboot_es_demo.entity.Entity; import com.hansonwang99.springboot_es_demo.service.TestService; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import io.searchbox.client.JestClient; import io.searchbox.client.JestResult; import io.searchbox.core.Bulk; import io.searchbox.core.Index; import io.searchbox.core.Search; @Service public class TestServiceImpl implements TestService { private static final Logger LOGGER = LoggerFactory.getLogger(TestServiceImpl.class); @Autowired private JestClient jestClient; @Override public void saveEntity(Entity entity) { Index index = new Index.Builder(entity).index(Entity.INDEX_NAME).type(Entity.TYPE).build(); try { jestClient.execute(index); LOGGER.info("ES 插入完成"); } catch (IOException e) { e.printStackTrace(); LOGGER.error(e.getMessage()); } } /** * 批量保存内容到ES */ @Override public void saveEntity(List<Entity> entityList) { Bulk.Builder bulk = new Bulk.Builder(); for(Entity entity : entityList) { Index index = new Index.Builder(entity).index(Entity.INDEX_NAME).type(Entity.TYPE).build(); bulk.addAction(index); } try { jestClient.execute(bulk.build()); LOGGER.info("ES 插入完成"); } catch (IOException e) { e.printStackTrace(); LOGGER.error(e.getMessage()); } } /** * 在ES中搜索内容 */ @Override public List<Entity> searchEntity(String searchContent){ SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); //searchSourceBuilder.query(QueryBuilders.queryStringQuery(searchContent)); //searchSourceBuilder.field("name"); searchSourceBuilder.query(QueryBuilders.matchQuery("name",searchContent)); Search search = new Search.Builder(searchSourceBuilder.toString()) .addIndex(Entity.INDEX_NAME).addType(Entity.TYPE).build(); try { JestResult result = jestClient.execute(search); return result.getSourceAsObjectList(Entity.class); } catch (IOException e) { LOGGER.error(e.getMessage()); e.printStackTrace(); } return null; } } EntityController.java package com.hansonwang99.springboot_es_demo.controller; import java.util.ArrayList; import java.util.List; import com.hansonwang99.springboot_es_demo.entity.Entity; import com.hansonwang99.springboot_es_demo.service.TestService; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/entityController") public class EntityController { @Autowired TestService cityESService; @RequestMapping(value="/save", method=RequestMethod.GET) public String save(long id, String name) { System.out.println("save 接口"); if(id>0 && StringUtils.isNotEmpty(name)) { Entity newEntity = new Entity(id,name); List<Entity> addList = new ArrayList<Entity>(); addList.add(newEntity); cityESService.saveEntity(addList); return "OK"; }else { return "Bad input value"; } } @RequestMapping(value="/search", method=RequestMethod.GET) public List<Entity> save(String name) { List<Entity> entityList = null; if(StringUtils.isNotEmpty(name)) { entityList = cityESService.searchEntity(name); } return entityList; } } 实际实验 增加几条数据,可以使用postman工具,也可以直接在浏览器中输入,如增加以下5条数据: http://localhost:6325/entityController/save?id=1&name=南京中山陵 http://localhost:6325/entityController/save?id=2&name=中国南京师范大学 http://localhost:6325/entityController/save?id=3&name=南京夫子庙 http://localhost:6325/entityController/save?id=4&name=杭州也非常不错 http://localhost:6325/entityController/save?id=5&name=中国南边好像没有叫带京字的城市了 数据插入效果如下(使用可视化插件elasticsearch-head观看): 我们来做一下搜索的测试:例如我要搜索关键字“南京”我们在浏览器中输入: http://localhost:6325/entityController/search?name=南京 搜索结果如下: 刚才插入的5条记录中包含关键字“南京”的四条记录均被搜索出来了! 当然这里用的是standard分词方式,将每个中文都作为了一个term,凡是包含“南”、“京”关键字的记录都被搜索了出来,只是评分不同而已,当然还有其他的一些分词方式,此时需要其他分词插件的支持,此处暂不涉及,后文中再做探索。

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册