贷前系统ElasticSearch实践总结
宜信技术学院:http://college.creditease.cn/
贷前系统负责从进件到放款前的所有业务流程的实现。其中包含一些数据量大、条件多且复杂的综合查询请求。为了提高查询效率引入了ElasticSearch。并希望基于此快速搭建一个简单的数据仓库 并提供一些OLAP相关功能。同时有一些心得体会可以分享给各位
一 索引
描述:为快速定位数据而设计的某种数据结构。
索引类似于一本目录书,在某种程度上能够提升数据库查询效率。为了深入理解ES运行机制,则需系统学习其索引结构及其应用方法。
常用索引介绍
1. 位图索引
2. 哈希索引
3. BTREE索引
4. 倒排索引
1.1. 位图索引(BitMap)
位图索引适用于字段值为可枚举的有限个数值的情况
位图索引通过二进制数字串(bitMap)来表示数据的存在状态,在具体位置上采用1来表示该位置存在的数据信息,则当前位置未存在的数据信息则由0来表示
下图1 为用户表,存储了性别和婚姻状况两个字段;
图2中 分别为性别和婚姻状态建立了两个位图索引。
例如:性别->男 对应索引为:101110011,表示第1、3、4、5、8、9个用户为男性。其他属性以此类推。
使用位图索引查询:
• 男性 并且已婚 的记录 = 101110011 & 11010010 = 100100010,即第1、4、8个用户为已婚男性。
• 女性 或者未婚的记录 = 010001100 | 001010100 = 011011100, 即第2、3、5、6、7个用户为女性或者未婚。
1.2. 哈希索引
顾名思义,是指使用某种哈希函数实现key->value 映射的索引结构。
哈希索引适用于等值检索,通过一次哈希计算即可定位数据的位置。
下图3详细阐述了哈希索引的组织架构,并遵循了Java HashMap的实现机制。该数据结构通过冲突链表的方式实现了哈希冲突的有效解决。
图三
1.3. BTREE索引
BTREE索引是关系型数据库最常用的索引结构,方便了数据的查询操作。
BTREE: 有序平衡N阶树, 每个节点有N个键值和N+1个指针, 指向N+1个子节点。
一棵BTREE的简单结构如下图4所示,为一棵2层的3叉树,有7条数据:
图四
以Mysql最常用的InnoDB引擎为例,描述下BTREE索引的应用。
Innodb中的数据表采用索引组织形式存储,并非简单的文件系统结构。即整个数据表均采用B+tree结构进行存储,请参考图5的相关内容。
图 5
该系统架构中,默认情况下将图5左侧区域指定为主键表(当系统未明确设定为主动自增主键时,默认采用非空外码作为聚簇候选键;若无外码约束,则InnoDB内部会自动生成6字节隐藏主键作为聚簇候选)。叶节点完整地保存了包含主键字段和详细数据的内容(通过'key + row_data'格式实现数据持久化)。
采用B+树结构表示二级索引形式,在图5右侧部分中展示了其组织方式。相较于主键而言,“其叶子节点仅存储指针信息”,这意味着在查询过程中需多进行一次主键查找步骤。
维持一颗既有序又平衡的多叉树并非易事,在进行节点插入操作时需要对相应的位置进行调整其主要难点在于尤其是在被插入的新节点处于完全随机的状态时这种情况下只会导致局部区域发生变动并确保整体结构的高度稳定
可以参考红黑树的节点的插入算法:
https://en.wikipedia.org/wiki/Red–black_tree
因此若innodb表配置有自增主键,则数据插入将呈现有序状态并具备较高效率;反之若innodb表未配置自增主键,在插入非业务相关的关键字时可能导致大量b+树调整操作而降低性能
注:
• Mysql Innodb使用自增主键的插入效率高。
遵循基于Snowflake模型的自增键生成机制,在这种方案下产生的键值具有持续增长特性,并且能够实现较快的增长速度。
1.4. 倒排索引(反向索引)
倒排索引也叫反向索引,可以相对于正向索引进行比较理解。
正向索引体现了某一篇文献与其内部关键词之间的对应关系;当提供一个具体的文献标识时,则能够检索到该特定文献的相关词汇及其在文献中的位置信息。例如,在图6所示的例子中可以看到左侧为文献内容右侧为对应的索引结构。
图 6
反向索引是指某个关键词与其所属文档之间的对应关系;当设定特定的关键词标识时,则会检索出包含这些关键词的所有相关文档集合,并提供与这些关键词相关的具体信息如频率、出现位置等数据(如图7所示)。
图 7
由单词集合与文档集合构成如图8所示
图 8
以图9为基础设计的一种数据组织模式下形成的文本检索系统架构。这种组织方式主要由词典部分构成,在内存中的位置是整个文档语料库中经过提取整理后的所有唯一词汇所形成的序列化表征;随后依据每个关键词与其相关联的信息空间建立相应的逆向指针连接关系,在磁盘介质上完成这些指针关系的整体组织与存储;最终实现的是在查询阶段能够快速定位到目标信息资源所在的具体位置这一功能特性。
图 9 倒排索引结构
下面以一个具体的例子来描述下,如何从一个文档集合中生成倒排索引。
如图10,共存在5个文档,第一列为文档编号,第二列为文档的文本内容。
对上述文档集合进行分词解析后统计出的关键词汇共有10个。我们选取第一个关键词'谷歌'作为示例来进行说明:首先为其赋予一个唯一标识'单词ID'值为1接着统计其在所有文档中的出现次数即其在文档中的出现次数为5次其中有5份文件包含该词汇仅有第3份文件中标明了2次信息其余4份文件各出现一次从而构建了如图11所示的逆向索引表
1.4.1. 单词词典查询优化
对于一个规模非常庞大的文档集合而言,在其中可能会存在几十万个或上百万个不同的词汇。如何迅速定位某一个特定词汇,则直接关系到搜索效率的提升程度。为了提高搜索效率和系统性能,在构建信息检索系统时通常会采取以下几种具体的方法:
词典Hash索引
Hash表实现起来较为简便,在查找某个特定的单词时,则是通过应用哈希函数来计算其哈希值;如果哈希表中存在对应的记录,则说明该数据确实存在;否则将返回无结果的信息即可;这种情况下适用于进行精确匹配操作以及等于值的查找操作。如图12所示,在处理冲突时将具有相同哈希值的单词存储在一个冲突列表中。
词典BTREE索引
遵循Innodb二级索引模式,在关键词处理阶段将关键词按特定顺序进行排序处理,并构建一个基于BTree的数据结构作为存储机制;其中每个数据节点都通过指针连接到其对应的倒排索引结构。
二分查找
依照预设的规则排列生成一个按顺序排列的单词列表,在搜索过程中采用二分查找策略;这种搜索策略可对应于一种高度平衡且有序排列的树形结构,请参考图14所示的形式。
FST(Finite State Transducers )实现
FST是一种有限状态转换机,在本研究中被采用。该模型具备两个显著优势:首先,在词汇表中通过合理利用词干和后缀的重叠使用特性减少了存储空间;其次,在搜索速度方面表现优异,其搜索操作的时间复杂度为O(len(str))。
以插入“cat”、 “deep”、 “do”、 “dog” 、“dogs”这5个单词为例构建FST(注:必须已排序)。
15
如图15所示,在分析过程中我们清晰展示了所得结果为一个有向无环图(DAG)。该结构能够便捷地用于执行查询操作,并且在构建阶段我们可以将每个单词系统性地转换为特定数值和代码系统对应起来,在此基础之上实现了对输入字符串的关键路径分析功能。even在构建阶段我们可以将每个单词与特定数值和代码系统对应起来,在此基础之上实现了对输入字符串的关键路径分析功能并建立了对应的key-value存储关系以提高后续数据检索效率
此外,还可以采用这些数据结构作为优化手段之一.例如,我们可以选择Skip List,Trie以及Double Array Trie等结构来实现这一目标.
二 ElasticSearch使用心得
下面结合贷前系统具体的使用案例,介绍ES的一些心得总结。
目前使用的ES版本:5.6
官网地址:https://www.elastic.co/products/elasticsearch
ES一句话介绍:The Heart of the Elastic Stack(摘自官网)
ES的一些关键信息:
2010年2月首次发布
Elasticsearch Store, Search, and Analyze
丰富的Restful接口
基本概念
• 索引(index)
ES中的索引,并非前面所提及的那个概念,在这里指的是整个文档库,并不等同于单独的一个数据库结构;类似于关系型数据库中的一个数据表。
• 文档(document)
即写入ES的一条记录,一般是JSON形式的。
• 映射(Mapping)
文档数据结构的元数据描述通常采用JSON schema形式,并且能够根据需求动态构建或预先设定固定的模式
•类型(type)
因为误解和误用导致的问题存在, type不再建议采用; 在当前应用的 Elasticsearch 实现中每个索引仅设置了单一 default type.
• 节点
将一个ES的服务实例命名为服务节点。为了确保数据的安全性和可靠性,并且提升数据查询效率,在大多数情况下,ES倾向于采用集群部署模式。
• 集群
多个ES节点互相通信,在数据存储与查询方面实现了共同承担,并因此形成了一个集群系统
• 分片
为了应对海量数据存储的需求,在分布式系统架构中通常会采用分区(partition)的方式管理数据资源。这些分区(partitions)通常会平均分配到各个 Elasticsearch(ES)节点上以实现负载均衡和高效的数据访问特性。需要注意的是,在这种架构下,默认情况下无法更改分区数量
• 副本
完整的分片数据副本通常配备每个分片,并通过该副本进行数据查询;在集群环境下使用该副本能够显著提升查询效率。
安装部署
• JDK版本: JDK1.8
• 安装过程比较简单,可参考官网:下载安装包 -> 解压 -> 运行
• 安装过程遇到的坑:
启动过程中会消耗较多系统资源,在必要时应根据具体情况调整相关参数配置以优化性能和稳定性;如需进一步了解如何进行配置,请参考以下文档
http://www.cnblogs.com/sloveling/p/elasticsearch.html
实例讲解
下面以一些具体的操作介绍ES的使用:
• 初始化索引
初始化并配置索引为 Elasticsearch 系统创建新索引并设置基础参数配置。具体包括设置索引名称、文档映射(Mapping)方案、自定义索引别名、分片数量(默认值为 5 份)、副本数量(默认值为 1 份)等关键属性设置项;其中分片数量与副本数量在数据量较为有限的情况下可直接采用预设值无需额外配置。
该系统提供了两种初始化索引的方法:一种是利用Dynamic Template技术实现的Dynamic Mapping机制;另一种则采用了显式预定义映射方案。
1. 动态模板 (Dynamic Template)
`<p style="line-height: 2em;"><span style="font-size: 14px;">curl -X PUT http:``//ip:9200/loan_idx -H 'content-type: application/json' -d '{"mappings":{ "order_info":{ "dynamic_date_formats":["yyyy-MM-dd HH:mm:ss |
yyyy-MM-dd], "dynamic_templates":[ {"orderId2":{ "match_mapping_type":"string", "match_pattern":"regex", "match":"^orderId$", "mapping":{ "type":"long" } } }, {"strings_as_keywords":{ "match_mapping_type":"string", "mapping":{ "type":"keyword", "norms":false } } } ] } }, "aliases":{ "loan_alias":{} }}' ` |
|---|
在我们的系统中所使用的动态模板部分包括了一个JSON串。其中规定了日期格式的方式包括dynamic_date_formats字段;我们还制定了规则orderId2,在处理涉及这个字段时会将其转换为长整型数值。另外规定了一种处理方式,在处理string类型的字段时会将其映射到keyword类型,并且norms属性设置为false。有关于keyword类型的详细说明以及norms相关参数的具体设置,请参考下面的数据类型章节。
2. 预定义映射
预先定义的映射与前述方法存在显著差异之处在于:它要求将所有已知的字段类型详细描述并预先编码到mapping结构中。具体参考下图所示的部分内容作为操作示例:
16
图16中JSON结构的上层部分与动态模板保持一致。红框内标注的内容即为预先定义的关键属性:apply.applyInfo.appSubmissionTime, apply.applyInfo.applyId, apply.applyInfo.applyInputSource等字段名;其中type标识了该字段的具体类型,在完成映射定义后插入的数据必须严格对应这些字段名和类型描述;否则系统将返回相应的异常信息
• 常用数据类型:
常用的数据类型有text, keyword, date, long, double, boolean, ip
在实际应用中,默认将字符串字段设置为keyword而非text的主要原因是因为text类型的字段会被解析处理,并执行分词和过滤功能。而keyword字段则完整地存储数据而不进行额外的处理。从而避免了不必要的操作,并提高了索引性能。
配合使用keyword时还存在一个关键词参数norm,默认设置为true(即表示该字段参与评分);若设置为false,则表示当前字段将不参与评分。所谓的评分机制是基于单词的TF-IDF或其他相关规则计算得出的一种评估方法,在给查询结果打上一个分数后用于对搜索结果进行排序。通常情况下无需对搜索结果进行额外的排序操作(系统已有明确的排序字段配置),从而进一步优化了查询效率
• 索引名无法修改
为初始化一个索引,在URL中必须明确指定了对应的索引名称,并且一旦设置即不可更改;因此,在一般情况下,默认会设置一个默认标识符alias:作为其名称。
<p style=``"line-height: 2em;"``><span style=``"font-size: 14px;"``>``"aliases"``:{ ``"loan_alias"``:{ }<br> }<br></span></p> |
|---|
别名和索引名称代表多对一的关系,即每个索引都能被多个别名所映射,同样地,每个别名也能对应多个索引;在一对一模式下,所有涉及索引名称的位置都可以替换成相应的别名;主要优点在于这种替代方案能够灵活且便于调整。
• Mapping中已存在的字段无法更新
如果一个字段已经初始化完成(利用动态映射技术通过向数据库中注入数据的方式实现...)那么就可以明确该字段的数据类型。当尝试输入不符合预期的数据时会出现错误信息例如在创建一个预期为长整型的字段时如果往这个长整型字段中插入非数字类型的值则系统将返回关于数据类型的错误提示信息。
在这种情况下可能就需要重建一个新的数据库指数,并且在之前提到的方法中应用了表重命名这一策略;通常分为三个步骤执行:第一步是创建一个新的数据库指数并将存在格式错误字段的数据字段转换为其正确的数据类型;第二步是通过数据库引擎(ES)自带的Reindex API功能实现数据从原有数据库指数迁移至新生成数据库指数的位置;第三步则是利用数据库引擎提供的Aliases API功能,在新的数据库指数中附加原有数据库指数中存在的表重命名信息,并彻底删除原有数据库指数及其相关联的所有表重命名信息。
上述步骤适用于离线迁移;若希望实现不停机实时迁移,则步骤会稍微复杂些。
• API
基本的操作就是增删改查,可以参考ES的官方文档:
该指南详细阐述了Elasticsearch的核心功能与操作机制。
它涵盖了从数据存储到复杂查询的所有步骤。
读者可以通过本指南掌握基本操作并逐步提升技能。
同时提供了丰富的示例以增强理解效果。
一些比较复杂的操作通常会用到ES Script工具。推荐使用类Groovy语言下的painless脚本进行开发工作。这种脚本不仅能够提供一些常用的JAVA API功能(特别是基于JDK8构建的环境),同时还能支持像Joda time这样的常用时间处理接口。
举个比较复杂的更新的例子,说明painless script如何使用:
需求描述:
appSubmissionTime可被视为提交申请的时间点;lessonStartDate标记着课程开课的时间;expectLoanDate代表放款的时间节点。针对2018年9月10日的提交申请,在以下条件下进行处理:若提交申请与课程开课之间的日期间隔不足两天,则将放款安排至提交申请日期。
Painless Script如下:
<p style=``"line-height: 2em;"``><span style=``"font-size: 14px;"``>POST loan_idx/_update_by_query<br> { ``"script"``:{ ``"source"``:``"long getDayDiff(def dateStr1, def dateStr2){ <br> LocalDateTime date1= toLocalDate(dateStr1); LocalDateTime date2= toLocalDate(dateStr2); ChronoUnit.DAYS.between(date1, date2);<br> }<br> LocalDateTime toLocalDate(def dateStr)<br> { <br> DateTimeFormatter formatter = DateTimeFormatter.ofPattern(\"yyyy-MM-dd HH:mm:ss\"); LocalDateTime.parse(dateStr, formatter);<br> }<br> if(getDayDiff(ctx._source.appSubmissionTime, ctx._source.lenssonStartDate) < 2)<br> { <br> ctx._source.expectLoanDate=ctx._source.appSubmissionTime<br> }"``, ``"lang"``:``"painless"``<br> }<br> , ``"query"``:<br> { ``"bool"``:{ ``"filter"``:[<br> { ``"bool"``:{ ``"must"``:[<br> { ``"range"``:{ <br> ``"appSubmissionTime"``:<br> {<br> ``"from"``:``"2018-09-10 00:00:00"``, ``"to"``:``"2018-09-10 23:59:59"``, ``"include_lower"``:``true``, ``"include_upper"``:``true``<br> }<br> }<br> }<br> ]<br> }<br> }<br> ]<br> }<br> }<br>}<br></span></p> |
|---|
整个文本分为两大部分:下半部分使用query关键字进行按范围时间查询(具体日期为2018年9月10日),而上半部分的script用于对匹配到的数据进行操作。这一部分内容是基于类Groovy编写的一段代码(适合有一定Java基础的读者阅读)。经过格式化处理后如下所示:其中定义了两个辅助方法getDayDiff()和toLocalDate();在这些方法内部包含具体的if语句执行操作:
<p style=``"line-height: 2em;"``><span style=``"font-size: 14px;"``>long getDayDiff(def dateStr1, def dateStr2){<br> LocalDateTime date1= toLocalDate(dateStr1);<br> LocalDateTime date2= toLocalDate(dateStr2);<br> ChronoUnit.DAYS.between(date1, date2);<br>}<br>LocalDateTime toLocalDate(def dateStr){<br> DateTimeFormatter formatter = DateTimeFormatter.ofPattern(``"yyyy-MM-dd HH:mm:ss"``);<br> LocalDateTime.parse(dateStr, formatter);<br>}``if``(getDayDiff(ctx._source.appSubmissionTime, ctx._source.lenssonStartDate) < ``2``){<br> ctx._source.expectLoanDate=ctx._source.appSubmissionTime<br>}<br></span></p> |
|---|
然后提交该POST请求,完成数据修改。
• 查询数据
这里重点推荐一个ES的插件ES-SQL:
该网页详细介绍了Elasticsearch-SQL的核心功能与使用方法。
其中重点讲述了支持SQL语言的扩展功能。
包括基础查询与过滤条件的设置方法。
帮助开发者高效地利用该扩展功能提升数据检索效率。
该插件集成了多元化的SQL查询功能,并支持多种操作方式来检索所需数据。其中需要注意的地方有几个:
ES-SQL基于HTTP GET方法发送情况,受限于长度(4kb),可以通过以下参数进行优化设置。
http.max_initial_line_length: "8k"
进行总计、求平均等数字运算;若字段数据类型被指定为非数值型,则直接使用ESQL会导致错误;因此建议采用Painless脚本
使用Select as语法生成的查询结果与常规查询结果相比,在数据的位置结构上存在显著差异,并且这种差异需要特别需要注意
• NRT(Near Real Time):准实时
往ES系统中添加一条新记录后,在执行完查询操作之后一般都能够检索到最新的数据条目。人们通常认为ES系统是一个实时更新的搜索引擎系统。然而实际情况并非总是如此理想,在某种程度上这与其数据写入机制密切相关
– Lucene 索引段 - > ES 索引
将数据插入至 Elasticsearch 中时,则首先将信息存储在 Lucene 索引内随后才会被添加至 Elasticsearch 的主索引中在执行新主索引更新操作之前系统会查询当前版本的数据
– commit:原子写操作
索引段中的数据将按照原子级的方式来存储于ES索引中,在向ES系统中提交一条记录时,则能确保全部内容的成功提交,并非出现仅部分数据存储的情况。
– refresh:刷新操作,可以保证最新的提交被搜索到
索引段提交之后还有一个关键步骤需要执行刷新操作(Refresh),只有当这一操作完成之后才能确保新生成的索引数据能够被检索起来
为了性能方面的考量,Lucene选择延迟了耗时的刷新操作以避免在每次新增文档时进行耗时操作,默认设置为每隔一秒进行一次刷屏操作以保证一定的响应速度。然而,在实际应用中存在对更高刷新频率的需求。遇到这种情况时,则可考虑采用其他技术手段或重新评估需求合理性以达到预期效果
然而,ES为我们提供了便捷的实时查询接口,在使用该接口时所获取的数据均为最新信息,并具体说明了调用方式。
GET http://IP:PORT/index_name/type_name/id
该接口采用了HTTP GET方法,并基于数据主键(id)的机制进行查询。
该查询方式会同时检索...\cdot ...和Lucene索引段的数据,并整合结果。
最终结果通常是最新的。
但存在一个潜在的问题:每次执行该操作会导致ES执行刷新操作。
如果频繁调用此接口会导致性能问题。
• 数组处理
数组的处理比较特殊,拿出来单独讲一下。
– 表示方式就是普通的JSON数组格式,如:
• [1, 2, 3]、 [“a”, “b”]、 [ { "first" : "John", "last" : "Smith" },{"first" : "Alice", "last" : "White"} ]
– 需要注意的是,在ES中并没有数组这一特定数据类型的存在;最后的结果会以object或keyword等多种形式呈现出来。
– 普通数组对象查询的问题
普通数组对象的存储,会把数据打平后将字段单独存储,如:
<p style=``"line-height: 2em;"``><span style=``"font-size: 14px;"``>{ ``"user"``:[<br> { ``"first"``:``"John"``, ``"last"``:``"Smith"``<br> },<br> { ``"first"``:``"Alice"``, ``"last"``:``"White"``<br> }<br> ]<br>}<br></span></p> |
|---|
会转化为下面的文本
<p style=``"line-height: 2em;"``><span style=``"font-size: 14px;"``>{ ``"user.first"``:[ ``"John"``, ``"Alice"``<br> ], ``"user.last"``:[ ``"Smith"``, ``"White"``<br> ]<br>}<br></span></p> |
|---|
破坏了原有文本间的关联关系,
图17呈现了数据从索引插入到查询处理的简要流程:
1.组装数据,一个JSONArray结构的文本。
2.写入ES后,默认类型置为object。
- 检索first字段值为Alice且last字段值为Smith的所有文档(实际上没有任何一个文档同时满足这两个条件)
4.返回了和预期不符的结果。
17
– 嵌套(Nested)数组对象查询
嵌套数据结构能够有效应对上述查询结果不匹配的情况;推荐的技术方案是将ES系统中每个子对象独立生成独立的数据实体。如图18所示,在将用户信息字段声明为嵌套结构后再次执行相同查询操作时会返回空结果这是因为确实不存在同时满足user.first字段值为Alice以及user.last字段值为Smith这两个条件的有效文档存在
18
通常是对数组进行全量更新操作。若需单独修改某个字段,则需借助painless script技术实现,请参考文档:https://www.elastic.co/guide/en/elasticsearch/reference/5.6/docs-update.html
安全
作为核心议题的数据安全,在以下几个方面得到了有效的保障。
• XPACK
XPACK提供了名为Security的插件,并支持基于用户名密码的身份验证机制。该插件允许用户在第一个月体验该服务,并在试用期结束后,则会要求支付相应的费用以获取许可证。
• IP白名单
具体说明在开启ES服务器的防火墙配置时
• 代理
通常禁止业务系统直接连接 Elasticsearch 服务以进行数据查询,并要求对 Elasticsearch 接口进行封装处理;这些代理服务器还可以执行基本的安全认证功能,并且即使不用 XPACK 也能实现安全控制。
网络
• ElasticSearch服务器默认需要开通9200、9300 这两个端口。
以下将深入分析一个与网络相关的问题。当人们遇到类似的情况时,请参考本文内容作为指导。
引出异常前,先介绍一个网络相关的关键词,keepalive :
Http keep-alive和Tcp keepalive。
HTTP1.1协议默认启用'Connection: Keep-Alive'机制,在实际应用中意味着该HTTP连接能够被复用。具体而言,在后续的HTTP请求中可以直接利用现有连接而不必重新建立新的链接关系。这种机制显著提升了整体性能水平;而常见的HTTP连接池实现都会采用Keep-Alive策略来优化资源利用率
TCP协议中的keepalive机制与HTTP的不同之处主要体现在其功能定位上。在TCP协议中,则主要用于实现连接存活机制。具体配置则由net.ipv4.tcp_keepalive_time这一参数来决定。该参数设定了一个时间阈值(通常为2小时),当一个TCP连接在相隔多长时间内未交换数据时(即相隔超过阈值时间),设备将定期发送心跳包到另一端设备,并用于检测当前网络连接的有效性。当接收方确认接收到了这些心跳信息后,在正常情况下会及时返回确认应答ACK报文(Acknowledge),从而表明该网络通道仍然保持畅通无阻)。
下面介绍具体异常信息,描述如下:
两个核心业务服务器系统通过REST客户端进行通信(该客户端基于标准HTTP客户端实现,并支持多线程同时连接多个实例)与一组由三台独立的网络段上的ES节点构成的集群相连。偶尔会遇到一些周期性异常
每天9点左右会出现异常Connection reset by peer现象,并且这些现象会连续出现三次
<p style=``"line-height: 2em;"``><span style=``"font-size: 14px;"``>Caused by: java.io.IOException: Connection reset by peer <br> at sun.nio.ch.FileDispatcherImpl.read0(Native Method) <br> at sun.nio.ch.SocketDispatcher.read(SocketDispatcher.java:``39``) <br> at sun.nio.ch.IOUtil.readIntoNativeBuffer(IOUtil.java:``223``) <br> at sun.nio.ch.IOUtil.read(IOUtil.java:``197``)<br></span></p> |
|---|
为了有效解决该问题,在持续努力探索过程中
在线环境中,业务服务器与ES集群之间存在防火墙设置。该策略定义空闲连接超时时间为1小时(即从上一次心跳时间开始计算60秒),而与上面提到的Linux服务器默认设置不同(后者设定为空闲时间3600秒)。由于当前系统夜间访问量较低,在线时间内有部分远程会话超出预设超时时间未得到及时响应,在这种情况下(即服务端发送RST前),客户端已无法正常通信;当第二天早上尝试通过失效链接请求服务时,在所有三台节点均返回同样的错误信息:Connection reset by peer(服务端返回断开信号)。
参考
《深入理解ElasticSearch》
http://www.cnblogs.com/Creator/p/3722408.html
https://yq.aliyun.com/articles/108048
http://www.cnblogs.com/LBSer/p/4119841.html
http://www.cnblogs.com/yjf512/p/5354055.html
来源:宜信技术学院 作者:综合信贷雷鹏
