在本文中,我们讨论索引的加载方式以及对传入查询和搜索实例管理的影响。
在早期的Sphinx版本中,如果设置了preopen选项,索引会被预读并加载到内存中。在这个过程中,守护进程将拒绝接受任何传入的连接。对于小型索引,这不是一个大问题,因为它们可以快速加载。但对于需要加载几十甚至数百GB的大型索引,这是一个真正的问题,可能需要几分钟甚至更长时间才能完成加载。
在Sphinx 2.3中,这种情况发生了变化,因为索引文件是通过内存映射(使用mmap)加载,而不是简单地读取并加载到内存中。使用mmap,守护进程的一个影子线程(而非主线程)首先读取每个页面的第一个字节,然后继续读取剩余的数据,缓慢地将所有内容加载到RAM中,同时还允许访问数据。简而言之,这是索引文件的惰性加载。
这样,守护进程可以在启动后立即接受连接。如果查询需要访问尚未加载到内存中的某些随机数据,它将从磁盘读取。这意味着查询的执行可能会比平常慢(取决于存储性能),但守护进程至少可以提供结果。更重要的是,一旦某个索引的文件加载完成,守护进程就可以为其提供"全速"服务,即使其他索引仍在加载。
虽然这对大多数用户来说是个好消息,但对某些人来说,“惰性"加载可能并不是最佳选择。例如,使用简单策略(随机或轮询)且不测量响应时间的负载均衡器,会在守护进程启动后立即将重新启动的实例添加到集群中。由于查询需要直接从磁盘读取,实例将提供比平常更高或高得多的响应时间,这是不希望看到的。相反,最好是在守护进程完成索引加载后再将实例添加到集群中。
为了应对这种情况,自2.3版本以来, searchd 有一个选项,尽管直到最近才被记录:’–force-preread’。使用此选项,守护进程仍将对索引文件进行内存映射,但预读是一个阻塞操作(就像在旧版本中一样),searchd将不会响应,直到所有内容都加载到内存中。