#研发解决方案介绍#基于ES的搜索+筛选+排序解决方案
本文档适用人员:研发和运维
- 曾经的基于MongoDB的筛选+排序解决方案
- MongoDB方案的缺陷
- 看中了搜索引擎的facet特性
- 看中了ES的简洁
- 看中了ES的天生分布式设计
- 窝窝的ES方案
- ES的几次事故和教训
- ES自身存在的问题
|
由于频道页流量小于首页,尤其是用户很少点击到的深度筛选条件组合查询,所以下图中的所有枚举项商品数量都容易缓存失效或缓存挤出: ![]() 图2 筛选越来越复杂,标题数字却要保持准确性 一旦缓存失效后,但凡我从上图的“20元以下”点击切换到“51-80元”或做更深层次筛选,那么程序就要针对上面所有组合条件对 MongoDB 商品记录逐一做 count 计算。 虽然每一个 count 计算都很快不属于慢查询,但也架不住多啊,尤其是配上区县和商圈等动辄6、7层深的筛选组合,点击一次轻易就涉及成百次的 count 计算,代价还是很大的。 由于在商城模式下,不同频道很可能不断增加新筛选条件,导致筛选组合越来越复杂,最终可能要求我们从基于 NoSQL 的排序和筛选方案,尽快转变为基于搜索引擎的排序和筛选方案。 |
介绍分面 分面是指事物的多维度属性。例如一本书包含主题、作者、年代等分面。而分面搜索是指通过事物的这些属性不断筛选、过滤搜索结果的方法。可以将分面搜索看成搜索和浏览的结合。 灵活使用分面 有时用户并不明确自己的目的,因此提供宽松的筛选方式更符合这部分用户的预期。Bing 的旅行搜索中选择航班时,用户可以通过滑块来选择某个时间段起飞的航班。 |
- Field Facet:如果需要对多个字段进行Facet查询,那么将 facet.field 参数声明多次,Facet字段必须被索引;
- Date Facet:时间字段的取值有无限性,用户往往关心的不是某个时间点而是某个时间段内的查询统计结果,譬如按月份查;
- Facet Query:利用类似于filter query的语法提供了更为灵活的Facet,譬如根据价格字段查询时,可设定不同价格区间;

商品维度是我们主要的查询维度,其业务复杂度也比较高。针对网站查询特性,我们的商品主索引方案为:每个城市建立一个 index,所以一共有400多个 index,每个城市仅有1个主 shard(不分片)。这样做的好处是以后我们根据热点城市和非热点城市,可以将各个 index 手工分配到不同的 node 上,可以做很多优化。
其结构为:
图7 goodsinfo
为了减少索引量和功能拆分,减少商品索引的内存占用,所以我们把全文检索单独建为一个索引。
每个城市索引或者商品索引按频道分为几个type,如下图所示。
图9 type
商品频道映射到es的type是很容易理解的,因为每个频道的模型不同:有的频道特有“用餐人数”属性,有的频道特有“出发城市”和“目的地城市”属性 所以每个频道对应一个es的type,每个type绑定一种特定的mapping(这个mapping里面可以指定该频道各自的特殊属性如何储存到ES)。ES 会保证所有 shard 的主副本不在同一个 node 上面,但我们是 ES 服务器集群,每台服务器上有多个 node,一个 shard 的主副本不在同一个节点还是不够的,我们还需要一个 shard 的主副本不在同一台服务器,甚至在多台物理机的情况下保证要保证不在同一个机架上,才可以保证系统的高可用性。
所以ES提供了一个配置:cluster.routing.allocation.awareness.attributes: rack_id。
这个属性保证了主副 shard 会分配到名称不同的 rack_id 上面。
当我们停止一个节点时,如停止 174_node_2,则 ES 会自动重新平衡数据,如下图所示:
图13 重新分布
即使一台物理机完全 down 掉,我们可以看到其他物理机上的数据是完整的,ES 依然可以保证服务正常。

