SlideShare una empresa de Scribd logo
1 de 65
Descargar para leer sin conexión
基于 lucene 的站内搜索实战


      Beta 技术沙龙
           http://club.blogbeta.com
          官方 twitter : @betasalon

 tangfulin <tangfulin@gmail.com>
 www.imobile.com.cn
 2009.07.26
目录
   关于手机之家
   过去:手机之家搜索 V1.0
   现在:手机之家搜索 V1.5
       需求背景
       目标
       进度
       设计
       实现
       测试
       上线,运维
       经验分享
   将来:手机之家搜索 V2.0
目录
   关于手机之家
   过去:手机之家搜索 V1.0
   现在:手机之家搜索 V1.5
       需求背景
       目标
       进度
       设计
       实现
       测试
       上线,运维
       经验分享
   将来:手机之家搜索 V2.0
关于手机之家

手机之家是一个旨在提供全方位的手机相关服务的资讯类网站。在 7 年的

时间里,手机之家从无到有,已经发展成为极具人气、最受关注的手机产

品资讯网站。



目前已有的一些统计数据:

●a. 1100w+ 用户
●b. 3000w+ 帖子

●c. 1.1TB+ 附件

●d. 780w+ Page View/ 每天

●e. 5~10w 在线用户 /15 分钟
目录
   关于手机之家
   过去:手机之家搜索 V1.0
   现在:手机之家搜索 V1.5
       需求背景
       目标
       进度
       设计
       实现
       测试
       上线,运维
       经验分享
   将来:手机之家搜索 V2.0
手机之家的搜索 V1.0(1/3)
   产品大全搜索
   新闻 CMS  搜索
   论坛搜索(默认只搜索标题)
   论坛帖子及回复搜索
   手机铃声,主题,电子书,软件搜索
   二手交易搜索
   其它版块的搜索
手机之家的搜索 V1.0(2/3)

    基本实现了多个业务模块需要的搜索功能
    
        不同的搜索字段
    
        不同的排序方式
    
        不同的更新频率
    
        Java 多进程,多线程实现
