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