• 近实时搜索
    • refeash API

    近实时搜索

    因为per-segment search机制,索引和搜索一个文档之间是有延迟的。新的文档会在几分钟内可以搜索,但是这依然不够快。

    磁盘是瓶颈。提交一个新的段到磁盘需要fsync操作,确保段被物理地写入磁盘,即时电源失效也不会丢失数据。但是fsync是昂贵的,它不能在每个文档被索引的时就触发。

    所以需要一种更轻量级的方式使新的文档可以被搜索,这意味这移除fsync

    位于Elasticsearch和磁盘间的是文件系统缓存。如前所说,在内存索引缓存中的文档(图1)被写入新的段(图2),但是新的段首先写入文件系统缓存,这代价很低,之后会被同步到磁盘,这个代价很大。但是一旦一个文件被缓存,它也可以被打开和读取,就像其他文件一样。

    图1:内存缓存区有新文档的Lucene索引
    内存缓存区有新文档的Lucene索引

    Lucene允许新段写入打开,好让它们包括的文档可搜索,而不用执行一次全量提交。这是比提交更轻量的过程,可以经常操作,而不会影响性能。

    图2:缓存内容已经写到段中,但是还没提交
    缓存内容已经写到段中,但是还没提交

    refeash API

    在Elesticsearch中,这种写入打开一个新段的轻量级过程,叫做refresh。默认情况下,每个分片每秒自动刷新一次。这就是为什么说Elasticsearch是近实时的搜索了:文档的改动不会立即被搜索,但是会在一秒内可见。

    这会困扰新用户:他们索引了个文档,尝试搜索它,但是搜不到。解决办法就是执行一次手动刷新,通过API:

    1. POST /_refresh <1>
    2. POST /blogs/_refresh <2>
    • <1> refresh所有索引
    • <2> 只refresh 索引blogs

    虽然刷新比提交更轻量,但是它依然有消耗。人工刷新在测试写的时有用,但是不要在生产环境中每写一次就执行刷新,这会影响性能。相反,你的应用需要意识到ES近实时搜索的本质,并且容忍它。

    不是所有的用户都需要每秒刷新一次。也许你使用ES索引百万日志文件,你更想要优化索引的速度,而不是进实时搜索。你可以通过修改配置项refresh_interval减少刷新的频率:

    1. PUT /my_logs
    2. {
    3. "settings": {
    4. "refresh_interval": "30s" <1>
    5. }
    6. }
    • <1> 每30s refresh一次my_logs

    refresh_interval可以在存在的索引上动态更新。你在创建大索引的时候可以关闭自动刷新,在要使用索引的时候再打开它。

    1. PUT /my_logs/_settings
    2. { "refresh_interval": -1 } <1>
    3. PUT /my_logs/_settings
    4. { "refresh_interval": "1s" } <2>
    • <1> 禁用所有自动refresh
    • <2> 每秒自动refresh