ElasticSearch架构反向思路

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
日志服务 SLS,月写入数据量 50GB 1个月
简介: 我分析一个系统的设计思路,往往不是一开始就去看看这个系统的设计文档或者源代码,而是去看系统的基本介绍,特别是框架类的功能详细介绍,然后根据介绍可以大概了解这样一个系统用来解决什么问题,有哪些特色,然后基于自己对这些问题的想法,根据自己的经验来同样设计一个系统,看包含哪些内容,使用哪些架构模式和思路,然后带着自己设计的东西再去看另一个系统的设计思路,可能再更加清楚,也会反思自己的设计是否哪些地方存在问题,可以加以改进。

我曾经在多个场合说过,我分析一个系统的设计思路,往往不是一开始就去看看这个系统的设计文档或者源代码,而是去看系统的基本介绍,特别是框架类的功能详细介绍,然后根据介绍可以大概了解这样一个系统用来解决什么问题,有哪些特色,然后基于自己对这些问题的想法,根据自己的经验来同样设计一个系统,看包含哪些内容,使用哪些架构模式和思路,然后带着自己设计的东西再去看另一个系统的设计思路,可能再更加清楚,也会反思自己的设计是否哪些地方存在问题,可以加以改进。

最近正好准备玩ElasticSearch,本来在2013年就想玩这个,但由于工作原因耽误了,现在又翻出来看看有什么好玩的,下面就详细地记录了我对ElasticSearch的反向架构思考。顺便补充一句,目前用来研究的ElasticSearch的版本号是6.3

先来看看一份对ElasticSearch比较典型的介绍:

Elasticsearch是一个基于Apache Lucene(TM)的开源搜索引擎。无论在开源还是专有领域,Lucene可以被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库。
 
但是,Lucene只是一个库。想要使用它,你必须使用Java来作为开发语言并将其直接集成到你的应用中,更糟糕的是,Lucene非常复杂,你需要深入了解检索的相关知识来理解它是如何工作的。
 
Elasticsearch也使用Java开发并使用Lucene作为其核心来实现所有索引和搜索的功能,但是它的目的是通过简单的RESTful API来隐藏Lucene的复杂性,从而让全文搜索变得简单。
 
不过,Elasticsearch不仅仅是Lucene和全文搜索,我们还能这样去描述它:
 
分布式的实时文件存储,每个字段都被索引并可被搜索
分布式的实时分析搜索引擎
可以扩展到上百台服务器,处理PB级结构化或非结构化数据
而且,所有的这些功能被集成到一个服务里面,你的应用可以通过简单的RESTful API、各种语言的客户端甚至命令行与之交互。
 
上手Elasticsearch非常容易。它提供了许多合理的缺省值,并对初学者隐藏了复杂的搜索引擎理论。它开箱即用(安装即可使用),只需很少的学习既可在生产环境中使用。
 
随着你对Elasticsearch的理解加深,你可以根据不同的问题领域定制Elasticsearch的高级特性,这一切都是可配置的,并且配置非常灵活。

幸亏以前使用过Lucene做IDE底层项目模型关系的管理,对Lucene还算比较熟悉,否则还得先去看看Lucene的功能和用法。

从上面的介绍可以看出几个关键内容:

  1. Lucene在做索引的时候本身就有存储功能,所以存储这个东西是天然就有的,反而不用花时间考虑。
  2. 性能是一个比较关键的东西,特别是要做实时引擎,怎么保证高性能。
  3. ElasticSearch是一个分布式的系统,那么必然存在多结点通讯,协作等问题,比如使用ZooKeeper之类的系统进行注册和协同,当然也保不齐他自己玩一套。
  4. 既然是分布式系统,那么数据存储就不可能完全单机化,也就是存在Sharding的情况,如何Sharding,如何同步,在查找结果的时候,如何聚合。
  5. 分布式系统,只要涉及到数据更新,必然存在数据不一致问题,怎么解决。
  6. 由于索引本身原因,一旦出现Sharding,就很难做联合的查询,这个应该不能实现的,至少说不可能很简单得实现。
  7. 有一个网络层或者说对外服务接口层,用来进行交互,看介绍,支持多种协议,比如Client直接调用,或者是Restful风格。
  8. 参考服务接口层,还允许很多地方进行配置,那么很显然,应该是使用了类似于插件的技术来支持很多功能。

