zoukankan      html  css  js  c++  java
  • 巧用双索引避免es出现索引不存在的问题

    问题说明:

    企业级门户APP,有移动端组织架构,员工可以在app端查询公司用户信息,支持员工在通讯录中多字段搜索(姓名/工号/手机号/邮箱/......),模糊搜索。我们这边是使用elasticsearch来存储员工信息,

    以便于实现这种搜索功能。

     

    正常把员工信息导入到es中,搜索也不会有问题。但是我们的产品是个企业级产品,专门服务于不同的企业客户的,解决客户各式各样的需求。比如,正常员工的字段有姓名/工号手机号/邮箱/性别等,这也是我们产品中标准的字段,无法满足客户的个性化需求,例如客户需求:

    • 客户A:我们有职级字段,怎么办
    • 客户B:我们有昵称字段,怎么办
    • 客户C:我们有爱好字段,怎么办
    • ...........

    如上所述,不同企业有不同的字段,为了满足客户可以自定义属于他们自己的字段,我们设计了个性化字段的功能。

     个性化字段:企业可以在自己的租户下自定义此租户下员工字段,增加代码的灵活性(这个设计以后有机会在写一篇)
     

    在个性化字段中,可以控制某些字段是否能够在es中搜索,要支持es中搜索,那么就需要把字段初始化在es的索引中,当添加字段的时候就会到对应索引中增加字段。为了防止意外,我们提供了web端操作的界面,管理员可以手动重置整个租户的索引以及数据。在重建重新初始化期间,如果恰好用户正在使用搜索功能,可能会出现索引不存在或者员工搜索不到数据等问题。

    本文就是来说明下在es初始化期间怎么保证数据能够正常访问,方案:以空间换时间,引入双索引的来处理

    思路来源:在看《redis设计与实现》一书的时候,其中说明redis对字典的哈希表执行rehash的时候就是有两个hash表交换处理的,分别是ht[0]和ht[1]

     

    双索引设计

    系统中默认两个索引index0和index1,如果正在提供服务的索引是index0 ,那么在下次初始化重建的时候就会初始化index1, 待初始化完成后则index1对外提供服务,删除索引index0。如此反复循环。

    1. 名词解释

    下面单独是说明0租户下的索引设计,多租户下区分各个redis key和es索引即可

    • elasticsearch中有两个索引,一个index0 (员工索引0,默认),另一个index1(员工索引1)

    • ajisun:elastic:employee:init0(有过期时间的单key,判断此租户是否正在初始化中,)

    • ajisun:elastic:employee,0(hash key,存储0租户正在使用的索引)

     

    2. 索引重建步骤:
    1. 通过 redis keyajisun:elastic:employee:init0 来判断当前租户有没有正在初始化中,如果有,则忽略此次操作,如果没有初始化,请看第2步。

    2. 通过redis hash key ajisun:elastic:employee,{tenantId} 获取当前租户使用的es索引=oldIndex

    3. 如果oldIndex为空,就在redis中设置租户默认索引redis.hshPut("ajisun:elastic:employee", 0, "index0"), 那么即将初始化重建的新索引newIndex是 “index1”

    4. 如果oldIndex不为空,那么当前正在提供服务的索引是oldIndex,即将要初始化重建的新索引newIndex是非oldIndex(如果oldIndex是index0,那非oldIndex是index1,反之一样)

    5. 然后设置此租户索引正在初始化的key redis.strSet("ajisun:elastic:employee:init0", newIndex, 5L, TimeUnit.MINUTES); 加过期时间防止应用奔溃,导致状态是一直是初始化中

    6. 初始化新的索引newIndex,添加数据.

    7. 删除初始化状态的redis key,redis.delKey("ajisun:elastic:employee:init0");

    8. 改变redis中租户默认索引为newIndex, redis.hshPut("ajisun:elastic:employee",0, newIndex);

    9. 删除elasticsearch中的旧索引oldIndex。

     

    流程图如下:


     


    3. 数据搜索

    搜索数据的就比较简单,直接在redis.hshGet("ajisun:elastic:employee",0) 中查找到0租户目前正在使用索引,如果为空则使用默认的索引index0搜索。

     

    4. 数据修改/存储

    主要就是如果索引在初始化中,则直接把数据的修改/存储 操作新的索引上

    1. redis.hshGet("ajisun:elastic:employee",0) 中获取0租户正在使用的索引。

    2. 如果为空默认索引是index0

    3. 如果索引不为空,则获取redis缓存中redis.strGet("ajisun:elastic:employee:init0") 0租户是否为空

    4. 如果不为空,则说明正在初始化中,则保存数据的索引使用初始化中的索引

     

    以上就是针对es索引初始化期间影响正常使用的解决方案,其实没有难度的,只是提供一种思考方式,有问题欢迎提出交流。

     

    关注不迷路

    MySQL高级相关更多内容,如事务,锁,MVCC,读写分离,分库分表等还在持续更新中,欢迎关注催更。

    我是阿纪,用输出倒逼输入而持续学习,持续分享技术系列文章,以及全网值得收藏好文,欢迎关注公众号,做一个持续成长的技术人。

  • 相关阅读:
    畅通工程(hdu1232)并查集
    qsort函数的用法
    二叉搜索树(hdu3791)
    Binary Tree Traversals(HDU1710)二叉树的简单应用
    Safe Or Unsafe(hdu2527)哈弗曼VS优先队列
    山东省第四届acm解题报告(部分)
    Points on Cycle (hdu1700,几何)
    A计划 hdu2102(bfs一般题)
    杀人游戏(hdu2211)插入法
    hdu1518 Square(dfs)
  • 原文地址:https://www.cnblogs.com/sunjiguang/p/15706855.html
Copyright © 2011-2022 走看看