内容中心基于elasticsearch快速搭建搜索引擎

一、背景

易企秀创意云矩阵下面运营了多个以内容发布为核心的互联网产品,每天都有大量企业与设计师在这些平台制作并传播他们的作品,每个产品又由不同部门及技术小组分管运营,底层的技术框架、存储以及数据结构差异性都比较大,产品要求整合各产品线数据做一个一站式搜索引擎,数据要求尽可能与业务线保持实时同步,并且允许用户对搜索结果按照实时阅读量进行排序。幸运的是,elasticsearch提供了丰富的功能帮我们实现了大部分的操作,大幅降低了系统的维护成本。

二、数据处理流程

业务线用到的数据库主要有3类,分别是MySQL、oracle、MongoDB,其中内容数据存储在MongoDB中,其它基础信息分别储存在MySQL与oracle中,如标题、作者、发布时间等信息。那么对应的数据处理流程包含:数据抽取>数据清洗>映射到es>提供query。

  • 数据抽取
    1、业务数据:由于需求中要求数据近实时同步,那么按照传统的方式在上亿数据表中近实时做全表迁移与增量迁移的方案将是一件多么可怕的事情,即便每小时同步一次,业务方也是不能接受的;针对以上问题我们对同步方式做了优化,采用解析MySQL binlog的方式进行数据同步,业务方新增、修改、删除都会产生对应的binlog日志(oracle同步类似),根据不同的CRUD操作解析为对应的es操作,并将数据实时更新到索引库;针对MongoDB中的内容数据同步,只需每小时聚合有过修改操作的作品id,使用spark脚本根据id批量拉取MongoDB中的作品内容同步到es(MongoDB中作品id要建索引)。
    2、日志数据:作品的阅读量是基于日志计算的,前端通过sdk打点的,通过logserver(该项目会在后续实战篇进行讲解,高峰期每天可处理数十亿打点请求)采集日志发送到kafka。

  • 数据清洗
    1、业务数据:过滤标记为删除与发布时间为空的数据,因为这些数据已不允许在前端进行显示;这样的数据大约占全量数据的15%,滤除后可大幅提升后端存储与检索性能。
    2、日志数据:根据日志中业务类型与事件类型过滤出作品PV打点数据,再对数据格式化处理后存入新的kafka topic,为后续的实时消费使用;如果不对日志清洗,会有大量不相关的数据流入(页面元素点击事件、广告曝光事件等),会使日志量翻好几倍,徒增后端计算的压力。

  • 存储到ES
    1、业务数据:由于es中的索引库是宽表结构,会存在根据作品id拉取业务库多张属性表到一个es索引库的情况,这种情况下当遇到有删除操作的binlog时需要特殊处理,不能因为其中一张表的数据删除而删除es中对应的文档数据。
    2、日志数据:通过spark streaming实时消费kafka中的数据,每分钟形成一个batch,将计算好的作品pv数据通过es提供的spark connector存入对应的索引库,由于活跃作品比较多,每分钟对es的写操作大约是6-8w。

  • 提供query
    借助es提供的restful接口以及灵活的查询模板支持,使得接口层面的开发简单许多。

三、配置与优化

结合上述业务场景,如果不做任何优化,首次检索大约1s左右才能响应;由于es内部会对query和segment做缓存,当相似条件多次请求后,平均响应时间会降到500ms左右;经过对数据库、索引配置、查询语句三个层面简单配置后,首次检索降到了200ms以内,平均响应时间降了一个量级。

elasticsearch为满足多种不同的应用场景,底层提供多种数据结构支持,并做了大量的默认配置优化,部分配置针对具体的用户使用场景可能是冗余的,甚至可能造成性能的下降,需要根据实际业务场景做适当取舍,我们结合自身使用场景做了如下优化(文章中有疏漏或不正确的地方也欢迎点评指正):

数据库

1、jvm内存,分配给es的内存不要超出系统内存的50%,预留一半给Lucene,因为Lucene会缓存segment数据提升检索性能;内存配置不要超过32g,如果你的服务器内存没有远远超过64g,那么不建议将es的jvm内存设置为32g,因为超过32g后每个jvm对象指针的长度会翻倍,导致内存与cpu的开销增大。
2、禁用swapping,开启服务器虚拟内存交换功能会对es产生致命的打击,如果某个segment数据被缓存到了磁盘上,会导致原来0.1毫秒的操作变成10毫秒,大大降低数据的检索性能,使得es在提供查询服务时出现木桶效应,拖跨整个集群的对外服务性能。
3、硬盘配置,建议使用SSD,如果你的服务器硬盘是一块200g的机械硬盘,那么建议分成两块100g的盘去使用,这样能大大提升es读写硬盘的能力,通过elasticsearch.yml中的path.data来实现。
4、其它配置