我的习惯是从使用者角度来倒推系统架构

  1. 对外服务,称为Interface,这个其实还相对简单,应该提供两个基本功能,即BuildIndex(不一定要区分Create和Update,但Delete肯定要有)和Query(应该基于主Key和Condition两种查询),把这两个基本接口设计好,然后在上面加不同的封装或者通过Netty之类网络架构提供Rest服务,也可能基于Stub类似的机制提供RPC调用。
  2. 查询功能,是采用SQL还是Query模型的方式,我更倾向于后者,因为关联查询等很多功能是无法提供的,SQL校验会是比较麻烦的事情。
  3. 不管是BuildIndex还是Query,肯定要找到一台机器或者多台机器进行处理,由于这是一个分布式系统,而且还支持Sharding,那么可以肯定,需要分组,即Group,一个Group中包括若干个Node,用来支持服务。
  4. 怎么分组,正常可能是分两级,一种是基于模型定义的,比如对于某一些数据,象商品,用户这些数据可能分成一类数据对应一个Group来处理,这种处理比较直观,也简单。也就是说每一类模型会对应一个Group,而一个Group可能对着多个模型,特别是数据相对较少的时候。还有一种就是Sharding,通常来说,是对一类数据,根据某一个或者几个字段(Field),进行条件分组,也就说在这种分组情况下,每个Node的数据都是不全的,需要将多个Node合并在一起,才会形成完整的数据集。这两种分组都需要支持的。
  5. 对于BuildIndex和Query,当系统分成多个Group的时候,肯定要有一个Router的概念,即一个BuildIndex或者Query服务来的时候,得找到相应的Group(应该是Group下的Node),因为Lucene中的Document和Term特性,应该需要设计一个类似于数据库中的Table模型,一个Group负责处理多个Table。在BuildIndex和Query请求里,1. 必须带有Table的准确定义,比如User,Item等。
    按照前面的思考,Group是肯定应该存在的,但是每个Group否需要一个MasterNode呢?
  6. 当一个Query请求定义清楚后,会以路由的方式找到一个Group,如果数据量不大的话,一个Group中的Node应该是数据对等的,那么请求落到任何一个Node上都可以得到相应的结果。如果数据量很大,出现Sharding,就分两种情况,一种是Query中的条件,能够符合Sharding的定义条件,那么落到任何一个Node上以后,通过转发的方式,总是可以拿到请求,应该有两种实现方式,一是请求发到某个Node上以后,由Node分析后,将可以导向的Node返回,由请求方再次将指定的Node发送请求,二是任意Node直接向可以导向的Node转发请求,并拿到结果后返回给请求方,第二种对客户端友好,但如果数据量大的话,可能不太合适。还有一种情况就是,如果Query中的条件不能够符合Sharding定义,那么就出现类似于数据库查询的FullScan,由收到的Node将请求转发给相应的Node,构成全量搜索,然后由该Node合并后,返回。如果这样看,最好的方式还是Node统一处理,对请求方更友好一些,也更一致。
  7. 当BuildIndex的时候,必然是发给一个Node,由其完成Index后,再同步给其它Node,此时同步,是有一个MasterNode还是没有好呢?感觉设计一个MasterNode可能使得逻辑更简单。即大的Group里,MasterNode主要负责协作和BuildIndex同步,而Query则可以尽可能地落到DataNode侧。
  8. 虽然有了MasterNode,但仍然是可以将BuildIndex请求发给DataNode,由DataNode转发给MasterNode,这样会更加简单和友好。
  9. 考虑到BuildIndex和Query会有不同步的情况,那么怎么减少这种不一致性呢?如果由MasterNode或者指定的一个DataNode进行BuildIndex的时候,对其它Node的Query都会产生数据不一致性问题。假设由MasterNode给其它DataNode全部上锁,此时查询性能急速下降,这种方法不是非常建议,容易形成堵塞,不过如果数据很少更新,而且对数据一致性有较高要求,也可以支持,那里可能得在这个地方允许用户配置一致性优先还是性能优先了。如果是后者的话,按照我对Lucene的了解,此时每个DataNode最好有一个DiskStore和一个MemoryStore,查询时将两者合并查询,这样在保证高性能的情况下可以减少不一致性。或者更灵活一点,允许在BuildIndex的时候允许指定是否加锁,但这样可能会增加复杂度,需要再思考一下。
  10. 同样是数据不一致问题,除了上面的内容以外,还需要使用Log,这样MasterNode先记录Log,然后进行Index,同时分发给DataNode,DataNode也是先记录Log,这样一旦出现问题,可以随时在启动时从Log处Redo。
  11. 维护和管理功能:动态扩容,Reindex(扩容时肯定要用到),启动时先与多个DataNode同步Log,再根据Log进行Redo,保证数据的一致性。
  12. 插件化设计没什么难点,不管是类似于OSGi,还是说直接写一个Plugin的接口,然后加一个PluginManager都可以解决问题。但关键是Plugin需要在哪些情况下调用,以便让开发者可以更多的加入自己的定制。我猜可能有以下几个点:网络请求的Before和After处理(比如支持不同的数据模型,不同的安全检查等,记录日志,流量控制等),启动后的After处理(比如对Log进行Check,以便Redo),BuildIndex和Query的Before和After处理(其实就可以通过这个扩展来处理数据同步的问题)。
  13. 上面说的插件化设计并不难,但是否使用统一的Plugin接口,还是分开,需要考虑一下,毕竟可以提供扩展点的地方太多了。如果是我设计,大概是三大级继承,最顶层的有一个Plugin或者Extension的接口,提供Name,Desription,Dependecy等内容的定义,这个和Equinox都类似,其实不带任何业务支持的,第二层是业务级别的,比如说网络请求的,日志处理的,第三层就是具体实现了。再多就有点复杂了,有一个最顶层接口的好处是,在Eclipse里,查下继承关系,就得到所有实现了,方便分析代码,如果只设计二和三层,哈哈,就有得找了。