查看其内存使用状况发现,ES 各个节点的 JVM perm 区均处于满或者将要满的状态,如下图所示:
图15 当时perm的容量
注1:jstat -gc <pid>命令返回结果集中,上图红色方框中字段的含义为:
PC Current permanent space capacity (KB). 当前perm的容量 ;
PU Permanent space utilization (KB). perm的使用。
大家可以看到图1中的PU值基本等于PC值了。
由于 ES 各个节点的 perm 区接近饱和状态,所以造成了服务器负载升高,GC 频繁,并进一步造成 ES 集群出现了类似于“脑裂”的状态。
- 引入新技术,还是要谨慎,毕竟如果真是 mevl 脚本引起的问题,其实线下做压力测试就能提前发现。
- 加强ES的监控。
- 虽然现在回过头来看,如果在第一时间重启所有 nodes,损失应该是最小的——但是王超认为当时采用的保守策略依然是有意义的,因为在弄清楚问题原因之前,直接重启 nodes 有可能反而造成更大的数据破坏。
Elastic Search 在窝窝运行几年来基本稳定,可靠性和可用性也比较高,但是也暴露了一些问题:
- ES 的更新效率,作为基于 lucene 的分布式中间件,受限于底层数据结构,所以其更新索引的效率较低,lucene 一直在优化;
- ES 的可靠性的前提是保证其集群的整体稳定性,但我们遇到的情况,往往是当某个节点性能不佳的情况下,可能会拖累与其同服务器上的所有节点,从而造成整个集群的不稳定。
- 其实解决这个问题不难,两种方法:
- 增加服务器,让节点尽可能地散开;
- 当某个节点出现问题的时候,需要我们及早发现处理,不至于拖累整个集群。其实监控一个节点是否正常的方法不难,ES 是基于 JVM 的服务,它出现问题,往往和 GC、和内存有关,所以只要监控其内存达到某个上限就报警即可;
- 没有一个好的客户端可视化集群管理工具,官方或者主流的可视化管理工具,基本都是基于 ES 插件的,不符合我们的要求,所以需要一款可用的客户端可视化集群管理工具;
- ES 的升级问题,由于 ES 是一个快速发展的中间件系统,每一次新版本的更新,更改较大,甚至导致我们无法兼容老版本,所以 ES 升级问题是个不小的问题,再加上我们数据量较大,迁移也比较困难。
——END——
窝窝的解决方案介绍列表:
#研发解决方案#基于StatsD+Graphite的智能监控解决方案
es术语介绍:
cluster:
代表一个集群,集群中有多个节点,其中有一个为主节点。这个主节点是可以通过选举产生的。注意,主从节点是对于集群内部来说的。es的一个概念就是去中心化,字面上理解就是无中心节点,这是对于集群外部来说的,因为从外部来看es集群,在逻辑上是个整体,你与任何一个节点的通信和与整个es集群通信是等价的。
shards
代表索引分片。es可以把一个完整的索引分成多个分片,这样的好处是可以把一个大的索引拆分成多个,分布到不同的节点上。构成分布式搜索。分片的数量只能在索引创建前指定,并且索引创建后不能更改。
replicas
代表索引副本,es可以设置多个索引的副本。副本的作用,一是提高系统的容错性,当某个节点的某个分片损坏或丢失时可以从副本中恢复,二是提高es的查询效率,es会自动对搜索请求进行负载均衡。
recovery
代表数据恢复或叫数据重新分布,es在有节点加入或退出时会根据机器的负载对索引分片进行重新分配,挂掉的节点重新启动时也会进行数据恢复。
river
代表es的一个数据源,也是其他存储方式(如:数据库)同步数据到es的一个方法。它是以插件方式存在的一个es服务,通过读取river中的数据并把它索引到es中,官方的river有couchDB的,RabbitMQ的,Twitter的,Wikipedia的。
gateway
代表es索引快照的存储方式。es默认是先把索引存放到内存中,当内存满了时再持久化到本地硬盘。gateway对索引快照进行存储,当这个es集群关闭再重新启动时,就会从gateway中读取索引备份数据。es支持多种类型的gateway,有本地文件系统(默认),分布式文件系统,Hadoop的HDFS和amazon的s3云存储服务。
discovery.zen
代表es的自动发现节点机制。es是一个基于p2p的系统,它先通过广播寻找存在的节点,再通过多播协议来进行节点之间的通信,同时也支持点对点的交互。
Transport
代表es内部节点或集群与客户端的交互方式。默认内部是使用tcp协议进行交互,同时它支持http协议(json格式)、thrift、servlet、memcached、zeroMQ等的传输协议(通过插件方式集成)。

作者:旁观者
来源链接:https://www.cnblogs.com/zhengyun_ustc/p/55solution6.html
版权声明:
1、JavaClub(https://www.javaclub.cn)以学习交流为目的,由作者投稿、网友推荐和小编整理收藏优秀的IT技术及相关内容,包括但不限于文字、图片、音频、视频、软件、程序等,其均来自互联网,本站不享有版权,版权归原作者所有。
2、本站提供的内容仅用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人及本网站的合法权利。
3、本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站(javaclubcn@163.com),我们将第一时间核实后及时予以删除。