手机之家的搜索 V1.0(3/3)
   运行概况
       Dev by chaoqian (http://www.longker.org/)
       最初基于 Lucene 2.2 ,当前 2.4.1
       开发时间: 07 年 12 月- 08 年 4 月
       08 年 12 月随新版系统上线
       部署在 Imobile-SV39-A49 上:
        • X86_64 , 8 cpu @ 2.50GHz , 32G mem
        • CentOS release 5.2, JDK64 1.6,
       搜索: 35+ 万查询 / 天,高峰期 > 20 次 /s
       更新: 平均 15 条 / 分钟
目录
   关于手机之家
   过去:手机之家搜索 V1.0
   现在:手机之家搜索 V1.5
       需求背景
       目标
       进度
       设计
       实现
       测试
       上线,运维
       经验分享
   将来:手机之家搜索 V2.0
目录
   关于手机之家
   过去:手机之家搜索 V1.0
   现在:手机之家搜索 V1.5
       需求背景
       目标
       进度
       设计
       实现
       测试
       上线,运维
       经验分享
   将来:手机之家搜索 V2.0
需求背景 (1/3)

    重建索引
    
        索引字段变更
    
        分词算法变更
    
        搜索结果异常(记录重复,记录丢失)
    
        索引文件意外损坏
    
        V1.0 :半手工重建,重建过程需人工参与,重建过程中
        不能正常更新
    
        V1.5 :自动重建,重建过程中正常更新原来的索引
需求背景 (2/3)

    缩短更新周期(及时更新)
    
        Google 更新手机之家内容的周期为 30 分钟左右
    
        V1.0 索引更新周期为 10 - 15 分钟左右
    
        V1.5 预期更新周期为 3 分钟,实际为 1-5 分钟
需求背景 (3/3)
   搜索大索引( V1.5 )
       3300+ 万条记录的一个库, xml 原始文件 14G
       V1.0 索引文件为 13 G ,无法快速更新
       V1.5 索引文件为 3.9G (还是无法快速更新?)
       V1.5 完整重建一次: 140 分钟
目录
   关于手机之家
   过去:手机之家搜索 V1.0
   现在:手机之家搜索 V1.5
       需求背景
       目标
       进度
       设计
       实现
       测试
       上线,运维
       经验分享
   将来:手机之家搜索 V2.0
目标

    及时更新( 3 分钟)

    快速重建( < 2 小时)

    可配置(拥抱需求变化)

    可监控(运维友好)

    SLA :永远可写,永远可读,异常的时候唯一的表现是
    更新延迟

    高性能,能承受较大的流量,并发压力
目录
   关于手机之家
   过去:手机之家搜索 V1.0
   现在:手机之家搜索 V1.5
       需求背景
       目标
       进度
       设计
       实现
       测试
       上线,运维
       经验分享
   将来:手机之家搜索 V2.0
进度

    2009 年 4 月 1 号 search 2.0 init

    4 月 12 号,修改版本号为 1.5

    6 月 1 号, search 1.5 在线上试运行

    6 月 22 号,正式替换原来的搜索进程
目录
   关于手机之家
   过去:手机之家搜索 V1.0
   现在:手机之家搜索 V1.5
       需求背景
       目标
       进度
       设计
       实现
       测试
       上线,运维
       经验分享
   将来:手机之家搜索 V2.0
设计 (1/8)

    分离索引与存储,二次读取

    分离读与写

    分离 update 和 rebuild

    拆分大库和小库

    new open 小库(小库滚动), reopen 大库

    新索引预热

    更多: http://blog.fulin.org/category/tech/lucene
设计 (2/8) 分离索引与存储,二次读取
   索引里只存储 id ,其他的字段只索引不存储。
   优点:
       保持索引的大小为一个可接受的范围
       提高索引读取速度
       提高索引 cache 效率
   缺点:搜索时需要额外的请求来获取其它必须的字段
    ( lucene + db 方案)
   衍生项目: blackdb , memcache 协议 + bdbJE 存储
设计 (3/8) 分离读与写

    优点:
    
        降低编程复杂度
    
        保证搜索服务的可用性,和可扩展性(可以将索引文件
        分发到多台机器上,同时对外提供服务)
    
        提升索引更新速度

    缺点:
    • 需要移动索引文件
    • 需要额外的索引更新逻辑( reopen )
    • 无法使用当前设计中的 lucene 的 real-time search
设计 (4/8) 分离       update 和 rebuild


    Rebuild 的同时, update 正常更新

    Rebuild 需要将重建这段时间的更新计入新的索引中

    Rebuild 完成后,通知 update 切换到新索引上来,并
    继续更新

    进程间通信,当前使用最原始的基于文件的方式
设计 (5/8) 拆分大库和小库

    保证及时更新的同时,减少索引频繁同步(由写索引同
    步到读索引)带来的 io 压力

    更新频率
    • 小库(最近更新库) 1 分钟
    • 大库(历史库) 1 天到 1 周,可配置

    并行搜索,加速搜索速度

    问题: group by
设计 (6/8) 拆分大库和小库(续)

    增加新记录:
    
        增加到小库

    更新记录:
    
        从大库中删除(标记删除)
    
        从小库中删除(物理删除)
    
        增加到小库

    删除记录
    
        从大库中删除(标记删除)
    
        从小库中删除(物理删除)

    定期合并小库到大库,并清空小库
设计 (7/8) 搜索端索引更新

    小库每次同步到一个新的文件夹中

    保留最近打开的 n (2) 份小库索引目录

    检测到新的索引到达,关闭一个最旧的,打开新的,预
    热后标识为可用

    检测到新的小库到达, reopen 大库(为了逻辑上的简
    单起见,大小库同步更新)
设计 (8/8) 新索引预热

    目的:消除新打开的索引上前几次搜索慢的问题

    实现:
    • 过去:遍历一遍新打开的索引,将数据都读入内存
     • 引起 gc ,导致搜索暂停
     • 对 lucene 内置的 cache 无贡献
    • 现在:搜几个热门的词,并遍历结果集
    • 将来:使用原来的 cache 填充新的 cache

    预热完成后,再投入使用
目录
   关于手机之家
   过去:手机之家搜索 V1.0
   现在:手机之家搜索 V1.5
       需求背景
       目标
       进度
       设计
       实现
       测试
       上线,运维
       经验分享
   将来:手机之家搜索 V2.0
实现 (1/8)
                                         IndexRebuilder
    搜索管理后台
 发出开始重建索引命令         IndexReceiver
  cron 发送重建数据
                              Rebuild
                              xml data
                    端口
                    1986
                               Update
                              xml data   IndexUpdater

  DAL 数据更新                                                配置文件
  同步通知搜索


                   Searcher

  搜索客户端调用
  Searcher 的 API     端口
                     1985
实现 (2/8)IndexReceiver
                                          IndexRebuilder
     搜索管理后台        IndexReceiver
  发出开始重建索引命令
   cron 发送重建数据
                               Rebuild
                               xml data
                      端口
                      1986
                                Update
                               xml data   IndexUpdater

   DAL 数据更新                                                配置文件
   同步通知搜索


                    Searcher

  搜索客户端调用
  Searcher 的 API      端口
                      1985
实现 (2/8)IndexReceiver

    By Java , Daemon 程序

    监听端口,使用 SCGI 通讯协议

    使用 Monkey 为底层 NIO 处理框架

    接收客户端 post 过来的数据,并写入对应的目录

    Update 和 rebuild 共用

    为了保证原子性,先写入 .0.***.xml ,写入完成后,再 rename

    Receiver 只负责写入, updater 和 rebuilder 稍后负责删除(备份)

    对外提供服务,所以尽可能简单,单独进程
实现 (3/8)IndexUpdater
                                         IndexRebuilder
     搜索管理后台
  发出开始重建索引命令
   cron 发送重建数据
                              Rebuild
                              xml data
                    端口
                    1986
                               Update
                                         IndexUpdater
                              xml data

   DAL 数据更新                                               配置文件
   同步通知搜索


                   Searcher

  搜索客户端调用
  Searcher 的 API     端口
                     1985
实现 (3/8)IndexUpdater

    By Java , Daemon 程序

    多个索引共用,每个索引起一个线程

    可根据需要随时停止或启动单个索引更新的线程

    AddShutdownHook 退出前 close 所有打开的 IndexWriter

    功能:
    • 更新新数据到当前索引
    • 合并大小库
    • 拷贝当前索引的快照供搜索使用
    • 切换 rebuild 出来的新索引
实现 (4/8)IndexRebuilder
                                     IndexRebuilder

     搜索管理后台
  发出开始重建索引命令
   cron 发送重建数据
                              Rebuild
                              xml data
                    端口
                    1986
                               Update
                              xml data

   DAL 数据更新                                           配置文件
   同步通知搜索


                   Searcher

  搜索客户端调用
  Searcher 的 API     端口
                     1985
实现 (4/8)IndexRebuilder

     By Java , Daemon 程序

     多个索引共用,每个索引一个线程

     重建索引时序图:
                                                                 Receiver 接到通
                                                                 知,停止抄送
                                                                 updater 数据。
客户端发送开                 客户端发送重   客户端发送结                           重建过程结束
始重建标识                  建索引的数据   束重建标识

         Receiver 开始抄送
         update 数据到                                                              receiver
         rebuild-update
                                                            Updater 接到
          Updater 正常                                        通知,切换索
    T0




                                  T1


                                         T2


                                                  T3

                                                       T4




                                                                         T5
          更新                                                引。完成后通               updater
                                                            知 receiver

          Rebuilder                       Rebuilder    Rebuilder 处理完 t0
          开始工作                            处理完重         到 当前的更新数据,               rebuilder
                                          建数据          通知 updater ,然后
                                                       自己退出
开始重建                            重建数据            重建完成                            时间线
                                接收完毕
实现 (5/8)IndexRebuilder

    切换索引过程
    • Updater 删除自己当前的索引和未更新完的 xml 文件
    • Updater 将 rebuilder 的索引和 rebuild-update 的 xml 文件 “据为己有”
    • 通知 receiver 停止抄送
    • 继续正常的数据更新过程

    可以证明这个过程中,不会有数据丢失,也不会有数据重复
    • 前提: updater 的 xml 文件和 rebuild-update 的 xml 文件是完全相
      同的(包括文件名和数据)
    • t3-t4 : 数据来自 rebuild-update
    • t4-t5 : rebuild-update 中的数据可以被直接忽略
实现 (6/8)Transfer

     搜索管理后台
  发出开始重建索引命令
   cron 发送重建数据
                              Rebuild
                              xml data
                    端口
                    1986
                               Update
                              xml data

   DAL 数据更新                                     配置文件
   同步通知搜索


                   Searcher              Transfer
  搜索客户端调用
  Searcher 的 API     端口
                     1985
实现 (6/8)Transfer

    Bash 脚本,每个 indexId 一个进程,由 ControlCenter 或 monitor 启
    动和停止

    监控索引快照目录

    快照目录下存在子目录,并且子目录中存在 copy.done.sign
    ( IndexUpdater 拷贝快照完成后 touch 的标识),则 rsync 子目录到
    search

    Rsync 的时候:先 rsync 大库快照,再 rsync 小库快照,都成功后再
    rsync 一个 trans.done.sign

    以 0 字节的 sign 文件作为标识,模拟两阶段提交,保证文件拷贝,
    传输的原子性
实现 (7/8)Searcher

     搜索管理后台
  发出开始重建索引命令
   cron 发送重建数据
                           Rebuild
                           xml data
                    端口
                    1986
                            Update
                           xml data

   DAL 数据更新                           配置文件
   同步通知搜索

                   Searcher

  搜索客户端调用
  Searcher 的 API    端口
                    1985
实现 (7/8)Searcher

    By Java , Daemon 程序

    使用 Monkey 为底层 NIO 处理框架

    使用 SCGI 通讯协议

    启动后第一件事: warmUpAllIndex

    当有新索引到达的时候,在后台打开,预热后,再投入使用

    关闭旧的 IndexSearcher 实例的前提:当前没有线程还在使用它
    • 方法:计数 ( get +1 , return -1 ,为 0 表示没有被使用)

    Stat 统计
实现 (8/8)Utils

    Cleaner
    • Bash 脚本,每个 indexId 一个进程
    • 用来删除 Searcher 已经关闭或跳过的索引

    Monitor
    • 监控系统的各个进程是否存在,如不存在,则启动一个新的进程

    ControlCenter
    • Usage: ./controlCenter.sh {start|stop|restart} {all|receiver|updater|
      rebuilder|searcher|trans|cleaner}
    •     OR: ./controlCenter.sh {start|stop|restart} {monitor|
        logSlowSearch}
    •    OR: ./controlCenter.sh {mkdirs}
目录
   关于手机之家
   过去:手机之家搜索 V1.0
   现在:手机之家搜索 V1.5
       需求背景
       目标
       进度
       设计
       实现
       测试
       上线,运维
       经验分享
   将来:手机之家搜索 V2.0
性能简单测试结果
   Apache bench
       ­n 1000 ­c 10   ( 99%    545ms     100%  32838ms )
       ­n 2000 ­c 20   ( 90%   1171ms    99%   4106ms )
             库大小: 4.1G 条目数: 3300+w 更新周期: 1 分钟
             总请求 3000 ,慢查询 ( 耗时大于 1 秒 ) 比例 4%
          
              搜索词:手机之家论坛首页的板块名,随机
          
              最长: 37s
             > 10s : 22  (索引切换, gc )
             2s­10s : 38
             1s­2s : 62
性能对比测试结果 (1/6)
   Apache bench
       库大小: 4.1G ,条目数: 3300+w ,更新周期: 1 分钟
       搜索词:手机之家论坛板块名随机
       对比条件
             停止更新与正常更新
             分配索引 1 倍大小的内存与 2 倍大小的内存
             并发 10 个与 20 个
       Document Length:     1529 bytes
       Total transferred:       3447737 bytes (1722053 bytes)
       HTML transferred:    3085737 bytes (1541053 bytes)
性能对比测试结果 (2/6)
Time taken for tests                        停止更新 正常更新
分配索引大小1倍内存             ab -n 2000 -c   20    21.85 64.17
分配索引大小1倍内存             ab -n 1000 -c   10     13.1 11.93
分配索引大小2倍内存             ab -n 2000 -c   20     22.8 22.89
分配索引大小2倍内存             ab -n 1000 -c   10    10.37 10.74

备注:单位为秒
性能对比测试结果 (3/6)
Requests per second             停止更新 正常更新
分配索引大小1倍内存 ab -n 2000 -c   20    91.52 31.17
分配索引大小1倍内存 ab -n 1000 -c   10    76.33 83.83
分配索引大小2倍内存 ab -n 2000 -c   20    87.71 87.39
分配索引大小2倍内存 ab -n 1000 -c   10    96.45 93.13
性能对比测试结果 (4/6)
Time per request                         停止更新      正常更新
                                         218.531   641.674
分配索引大小1倍内存 ab -n 2000 -c 20              10.927    32.084
                                         131.015   119.288
分配索引大小1倍内存 ab -n 1000 -c 10              13.102    11.929
                                         228.012   228.870
分配索引大小2倍内存 ab -n 2000 -c 20              11.401    11.444
                                         103.676   107.375
分配索引大小2倍内存 ab -n 1000 -c 10              10.368    10.738
备注:
[ms] (mean)
(mean, across all concurrent requests)
性能对比测试结果 (5/6)
Transfer rate                          停止更新 正常更新
分配索引大小1倍内存        ab -n 2000 -c   20    154.06  52.47
分配索引大小1倍内存        ab -n 1000 -c   10    128.46 140.98
分配索引大小2倍内存        ab -n 2000 -c   20    147.63 146.82
分配索引大小2倍内存        ab -n 1000 -c   10    162.07 156.39
备注:
(Kbytes/sec)
性能对比测试结果 (6/6)
耗时比例                          停止更新 正常更新
                              50%  59 50% 162
                              95% 905 90% 1403
分配索引大小1倍内存 ab -n 2000 -c 20   100% 1525 98% 5738
                              50%  34 50%    24
                              99% 978 98% 750
分配索引大小1倍内存 ab -n 1000 -c 10   100% 1420 100% 3600
                              50%  61 50%    41
                              95% 906 95% 988
分配索引大小2倍内存 ab -n 2000 -c 20   99% 1519 99% 1678
                              50%  28 50%    27
                              99% 744 99% 698
分配索引大小2倍内存 ab -n 1000 -c 10   100% 905 100% 764

备注:百分比 毫秒
目录
   关于手机之家
   过去:手机之家搜索 V1.0
   现在:手机之家搜索 V1.5
       需求背景
       目标
       进度
       设计
       实现
       测试
       上线,运维
       经验分享
   将来:手机之家搜索 V2.0
部署上线
   运行概况
       updater , rebuilder 部署在 Imobile-SV25-B50 上
        • IntelXeon 4 cpu @2.60GHz , 6G mem
        • Slackware 12.1, JDK32 1.6
       Search 部署在 Imobile-SV39-A49 上:
        • X86_64 , 8 cpu @ 2.50GHz , 32G mem
        • CentOS release 5.2, JDK64 1.6
       搜索: 35+ 万查询 / 天,高峰期 > 20 次 /s
       更新: 平均 15 条 / 分钟
生产环境运行观察
   Slow search  比例: >1s 1.x%; >2s 0.2%
   机器负载 : 49(search): 1~3; 50(update): <1
   内存消耗: search: ­Xms4096M ­Xmx4096M
   Cpu 消耗 :多核之间平均比较分配
   索引平均更新速度: ~1 分钟
   索引延迟率(因各种原因导致延迟更新的比例)
目录
   关于手机之家
   过去:手机之家搜索 V1.0
   现在:手机之家搜索 V1.5
       需求背景
       目标
       进度
       设计
       实现
       测试
       上线,运维
       经验分享
   将来:手机之家搜索 V2.0
开发中的一些收获 (1/5)

    FileChannel.transferTo 拷贝文件失败:
    
        Fewer than the requested number of bytes are transferred if the
        target channel is non-blocking and it has fewer than count bytes
        free in its output buffer.
    
        解决: check copied size ,断点续传
    
        根据 lucene 索引文件更新的特性 ( 每次更新一个新版本的时
        候,都会新建一个全新的文件 ) ,使用 cp -l 链接替代真实的
        大文件拷贝动作
开发中的一些收获 (2/5)
   Kill  的问题
       Never kill smart frog, don't kill ­9
       Java use Runtime.getRuntime().addShutdownHook  to do the cleaning 
        things
       Lucene IndexWriter need close!
       server  程序,都应该考虑信号捕捉和处理的问题( java  程序容易忽
        略这个问题)
开发中的一些收获 (3/5)

    更新太频繁导致的磁盘 IO 问题
    – 同一台机器目录之间同步:没有问题
    – 一拖二,一拖三

    暂时解决
    – 建索引的机器不提供搜索服务
    – rsync 限速
开发中的一些收获 (4/5)
   GC  引起的服务暂停
    
        多个索引共用 Search 进程
    
        每个索引维持了多个 searcher
    
        索引更新太过频繁: 30 秒
   暂时解决
    
        纵向拆分:将两个最大的库拆分到单独的进程
    
        减少 searcher 个数到 2  个
    
        谨慎的选择 gc 的类型,并调整 gc 的参数
            G1 改进不明显,不稳定
开发中的一些收获 (5/5)
   Java server  程序的 trouble shooting
       性能问题: jprofile
       内存问题: jmx  + jconsole
       线程问题: Thread.currentThread().setName("diffDetect­" + 
        indexId); 
    
        详细的 log : log4j
    
        常用的脚本: logslowsearch.sh
    
        开发调试阶段:方便的重新编译并重启脚本
    
        线上服务阶段:完善的监控及报警机制
目录
   关于手机之家
   过去:手机之家搜索 V1.0
   现在:手机之家搜索 V1.5
       需求背景
       目标
       进度
       设计
       实现
       测试
       上线,运维
       经验分享
   将来:手机之家搜索 V2.0
持续改进

    配置文件改动检测,自动重新加载

    更智能的处理索引字段变更

    分词算法改进

    搜索关键字数据挖掘(搜索新词自动发现)

    搜索建议,搜索联想功能

    排序算法改进

    全站整合搜索

    准实时搜索
Lucene 3
   Lucene 2.9
    • Searchable.search(Weight, Filter, Collector): collector 终于可用了
    • Added new MultiReaderHitCollector: 解决 group by
    • near real-time search via IndexWriter.getReader(): 单机方案
   Lucene 3.0
    • Del deprecated apis: 大版本升级要谨慎
    • Port to Java5: 应该会有性能的提升
   Lucene 3.1
    • Near Realtime Search (using a built in RAMDirectory): 还是单机方案
    • Complete overhaul of FieldCache API/Implementation: 等到花儿也谢了
定制功能

    在某些情况下作为数据库的替代数据源
    
        类似淘宝搜索,按多个字段筛选,过滤,排序
    
        当前解决方案:使用 sql 从数据库中选取数据
    
        问题:数据可能因为业务逻辑的设计而分散在多个不同的
        库,表中,联表查询问题,并发压力问题
    
        难点:非典型的复杂的查询条件,如 group by
参考资料

    Lucene
    
        http://lucene.apache.org/
    
        http://lucene.apache.org/java/2_4_1/api/index.html

    中文分词
    
        http://code.google.com/p/paoding/
    
        http://code.google.com/p/imdict-chinese-analyzer/
    
        http://code.google.com/p/mmseg4j/

    Monkey ( Java 底层异步网络 IO 框架)

    DAL
关于我们

    关于 imobile
    
        网站首页 http://www.imobile.com.cn/
    
        关于  http://www.imobile.com.cn/about.html

    Longker ( V1.0 版本)
    
        http://www.longker.org/

    关于我( V1.5 版本)
    
        http://www.fulin.org/
    
        http://twitter.com/tangfl
更多讨论

    Java GC  的问题
   巨大的索引库与频繁更新如何共存
   全站整合搜索,后台技术实现与前台表现设计
   更多

Más contenido relacionado

La actualidad más candente

Orclrecove 1 pd-prm-dul testing for oracle database recovery_20141030_biot_wang
Orclrecove 1 pd-prm-dul testing for oracle database recovery_20141030_biot_wangOrclrecove 1 pd-prm-dul testing for oracle database recovery_20141030_biot_wang
Orclrecove 1 pd-prm-dul testing for oracle database recovery_20141030_biot_wangmaclean liu
 
自由軟體鑄造場_20111023_Subversion版本控制系統之操作_曾義峰(ant)
自由軟體鑄造場_20111023_Subversion版本控制系統之操作_曾義峰(ant)自由軟體鑄造場_20111023_Subversion版本控制系統之操作_曾義峰(ant)
自由軟體鑄造場_20111023_Subversion版本控制系統之操作_曾義峰(ant)OpenFoundry
 
Oracle管理藝術第1章 在Linux作業體統安裝Oracle 11g
Oracle管理藝術第1章 在Linux作業體統安裝Oracle 11gOracle管理藝術第1章 在Linux作業體統安裝Oracle 11g
Oracle管理藝術第1章 在Linux作業體統安裝Oracle 11gChien Chung Shen
 
Oracle试题Exam Adminv1.1
Oracle试题Exam Adminv1.1Oracle试题Exam Adminv1.1
Oracle试题Exam Adminv1.1Zianed Hou
 
PostgreSQL 9 1 新特性
PostgreSQL 9 1 新特性PostgreSQL 9 1 新特性
PostgreSQL 9 1 新特性March Liu
 

La actualidad más candente (7)

Orclrecove 1 pd-prm-dul testing for oracle database recovery_20141030_biot_wang
Orclrecove 1 pd-prm-dul testing for oracle database recovery_20141030_biot_wangOrclrecove 1 pd-prm-dul testing for oracle database recovery_20141030_biot_wang
Orclrecove 1 pd-prm-dul testing for oracle database recovery_20141030_biot_wang
 
自由軟體鑄造場_20111023_Subversion版本控制系統之操作_曾義峰(ant)
自由軟體鑄造場_20111023_Subversion版本控制系統之操作_曾義峰(ant)自由軟體鑄造場_20111023_Subversion版本控制系統之操作_曾義峰(ant)
自由軟體鑄造場_20111023_Subversion版本控制系統之操作_曾義峰(ant)
 
Oracle管理藝術第1章 在Linux作業體統安裝Oracle 11g
Oracle管理藝術第1章 在Linux作業體統安裝Oracle 11gOracle管理藝術第1章 在Linux作業體統安裝Oracle 11g
Oracle管理藝術第1章 在Linux作業體統安裝Oracle 11g
 
Oracle 索引介紹
Oracle 索引介紹Oracle 索引介紹
Oracle 索引介紹
 
Cdc@ganji.com
Cdc@ganji.comCdc@ganji.com
Cdc@ganji.com
 
Oracle试题Exam Adminv1.1
Oracle试题Exam Adminv1.1Oracle试题Exam Adminv1.1
Oracle试题Exam Adminv1.1
 
PostgreSQL 9 1 新特性
PostgreSQL 9 1 新特性PostgreSQL 9 1 新特性
PostgreSQL 9 1 新特性
 

Similar a 基于Lucene的站内搜索 Beta

数据库持续集成
数据库持续集成数据库持续集成
数据库持续集成wait4friend
 
从运维系统的开发谈安全架构设计
从运维系统的开发谈安全架构设计从运维系统的开发谈安全架构设计
从运维系统的开发谈安全架构设计mysqlops
 
Times Ten Training
Times Ten TrainingTimes Ten Training
Times Ten TrainingLi Chen
 
开源应用日志收集系统
开源应用日志收集系统开源应用日志收集系统
开源应用日志收集系统klandor
 
深入研究 Windows 系統服務 效能調校與故障排除
深入研究 Windows 系統服務    效能調校與故障排除深入研究 Windows 系統服務    效能調校與故障排除
深入研究 Windows 系統服務 效能調校與故障排除5045033
 
網站設計100步
網站設計100步網站設計100步
網站設計100步evercislide
 
Ocean base海量结构化数据存储系统 hadoop in china
Ocean base海量结构化数据存储系统 hadoop in chinaOcean base海量结构化数据存储系统 hadoop in china
Ocean base海量结构化数据存储系统 hadoop in chinaknuthocean
 
Subversion
SubversionSubversion
Subversioni7Xh
 
Web请求异步处理和海量数据即时分析在淘宝开放平台的实践
Web请求异步处理和海量数据即时分析在淘宝开放平台的实践Web请求异步处理和海量数据即时分析在淘宝开放平台的实践
Web请求异步处理和海量数据即时分析在淘宝开放平台的实践mysqlops
 
Software Engineer Talk
Software Engineer TalkSoftware Engineer Talk
Software Engineer TalkLarry Cai
 
高性能队列Fqueue的设计和使用实践
高性能队列Fqueue的设计和使用实践高性能队列Fqueue的设计和使用实践
高性能队列Fqueue的设计和使用实践孙立
 
鹰眼下的淘宝_EagleEye with Taobao
鹰眼下的淘宝_EagleEye with Taobao鹰眼下的淘宝_EagleEye with Taobao
鹰眼下的淘宝_EagleEye with Taobaoterryice
 
基于Symfony框架下的快速企业级应用开发
基于Symfony框架下的快速企业级应用开发基于Symfony框架下的快速企业级应用开发
基于Symfony框架下的快速企业级应用开发mysqlops
 
Java 的開放原碼全文搜尋技術 - Lucene
Java 的開放原碼全文搜尋技術 - LuceneJava 的開放原碼全文搜尋技術 - Lucene
Java 的開放原碼全文搜尋技術 - Lucene建興 王
 
Kubernetes project update and how to contribute
Kubernetes project update and how to contributeKubernetes project update and how to contribute
Kubernetes project update and how to contributeinwin stack
 

Similar a 基于Lucene的站内搜索 Beta (20)

数据库持续集成
数据库持续集成数据库持续集成
数据库持续集成
 
从运维系统的开发谈安全架构设计
从运维系统的开发谈安全架构设计从运维系统的开发谈安全架构设计
从运维系统的开发谈安全架构设计
 
Java@taobao
Java@taobaoJava@taobao
Java@taobao
 
Times Ten Training
Times Ten TrainingTimes Ten Training
Times Ten Training
 
开源应用日志收集系统
开源应用日志收集系统开源应用日志收集系统
开源应用日志收集系统
 
深入研究 Windows 系統服務 效能調校與故障排除
深入研究 Windows 系統服務    效能調校與故障排除深入研究 Windows 系統服務    效能調校與故障排除
深入研究 Windows 系統服務 效能調校與故障排除
 
Lucene实践
Lucene实践Lucene实践
Lucene实践
 
網站設計100步
網站設計100步網站設計100步
網站設計100步
 
Exodus2 大局观
Exodus2 大局观Exodus2 大局观
Exodus2 大局观
 
Ocean base海量结构化数据存储系统 hadoop in china
Ocean base海量结构化数据存储系统 hadoop in chinaOcean base海量结构化数据存储系统 hadoop in china
Ocean base海量结构化数据存储系统 hadoop in china
 
Subversion
SubversionSubversion
Subversion
 
Web请求异步处理和海量数据即时分析在淘宝开放平台的实践
Web请求异步处理和海量数据即时分析在淘宝开放平台的实践Web请求异步处理和海量数据即时分析在淘宝开放平台的实践
Web请求异步处理和海量数据即时分析在淘宝开放平台的实践
 
Software Engineer Talk
Software Engineer TalkSoftware Engineer Talk
Software Engineer Talk
 
高性能队列Fqueue的设计和使用实践
高性能队列Fqueue的设计和使用实践高性能队列Fqueue的设计和使用实践
高性能队列Fqueue的设计和使用实践
 
敦群學院-SharePoint精英計畫-系統開發-Day 3
敦群學院-SharePoint精英計畫-系統開發-Day 3敦群學院-SharePoint精英計畫-系統開發-Day 3
敦群學院-SharePoint精英計畫-系統開發-Day 3
 
鹰眼下的淘宝_EagleEye with Taobao
鹰眼下的淘宝_EagleEye with Taobao鹰眼下的淘宝_EagleEye with Taobao
鹰眼下的淘宝_EagleEye with Taobao
 
基于Symfony框架下的快速企业级应用开发
基于Symfony框架下的快速企业级应用开发基于Symfony框架下的快速企业级应用开发
基于Symfony框架下的快速企业级应用开发
 
Java 的開放原碼全文搜尋技術 - Lucene
Java 的開放原碼全文搜尋技術 - LuceneJava 的開放原碼全文搜尋技術 - Lucene
Java 的開放原碼全文搜尋技術 - Lucene
 
1~60
1~601~60
1~60
 
Kubernetes project update and how to contribute
Kubernetes project update and how to contributeKubernetes project update and how to contribute
Kubernetes project update and how to contribute
 

Más de fulin tang

雪球大数据体系实践
雪球大数据体系实践雪球大数据体系实践
雪球大数据体系实践fulin tang
 
雪球服务化实践历程.Print
雪球服务化实践历程.Print雪球服务化实践历程.Print
雪球服务化实践历程.Printfulin tang
 
订阅互联网
订阅互联网订阅互联网
订阅互联网fulin tang
 
我的奋斗 @ weibo
我的奋斗 @ weibo我的奋斗 @ weibo
我的奋斗 @ weibofulin tang
 
一个Nosql的故事
一个Nosql的故事一个Nosql的故事
一个Nosql的故事fulin tang
 
Redis大数据之路 dtcc-唐福林
Redis大数据之路 dtcc-唐福林Redis大数据之路 dtcc-唐福林
Redis大数据之路 dtcc-唐福林fulin tang
 
新浪微博开放平台中的 Redis 实践
新浪微博开放平台中的 Redis 实践新浪微博开放平台中的 Redis 实践
新浪微博开放平台中的 Redis 实践fulin tang
 
Gizzard, DAL and more
Gizzard, DAL and moreGizzard, DAL and more
Gizzard, DAL and morefulin tang
 
音乐搜索的极致
音乐搜索的极致音乐搜索的极致
音乐搜索的极致fulin tang
 
Voldemort Intro Tangfl
Voldemort Intro TangflVoldemort Intro Tangfl
Voldemort Intro Tangflfulin tang
 
毕业设计-Slide
毕业设计-Slide毕业设计-Slide
毕业设计-Slidefulin tang
 

Más de fulin tang (12)

雪球大数据体系实践
雪球大数据体系实践雪球大数据体系实践
雪球大数据体系实践
 
雪球服务化实践历程.Print
雪球服务化实践历程.Print雪球服务化实践历程.Print
雪球服务化实践历程.Print
 
订阅互联网
订阅互联网订阅互联网
订阅互联网
 
我的奋斗 @ weibo
我的奋斗 @ weibo我的奋斗 @ weibo
我的奋斗 @ weibo
 
一个Nosql的故事
一个Nosql的故事一个Nosql的故事
一个Nosql的故事
 
Redis大数据之路 dtcc-唐福林
Redis大数据之路 dtcc-唐福林Redis大数据之路 dtcc-唐福林
Redis大数据之路 dtcc-唐福林
 
新浪微博开放平台中的 Redis 实践
新浪微博开放平台中的 Redis 实践新浪微博开放平台中的 Redis 实践
新浪微博开放平台中的 Redis 实践
 
Redis 坑
Redis 坑Redis 坑
Redis 坑
 
Gizzard, DAL and more
Gizzard, DAL and moreGizzard, DAL and more
Gizzard, DAL and more
 
音乐搜索的极致
音乐搜索的极致音乐搜索的极致
音乐搜索的极致
 
Voldemort Intro Tangfl
Voldemort Intro TangflVoldemort Intro Tangfl
Voldemort Intro Tangfl
 
毕业设计-Slide
毕业设计-Slide毕业设计-Slide
毕业设计-Slide
 

基于Lucene的站内搜索 Beta

  • 1. 基于 lucene 的站内搜索实战 Beta 技术沙龙 http://club.blogbeta.com 官方 twitter : @betasalon tangfulin <tangfulin@gmail.com> www.imobile.com.cn 2009.07.26
  • 2. 目录  关于手机之家  过去:手机之家搜索 V1.0  现在:手机之家搜索 V1.5  需求背景  目标  进度  设计  实现  测试  上线,运维  经验分享  将来:手机之家搜索 V2.0
  • 3. 目录  关于手机之家  过去:手机之家搜索 V1.0  现在:手机之家搜索 V1.5  需求背景  目标  进度  设计  实现  测试  上线,运维  经验分享  将来:手机之家搜索 V2.0
  • 4.
  • 6. 目录  关于手机之家  过去:手机之家搜索 V1.0  现在:手机之家搜索 V1.5  需求背景  目标  进度  设计  实现  测试  上线,运维  经验分享  将来:手机之家搜索 V2.0
  • 7. 手机之家的搜索 V1.0(1/3)  产品大全搜索  新闻 CMS  搜索  论坛搜索(默认只搜索标题)  论坛帖子及回复搜索  手机铃声,主题,电子书,软件搜索  二手交易搜索  其它版块的搜索
  • 8. 手机之家的搜索 V1.0(2/3)  基本实现了多个业务模块需要的搜索功能  不同的搜索字段  不同的排序方式  不同的更新频率  Java 多进程,多线程实现
  • 9. 手机之家的搜索 V1.0(3/3)  运行概况  Dev by chaoqian (http://www.longker.org/)  最初基于 Lucene 2.2 ,当前 2.4.1  开发时间: 07 年 12 月- 08 年 4 月  08 年 12 月随新版系统上线  部署在 Imobile-SV39-A49 上: • X86_64 , 8 cpu @ 2.50GHz , 32G mem • CentOS release 5.2, JDK64 1.6,  搜索: 35+ 万查询 / 天,高峰期 > 20 次 /s  更新: 平均 15 条 / 分钟
  • 10. 目录  关于手机之家  过去:手机之家搜索 V1.0  现在:手机之家搜索 V1.5  需求背景  目标  进度  设计  实现  测试  上线,运维  经验分享  将来:手机之家搜索 V2.0
  • 11. 目录  关于手机之家  过去:手机之家搜索 V1.0  现在:手机之家搜索 V1.5  需求背景  目标  进度  设计  实现  测试  上线,运维  经验分享  将来:手机之家搜索 V2.0
  • 12. 需求背景 (1/3)  重建索引  索引字段变更  分词算法变更  搜索结果异常(记录重复,记录丢失)  索引文件意外损坏  V1.0 :半手工重建,重建过程需人工参与,重建过程中 不能正常更新  V1.5 :自动重建,重建过程中正常更新原来的索引
  • 13. 需求背景 (2/3)  缩短更新周期(及时更新)  Google 更新手机之家内容的周期为 30 分钟左右  V1.0 索引更新周期为 10 - 15 分钟左右  V1.5 预期更新周期为 3 分钟,实际为 1-5 分钟
  • 14. 需求背景 (3/3)  搜索大索引( V1.5 )  3300+ 万条记录的一个库, xml 原始文件 14G  V1.0 索引文件为 13 G ,无法快速更新  V1.5 索引文件为 3.9G (还是无法快速更新?)  V1.5 完整重建一次: 140 分钟
  • 15. 目录  关于手机之家  过去:手机之家搜索 V1.0  现在:手机之家搜索 V1.5  需求背景  目标  进度  设计  实现  测试  上线,运维  经验分享  将来:手机之家搜索 V2.0
  • 16. 目标  及时更新( 3 分钟)  快速重建( < 2 小时)  可配置(拥抱需求变化)  可监控(运维友好)  SLA :永远可写,永远可读,异常的时候唯一的表现是 更新延迟  高性能,能承受较大的流量,并发压力
  • 17. 目录  关于手机之家  过去:手机之家搜索 V1.0  现在:手机之家搜索 V1.5  需求背景  目标  进度  设计  实现  测试  上线,运维  经验分享  将来:手机之家搜索 V2.0
  • 18. 进度  2009 年 4 月 1 号 search 2.0 init  4 月 12 号,修改版本号为 1.5  6 月 1 号, search 1.5 在线上试运行  6 月 22 号,正式替换原来的搜索进程
  • 19. 目录  关于手机之家  过去:手机之家搜索 V1.0  现在:手机之家搜索 V1.5  需求背景  目标  进度  设计  实现  测试  上线,运维  经验分享  将来:手机之家搜索 V2.0
  • 20. 设计 (1/8)  分离索引与存储,二次读取  分离读与写  分离 update 和 rebuild  拆分大库和小库  new open 小库(小库滚动), reopen 大库  新索引预热  更多: http://blog.fulin.org/category/tech/lucene
  • 21. 设计 (2/8) 分离索引与存储,二次读取  索引里只存储 id ,其他的字段只索引不存储。  优点:  保持索引的大小为一个可接受的范围  提高索引读取速度  提高索引 cache 效率  缺点:搜索时需要额外的请求来获取其它必须的字段 ( lucene + db 方案)  衍生项目: blackdb , memcache 协议 + bdbJE 存储
  • 22. 设计 (3/8) 分离读与写  优点:  降低编程复杂度  保证搜索服务的可用性,和可扩展性(可以将索引文件 分发到多台机器上,同时对外提供服务)  提升索引更新速度  缺点: • 需要移动索引文件 • 需要额外的索引更新逻辑( reopen ) • 无法使用当前设计中的 lucene 的 real-time search
  • 23. 设计 (4/8) 分离 update 和 rebuild  Rebuild 的同时, update 正常更新  Rebuild 需要将重建这段时间的更新计入新的索引中  Rebuild 完成后,通知 update 切换到新索引上来,并 继续更新  进程间通信,当前使用最原始的基于文件的方式
  • 24. 设计 (5/8) 拆分大库和小库  保证及时更新的同时,减少索引频繁同步(由写索引同 步到读索引)带来的 io 压力  更新频率 • 小库(最近更新库) 1 分钟 • 大库(历史库) 1 天到 1 周,可配置  并行搜索,加速搜索速度  问题: group by
  • 25. 设计 (6/8) 拆分大库和小库(续)  增加新记录:  增加到小库  更新记录:  从大库中删除(标记删除)  从小库中删除(物理删除)  增加到小库  删除记录  从大库中删除(标记删除)  从小库中删除(物理删除)  定期合并小库到大库,并清空小库
  • 26. 设计 (7/8) 搜索端索引更新  小库每次同步到一个新的文件夹中  保留最近打开的 n (2) 份小库索引目录  检测到新的索引到达,关闭一个最旧的,打开新的,预 热后标识为可用  检测到新的小库到达, reopen 大库(为了逻辑上的简 单起见,大小库同步更新)
  • 27. 设计 (8/8) 新索引预热  目的:消除新打开的索引上前几次搜索慢的问题  实现: • 过去:遍历一遍新打开的索引,将数据都读入内存 • 引起 gc ,导致搜索暂停 • 对 lucene 内置的 cache 无贡献 • 现在:搜几个热门的词,并遍历结果集 • 将来:使用原来的 cache 填充新的 cache  预热完成后,再投入使用
  • 28. 目录  关于手机之家  过去:手机之家搜索 V1.0  现在:手机之家搜索 V1.5  需求背景  目标  进度  设计  实现  测试  上线,运维  经验分享  将来:手机之家搜索 V2.0
  • 29. 实现 (1/8) IndexRebuilder 搜索管理后台 发出开始重建索引命令 IndexReceiver cron 发送重建数据 Rebuild xml data 端口 1986 Update xml data IndexUpdater DAL 数据更新 配置文件 同步通知搜索 Searcher 搜索客户端调用 Searcher 的 API 端口 1985
  • 30. 实现 (2/8)IndexReceiver IndexRebuilder 搜索管理后台 IndexReceiver 发出开始重建索引命令 cron 发送重建数据 Rebuild xml data 端口 1986 Update xml data IndexUpdater DAL 数据更新 配置文件 同步通知搜索 Searcher 搜索客户端调用 Searcher 的 API 端口 1985
  • 31. 实现 (2/8)IndexReceiver  By Java , Daemon 程序  监听端口,使用 SCGI 通讯协议  使用 Monkey 为底层 NIO 处理框架  接收客户端 post 过来的数据,并写入对应的目录  Update 和 rebuild 共用  为了保证原子性,先写入 .0.***.xml ,写入完成后,再 rename  Receiver 只负责写入, updater 和 rebuilder 稍后负责删除(备份)  对外提供服务,所以尽可能简单,单独进程
  • 32. 实现 (3/8)IndexUpdater IndexRebuilder 搜索管理后台 发出开始重建索引命令 cron 发送重建数据 Rebuild xml data 端口 1986 Update IndexUpdater xml data DAL 数据更新 配置文件 同步通知搜索 Searcher 搜索客户端调用 Searcher 的 API 端口 1985
  • 33. 实现 (3/8)IndexUpdater  By Java , Daemon 程序  多个索引共用,每个索引起一个线程  可根据需要随时停止或启动单个索引更新的线程  AddShutdownHook 退出前 close 所有打开的 IndexWriter  功能: • 更新新数据到当前索引 • 合并大小库 • 拷贝当前索引的快照供搜索使用 • 切换 rebuild 出来的新索引
  • 34. 实现 (4/8)IndexRebuilder IndexRebuilder 搜索管理后台 发出开始重建索引命令 cron 发送重建数据 Rebuild xml data 端口 1986 Update xml data DAL 数据更新 配置文件 同步通知搜索 Searcher 搜索客户端调用 Searcher 的 API 端口 1985
  • 35. 实现 (4/8)IndexRebuilder  By Java , Daemon 程序  多个索引共用,每个索引一个线程  重建索引时序图: Receiver 接到通 知,停止抄送 updater 数据。 客户端发送开 客户端发送重 客户端发送结 重建过程结束 始重建标识 建索引的数据 束重建标识 Receiver 开始抄送 update 数据到 receiver rebuild-update Updater 接到 Updater 正常 通知,切换索 T0 T1 T2 T3 T4 T5 更新 引。完成后通 updater 知 receiver Rebuilder Rebuilder Rebuilder 处理完 t0 开始工作 处理完重 到 当前的更新数据, rebuilder 建数据 通知 updater ,然后 自己退出 开始重建 重建数据 重建完成 时间线 接收完毕
  • 36. 实现 (5/8)IndexRebuilder  切换索引过程 • Updater 删除自己当前的索引和未更新完的 xml 文件 • Updater 将 rebuilder 的索引和 rebuild-update 的 xml 文件 “据为己有” • 通知 receiver 停止抄送 • 继续正常的数据更新过程  可以证明这个过程中,不会有数据丢失,也不会有数据重复 • 前提: updater 的 xml 文件和 rebuild-update 的 xml 文件是完全相 同的(包括文件名和数据) • t3-t4 : 数据来自 rebuild-update • t4-t5 : rebuild-update 中的数据可以被直接忽略
  • 37. 实现 (6/8)Transfer 搜索管理后台 发出开始重建索引命令 cron 发送重建数据 Rebuild xml data 端口 1986 Update xml data DAL 数据更新 配置文件 同步通知搜索 Searcher Transfer 搜索客户端调用 Searcher 的 API 端口 1985
  • 38. 实现 (6/8)Transfer  Bash 脚本,每个 indexId 一个进程,由 ControlCenter 或 monitor 启 动和停止  监控索引快照目录  快照目录下存在子目录,并且子目录中存在 copy.done.sign ( IndexUpdater 拷贝快照完成后 touch 的标识),则 rsync 子目录到 search  Rsync 的时候:先 rsync 大库快照,再 rsync 小库快照,都成功后再 rsync 一个 trans.done.sign  以 0 字节的 sign 文件作为标识,模拟两阶段提交,保证文件拷贝, 传输的原子性
  • 39. 实现 (7/8)Searcher 搜索管理后台 发出开始重建索引命令 cron 发送重建数据 Rebuild xml data 端口 1986 Update xml data DAL 数据更新 配置文件 同步通知搜索 Searcher 搜索客户端调用 Searcher 的 API 端口 1985
  • 40. 实现 (7/8)Searcher  By Java , Daemon 程序  使用 Monkey 为底层 NIO 处理框架  使用 SCGI 通讯协议  启动后第一件事: warmUpAllIndex  当有新索引到达的时候,在后台打开,预热后,再投入使用  关闭旧的 IndexSearcher 实例的前提:当前没有线程还在使用它 • 方法:计数 ( get +1 , return -1 ,为 0 表示没有被使用)  Stat 统计
  • 41. 实现 (8/8)Utils  Cleaner • Bash 脚本,每个 indexId 一个进程 • 用来删除 Searcher 已经关闭或跳过的索引  Monitor • 监控系统的各个进程是否存在,如不存在,则启动一个新的进程  ControlCenter • Usage: ./controlCenter.sh {start|stop|restart} {all|receiver|updater| rebuilder|searcher|trans|cleaner} • OR: ./controlCenter.sh {start|stop|restart} {monitor| logSlowSearch} • OR: ./controlCenter.sh {mkdirs}
  • 42. 目录  关于手机之家  过去:手机之家搜索 V1.0  现在:手机之家搜索 V1.5  需求背景  目标  进度  设计  实现  测试  上线,运维  经验分享  将来:手机之家搜索 V2.0
  • 43. 性能简单测试结果  Apache bench  ­n 1000 ­c 10   ( 99%    545ms     100%  32838ms )  ­n 2000 ­c 20   ( 90%   1171ms    99%   4106ms )  库大小: 4.1G 条目数: 3300+w 更新周期: 1 分钟  总请求 3000 ,慢查询 ( 耗时大于 1 秒 ) 比例 4%  搜索词:手机之家论坛首页的板块名,随机  最长: 37s  > 10s : 22  (索引切换, gc )  2s­10s : 38  1s­2s : 62
  • 44. 性能对比测试结果 (1/6)  Apache bench  库大小: 4.1G ,条目数: 3300+w ,更新周期: 1 分钟  搜索词:手机之家论坛板块名随机  对比条件  停止更新与正常更新  分配索引 1 倍大小的内存与 2 倍大小的内存  并发 10 个与 20 个  Document Length:     1529 bytes  Total transferred:       3447737 bytes (1722053 bytes)  HTML transferred:    3085737 bytes (1541053 bytes)
  • 45. 性能对比测试结果 (2/6) Time taken for tests 停止更新 正常更新 分配索引大小1倍内存 ab -n 2000 -c 20 21.85 64.17 分配索引大小1倍内存 ab -n 1000 -c 10 13.1 11.93 分配索引大小2倍内存 ab -n 2000 -c 20 22.8 22.89 分配索引大小2倍内存 ab -n 1000 -c 10 10.37 10.74 备注:单位为秒
  • 46. 性能对比测试结果 (3/6) Requests per second 停止更新 正常更新 分配索引大小1倍内存 ab -n 2000 -c 20 91.52 31.17 分配索引大小1倍内存 ab -n 1000 -c 10 76.33 83.83 分配索引大小2倍内存 ab -n 2000 -c 20 87.71 87.39 分配索引大小2倍内存 ab -n 1000 -c 10 96.45 93.13
  • 47. 性能对比测试结果 (4/6) Time per request 停止更新 正常更新 218.531 641.674 分配索引大小1倍内存 ab -n 2000 -c 20 10.927 32.084 131.015 119.288 分配索引大小1倍内存 ab -n 1000 -c 10 13.102 11.929 228.012 228.870 分配索引大小2倍内存 ab -n 2000 -c 20 11.401 11.444 103.676 107.375 分配索引大小2倍内存 ab -n 1000 -c 10 10.368 10.738 备注: [ms] (mean) (mean, across all concurrent requests)
  • 48. 性能对比测试结果 (5/6) Transfer rate 停止更新 正常更新 分配索引大小1倍内存 ab -n 2000 -c 20 154.06 52.47 分配索引大小1倍内存 ab -n 1000 -c 10 128.46 140.98 分配索引大小2倍内存 ab -n 2000 -c 20 147.63 146.82 分配索引大小2倍内存 ab -n 1000 -c 10 162.07 156.39 备注: (Kbytes/sec)
  • 49. 性能对比测试结果 (6/6) 耗时比例 停止更新 正常更新 50% 59 50% 162 95% 905 90% 1403 分配索引大小1倍内存 ab -n 2000 -c 20 100% 1525 98% 5738 50% 34 50% 24 99% 978 98% 750 分配索引大小1倍内存 ab -n 1000 -c 10 100% 1420 100% 3600 50% 61 50% 41 95% 906 95% 988 分配索引大小2倍内存 ab -n 2000 -c 20 99% 1519 99% 1678 50% 28 50% 27 99% 744 99% 698 分配索引大小2倍内存 ab -n 1000 -c 10 100% 905 100% 764 备注:百分比 毫秒
  • 50. 目录  关于手机之家  过去:手机之家搜索 V1.0  现在:手机之家搜索 V1.5  需求背景  目标  进度  设计  实现  测试  上线,运维  经验分享  将来:手机之家搜索 V2.0
  • 51. 部署上线  运行概况  updater , rebuilder 部署在 Imobile-SV25-B50 上 • IntelXeon 4 cpu @2.60GHz , 6G mem • Slackware 12.1, JDK32 1.6  Search 部署在 Imobile-SV39-A49 上: • X86_64 , 8 cpu @ 2.50GHz , 32G mem • CentOS release 5.2, JDK64 1.6  搜索: 35+ 万查询 / 天,高峰期 > 20 次 /s  更新: 平均 15 条 / 分钟
  • 52. 生产环境运行观察  Slow search  比例: >1s 1.x%; >2s 0.2%  机器负载 : 49(search): 1~3; 50(update): <1  内存消耗: search: ­Xms4096M ­Xmx4096M  Cpu 消耗 :多核之间平均比较分配  索引平均更新速度: ~1 分钟  索引延迟率(因各种原因导致延迟更新的比例)
  • 53. 目录  关于手机之家  过去:手机之家搜索 V1.0  现在:手机之家搜索 V1.5  需求背景  目标  进度  设计  实现  测试  上线,运维  经验分享  将来:手机之家搜索 V2.0
  • 54. 开发中的一些收获 (1/5)  FileChannel.transferTo 拷贝文件失败:  Fewer than the requested number of bytes are transferred if the target channel is non-blocking and it has fewer than count bytes free in its output buffer.  解决: check copied size ,断点续传  根据 lucene 索引文件更新的特性 ( 每次更新一个新版本的时 候,都会新建一个全新的文件 ) ,使用 cp -l 链接替代真实的 大文件拷贝动作
  • 55. 开发中的一些收获 (2/5)  Kill  的问题  Never kill smart frog, don't kill ­9  Java use Runtime.getRuntime().addShutdownHook  to do the cleaning  things  Lucene IndexWriter need close!  server  程序,都应该考虑信号捕捉和处理的问题( java  程序容易忽 略这个问题)
  • 56. 开发中的一些收获 (3/5)  更新太频繁导致的磁盘 IO 问题 – 同一台机器目录之间同步:没有问题 – 一拖二,一拖三  暂时解决 – 建索引的机器不提供搜索服务 – rsync 限速
  • 57. 开发中的一些收获 (4/5)  GC  引起的服务暂停  多个索引共用 Search 进程  每个索引维持了多个 searcher  索引更新太过频繁: 30 秒  暂时解决  纵向拆分:将两个最大的库拆分到单独的进程  减少 searcher 个数到 2  个  谨慎的选择 gc 的类型,并调整 gc 的参数  G1 改进不明显,不稳定
  • 58. 开发中的一些收获 (5/5)  Java server  程序的 trouble shooting  性能问题: jprofile  内存问题: jmx  + jconsole  线程问题: Thread.currentThread().setName("diffDetect­" +  indexId);   详细的 log : log4j  常用的脚本: logslowsearch.sh  开发调试阶段:方便的重新编译并重启脚本  线上服务阶段:完善的监控及报警机制
  • 59. 目录  关于手机之家  过去:手机之家搜索 V1.0  现在:手机之家搜索 V1.5  需求背景  目标  进度  设计  实现  测试  上线,运维  经验分享  将来:手机之家搜索 V2.0
  • 60. 持续改进  配置文件改动检测,自动重新加载  更智能的处理索引字段变更  分词算法改进  搜索关键字数据挖掘(搜索新词自动发现)  搜索建议,搜索联想功能  排序算法改进  全站整合搜索  准实时搜索
  • 61. Lucene 3  Lucene 2.9 • Searchable.search(Weight, Filter, Collector): collector 终于可用了 • Added new MultiReaderHitCollector: 解决 group by • near real-time search via IndexWriter.getReader(): 单机方案  Lucene 3.0 • Del deprecated apis: 大版本升级要谨慎 • Port to Java5: 应该会有性能的提升  Lucene 3.1 • Near Realtime Search (using a built in RAMDirectory): 还是单机方案 • Complete overhaul of FieldCache API/Implementation: 等到花儿也谢了
  • 62. 定制功能  在某些情况下作为数据库的替代数据源  类似淘宝搜索,按多个字段筛选,过滤,排序  当前解决方案:使用 sql 从数据库中选取数据  问题:数据可能因为业务逻辑的设计而分散在多个不同的 库,表中,联表查询问题,并发压力问题  难点:非典型的复杂的查询条件,如 group by
  • 63. 参考资料  Lucene  http://lucene.apache.org/  http://lucene.apache.org/java/2_4_1/api/index.html  中文分词  http://code.google.com/p/paoding/  http://code.google.com/p/imdict-chinese-analyzer/  http://code.google.com/p/mmseg4j/  Monkey ( Java 底层异步网络 IO 框架)  DAL
  • 64. 关于我们  关于 imobile  网站首页 http://www.imobile.com.cn/  关于 http://www.imobile.com.cn/about.html  Longker ( V1.0 版本)  http://www.longker.org/  关于我( V1.5 版本)  http://www.fulin.org/  http://twitter.com/tangfl
  • 65. 更多讨论  Java GC  的问题  巨大的索引库与频繁更新如何共存  全站整合搜索,后台技术实现与前台表现设计  更多