基于以上分析,可以列出来几个基本的元素和服务:

  1. Node+Group+MasterNode+DataNode
  2. Table+Field+Key+Condition
  3. BuildIndex+Query
  4. Log
  5. Plugin

下面是大致的架构域图:

_

还有几个难点,需要再考虑一下:

  1. Query可能会有Paging的需要,那么一旦出现Sharding的话,需要将多个DataNode的结果Merge后,进行Sort,再计算Paging后返回。这个对性能的要求比较高,特别是当页面翻到几十页的时候,性能损失非常大,如何处理?还是说技术层面上不做解决,直接让业务方来自行规划。
  2. 因为ElasticSearch是基于Lucene的,而Lucene并不提供事务操作,比如先行锁再Update,因此一旦出现冲突时,因为网络延时等原因,有可能后面的数据覆盖前面的数据,这种情况怎么考虑,是加一个时间版本号还是忽略这种情况?
  3. 另外ElasticSearch对数据一致性不可能提供太好的解决方案,因此最好还是将一些非核心业务数据进行查询,比如日志,就不会出现修改,再比如电商中的商品表,修改相对并不频繁,但如果商品表里包含商品数量,那么就挂了,所有必须减少将频繁更新的数据放入搜索。
  4. 有点记不清楚Lucene的存储机制了,是否支持类似于数据库的Update语句,只更新部分数据。如果不支持,那么ElasticSearch是否需要支持呢?如果是我,应该不会支持,做太多的事情更容易出错。
  5. 当MasterNode当掉,显然可以通过选举或者别的方法找到一个新的MasterNode,但如果一个MasterNode或者DataNode收到一个BuildIndex请求后,再当掉,最好是通知Client失败,由Client发起重试。由于所有BuildIndex请求都是发给MasterNode来处理的,那么就相对简单了,如果MasterNode失败后重新加入Group,由于此时它不再是Master,就可以丢弃这个日志,保证数据一致性。这块的细节会比较多,记录Log,然后如何Redo,如何Sync,如何抛弃,都需要深入分析。不在这里折腾了。