bootstrap.memory_lock: true
#设置为true锁住内存,当服务混合部署了多个组件及服务时,应开启此操作,允许es占用足够多的内存。
indices.breaker.request.limit: 10%
#设置单个request请求的内存熔断限制,默认是jvm堆的60%(es7.0引入了新的内存熔断机制,会智能判断,规避OOM)。
index.merge.scheduler.max_thread_count: 1
#设置segment合并时占用的线程数,配置线程数越多对磁盘io消耗就越大(SSD忽略)。
indices.queries.cache.size:20%
#query请求可使用的jvm内存限制,默认是10%。
indices.requests.cache.size:2%
#查询request请求的DSL语句缓存,被缓存的DSL语句下次请求时不会被二次解析,可提升检索性能,默认值是1%。
indices.fielddata.cache.size:30%
#设置字段缓存的最大值,默认无限制。

索引配置

1、通过配置index_options优化text field的索引生成方式,es默认除生成倒排以外还会记录文档的词频与term的位置信息,如果只是用来对文档的检索不需要评分与高亮,可优化。

2、禁用field评分,如果该字段不需参与相关度打分那么可禁用,通过将norms设置为false来禁用评分提升检索性能。

3、Number类型的优化,如果该数字类型字段存储的是type信息 ,不会进行排序与范围查询操作,建议存储为keyword类型,keyword本身做了大量优化操作,对于检索与过滤性能更佳。

4、禁用doc_values,es为提升keyword类型下数据的排序与聚合性能,默认为每一个keyword field都开启了此功能,非必要场景禁用此操作可节省磁盘空间。

5、开启最优化压缩,通过配置"index.codec":"best_compression"开启最优压缩,可节省磁盘空间,但会增大cpu负载。

6、设置合适的分片数,多分片为es集群提供了分布式计算的保障,但一般不建议超过服务器的数量,过多的分片就意味着会有过多的segment产生,过多的segment消耗内存与系统IO。

7、设置合适的副本数,虽然多副本可以提升es的并发处理能力,但根据实际应用当中,这个值不建议配置太高,因为副本数据在进行同步时会带来过高的IO消耗。

8、降低刷新操作,过高的刷新会增大磁盘io负载,通过配置"index.refresh_interval":"-1"来控制刷新频率,es默认配置为1s,如果对数据时效性要求不高的话修改为30s-60s,-1表示禁用刷新。

9、通过forcemerge 强制合并索引段,定期清理过小的segment段,Lucene为加快检索速度,会为每个segment构建一层FST前缀索引,这些数据会全部加载到内存,降低segment段的数量有助于降低内存的消耗,过多的segment段也会增大底层os打开关闭文件的时间。

10、copy_to,使用multi_match在大数据量场景下进行多字段查询会很慢,利用copy_to将多个字段中的索引合并到一个字段,使用match查询该字段性能大幅提升。

查询优化

1、尽量避免深度翻页场景,默认最大结果集深度为10000,可根据实际使用场景适当调大该值,如index.max_result_window:20000 ,该值设置过大,在高并发场景下会频繁触发es内部gc操作,影响整体性能。

2、使用sliced scroll翻页拉取大数据结果集,大家都知道使用scroll去做深度翻页读取大量数据,但这种操作不支持online,原因就是它的指针是全局的无法支撑高并发操作,这时需要用到sliced scroll。

3、尽可的使用filter操作,因为filter操作会使用缓存并且不会进行评分计算,性能高于query。

4、如果查询语句比较复杂且不需要翻页操作的话可增加timeout=1s&terminate_after=10000两个参数,在高并发场景下性能提升3-5倍。

四、小结

5个实例(8核16g)索引了上亿文档内容,优化后任意检索一条数据由原来的1s左右降低到200ms内 ,平均性能提升3-5倍。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,588评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,456评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,146评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,387评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,481评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,510评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,522评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,296评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,745评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,039评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,202评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,901评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,538评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,165评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,415评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,081评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,085评论 2 352

推荐阅读更多精彩内容