相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
相关文章
|
1月前
|
存储 分布式计算 大数据
大数据-169 Elasticsearch 索引使用 与 架构概念 增删改查
大数据-169 Elasticsearch 索引使用 与 架构概念 增删改查
59 3
|
2月前
|
存储 JSON 数据库
Elasticsearch 分布式架构解析
【9月更文第2天】Elasticsearch 是一个分布式的搜索和分析引擎,以其高可扩展性和实时性著称。它基于 Lucene 开发,但提供了更高级别的抽象,使得开发者能够轻松地构建复杂的搜索应用。本文将深入探讨 Elasticsearch 的分布式存储和检索机制,解释其背后的原理及其优势。
203 5
|
16天前
|
存储 索引
Elasticsearch分布式架构
【11月更文挑战第2天】
23 1
|
1月前
|
存储 监控 分布式数据库
百亿级存储架构: ElasticSearch+HBase 海量存储架构与实现
本文介绍了百亿级数据存储架构的设计与实现,重点探讨了ElasticSearch和HBase的结合使用。通过ElasticSearch实现快速检索,HBase实现海量数据存储,解决了大规模数据的高效存储与查询问题。文章详细讲解了数据统一接入、元数据管理、数据一致性及平台监控等关键模块的设计思路和技术细节,帮助读者理解和掌握构建高性能数据存储系统的方法。
百亿级存储架构: ElasticSearch+HBase 海量存储架构与实现
|
3月前
|
消息中间件 搜索推荐 UED
Elasticsearch 作为推荐系统后端的技术架构设计
【8月更文第28天】在现代互联网应用中,推荐系统已经成为提高用户体验和增加用户粘性的重要手段之一。Elasticsearch 作为一个高性能的搜索和分析引擎,不仅能够提供快速的全文检索能力,还可以通过其强大的数据处理和聚合功能来支持推荐系统的实现。本文将探讨如何利用 Elasticsearch 构建一个高效且可扩展的推荐系统后端架构,并提供一些具体的代码示例。
268 0
|
5月前
|
存储 缓存 监控
深入解析Elasticsearch的内存架构与管理
深入解析Elasticsearch的内存架构与管理
深入解析Elasticsearch的内存架构与管理
|
6月前
|
canal 消息中间件 关系型数据库
【分布式技术专题】「分布式技术架构」MySQL数据同步到Elasticsearch之N种方案解析,实现高效数据同步
【分布式技术专题】「分布式技术架构」MySQL数据同步到Elasticsearch之N种方案解析,实现高效数据同步
273 0
|
13天前
|
缓存 负载均衡 JavaScript
探索微服务架构下的API网关模式
【10月更文挑战第37天】在微服务架构的海洋中,API网关犹如一座灯塔,指引着服务的航向。它不仅是客户端请求的集散地,更是后端微服务的守门人。本文将深入探讨API网关的设计哲学、核心功能以及它在微服务生态中扮演的角色,同时通过实际代码示例,揭示如何实现一个高效、可靠的API网关。
|
12天前
|
Cloud Native 安全 数据安全/隐私保护
云原生架构下的微服务治理与挑战####
随着云计算技术的飞速发展,云原生架构以其高效、灵活、可扩展的特性成为现代企业IT架构的首选。本文聚焦于云原生环境下的微服务治理问题,探讨其在促进业务敏捷性的同时所面临的挑战及应对策略。通过分析微服务拆分、服务间通信、故障隔离与恢复等关键环节,本文旨在为读者提供一个关于如何在云原生环境中有效实施微服务治理的全面视角,助力企业在数字化转型的道路上稳健前行。 ####
|
12天前
|
Dubbo Java 应用服务中间件
服务架构的演进:从单体到微服务的探索之旅
随着企业业务的不断拓展和复杂度的提升,对软件系统架构的要求也日益严苛。传统的架构模式在应对现代业务场景时逐渐暴露出诸多局限性,于是服务架构开启了持续演变之路。从单体架构的简易便捷,到分布式架构的模块化解耦,再到微服务架构的精细化管理,企业对技术的选择变得至关重要,尤其是 Spring Cloud 和 Dubbo 等微服务技术的对比和应用,直接影响着项目的成败。 本篇文章会从服务架构的演进开始分析,探索从单体项目到微服务项目的演变过程。然后也会对目前常见的微服务技术进行对比,找到目前市面上所常用的技术给大家进行讲解。
29 1
服务架构的演进:从单体到微服务的探索之旅
下一篇
无影云桌面