Elasticsearch integration

Elasticsearch integration

版本历史

  • 在 GitLab 8.4 中引入 .
  • 在 GitLab 9.0 中引入了对支持.

本文档介绍了如何使用 GitLab 设置 Elasticsearch. 启用后,您将受益于快速的搜索响应时间以及两个特殊搜索的优点:

Installing Elasticsearch

Omnibus 软件包中包括 Elasticsearch. 无论您使用的是 Omnibus 软件包还是从源代码安装的 GitLab,您都必须 . 提供有关安装 Elasticsearch 的详细信息超出了本文档的范围.

注意: Elasticsearch 应该安装在单独的服务器上,无论您自己安装还是使用云托管产品,例如 Elastic 的Elasticsearch Service (在 AWS,GCP 或 Azure 上可用)或 Service. 不建议在与 GitLab 相同的服务器上运行 Elasticsearch,这可能会导致 GitLab 实例性能下降.注意: 对于单节点 Elasticsearch 集群,功能集群的运行状况为黄色 (永远不会为绿色),因为已分配了主要分片,但副本却无法存在,因为没有其他节点可以为 Elasticsearch 分配副本.

将数据添加到数据库或存储库中并在管理区域中启用 Elasticsearch 后 ,搜索索引将自动更新.

Elasticsearch repository indexer

为了索引 Git 存储库数据,GitLab 使用了Go 语言编写的 .

Go 索引器的安装方式取决于您的 GitLab 版本:

  • 对于 Omnibus GitLab 11.8 及更高版本,请参见Omnibus GitLab .
  • For installations from source or older versions of Omnibus GitLab, install the indexer .

从 GitLab 11.8 开始,Omnibus GitLab 中包含了 Go 索引器. 以前的基于 Ruby 的索引器已在GitLab 12.3中删除.

From source

首先,我们需要安装一些依赖项,然后构建并安装索引器本身.

该项目依靠ICU进行文本编码,因此我们需要确保在运行之前安装了适用于您平台的开发包.

Debian / Ubuntu

要在 Debian 或 Ubuntu 上安装,请运行:

CentOS / RHEL

要在 CentOS 或 RHEL 上安装,请运行:

  1. sudo yum install libicu-devel
Mac OSX

要在 macOS 上安装,请运行:

  1. brew install icu4c
  2. export PKG_CONFIG_PATH="/usr/local/opt/icu4c/lib/pkgconfig:$PKG_CONFIG_PATH"

Building and installing

要构建和安装索引器,请运行:

  1. indexer_path=/home/git/gitlab-elasticsearch-indexer
  2. # Run the installation task for gitlab-elasticsearch-indexer:
  3. sudo -u git -H bundle exec rake gitlab:indexer:install[$indexer_path] RAILS_ENV=production

The gitlab-elasticsearch-indexer will be installed to /usr/local/bin.

您可以使用PREFIX env 变量更改安装路径. 如果这样做,请记住将-E标志传递给sudo .

Example:

  1. PREFIX=/usr sudo -E make install

安装完成后,请在您实例的 Elasticsearch 设置下启用, .

Elasticsearch 需要的资源超出了GitLab 系统要求中记录的资源. 这些会因安装大小而异,但是,根据 ,您应确保每个 Elasticsearch 节点至少至少8 GiB RAM .

请记住,这是 Elasticsearch 的最低要求 . 对于生产实例,他们建议使用更多的资源.

所需的存储空间在很大程度上取决于要存储在 GitLab 中的存储库的大小,但是根据经验,由于所有存储库加起来,您应该至少有 50%的可用空间.

Enabling Elasticsearch

为了启用 Elasticsearch,您需要具有管理员权限. 导航到管理区域 (扳手图标),然后导航到设置>集成并展开Elasticsearch部分.

单击保存更改以使更改生效.

可以使用以下 Elasticsearch 设置:

Limiting namespaces and projects

如果选择” Limit namespaces and projects that can be indexed更多选项可用

您可以选择名称空间和项目以排他索引. 请注意,如果名称空间是一个组,它将包括所有子组以及属于这些子组的要被索引的项目.

如果所有名称空间都已建立索引,Elasticsearch 仅提供跨组代码/提交搜索(全局). 在仅对名称空间的子集进行索引的特定情况下,全局搜索将不提供代码或提交范围. 这仅在索引命名空间的范围内才有可能. 当前,无法对多个已索引的名称空间进行编码/提交搜索(当仅对名称空间的子集进行索引时). 例如,如果两个组都已建立索引,则无法在两个组上运行单个代码搜索. 您只能在第一组上然后在第二组上运行代码搜索.

您可以通过编写感兴趣的部分名称空间或项目名称来过滤选择下拉列表.

注意:如果未选择名称空间或项目,则不会进行 Elasticsearch 索引.警告:如果您已经为实例建立索引,则必须重新生成索引,才能删除所有现有数据以进行过滤以使其正常工作. 为此,请运行 Rake 任务gitlab:elastic:recreate_indexgitlab:elastic:clear_index_status . 然后,从列表中删除名称空间或项目将按预期从 Elasticsearch 索引中删除数据.

Disabling Elasticsearch

要禁用 Elasticsearch 集成:

  1. 导航到管理区域 (扳手图标),然后导航到设置>集成 .
  2. 展开Elasticsearch部分,然后取消选中Elasticsearch 索引启用 Elasticsearch 的 搜索 .
  3. 单击保存更改以使更改生效.
  4. (可选)删除现有索引:

    1. # Omnibus installations
    2. sudo gitlab-rake gitlab:elastic:delete_index
    3. # Installations from source
    4. bundle exec rake gitlab:elastic:delete_index RAILS_ENV=production

启用 Elasticsearch 索引编制后,您的 GitLab 实例中的新更改将在发生更改时自动进行索引. 要回填现有数据,可以使用以下方法之一在后台作业中对其进行索引.

Indexing through the administration UI

Introduced in 12.3.

通过管理区域建立索引:

  1. Configure your Elasticsearch host and port.
  2. 创建空索引:

    1. # Omnibus installations
    2. sudo gitlab-rake gitlab:elastic:create_empty_index
    3. # Installations from source
    4. bundle exec rake gitlab:elastic:create_empty_index RAILS_ENV=production
  3. .

  4. Click 索引所有项目 in 管理区域>设置>集成> Elasticsearch.
  5. 单击确认消息中的检查进度 ,以查看后台作业的状态.
  6. 个人摘要需要手动编制索引:

    1. # Omnibus installations
    2. sudo gitlab-rake gitlab:elastic:index_snippets
    3. # Installations from source
    4. bundle exec rake gitlab:elastic:index_snippets RAILS_ENV=production

可以使用 Rake 任务执行索引.

Indexing small instances

警告:这将删除您现有的索引.

如果数据库大小小于 500 MiB,并且所有托管存储库的大小小于 5 GiB:

  1. .
  2. 索引您的数据:

    1. # Omnibus installations
    2. sudo gitlab-rake gitlab:elastic:index
    3. # Installations from source
    4. bundle exec rake gitlab:elastic:index RAILS_ENV=production
  3. 索引完成后,启用Search with Elasticsearch .

Indexing large instances

警告:执行异步索引编制将生成很多 Sidekiq 作业. 确保具有可扩展和高度可用的设置或创建以为该任务做准备

  1. Configure your Elasticsearch host and port.
  2. 创建空索引:

    1. # Omnibus installations
    2. sudo gitlab-rake gitlab:elastic:create_empty_index
    3. # Installations from source
    4. bundle exec rake gitlab:elastic:create_empty_index RAILS_ENV=production
  3. 如果这是您的 GitLab 实例的重新索引,请清除索引状态:

  4. .

  5. 索引大型 Git 存储库可能需要一段时间. 为了加快此过程,您可以暂时禁用自动刷新和复制. 根据我们的经验,您可以预期索引编制时间将减少 20%. 索引完成后,我们将启用它们. 此步骤是可选的!

    1. curl --request PUT localhost:9200/gitlab-production/_settings --header 'Content-Type: application/json' --data '{
    2. "index" : {
    3. "refresh_interval" : "-1",
    4. "number_of_replicas" : 0
    5. } }'
  6. 索引项目及其相关数据:

    1. # Omnibus installations
    2. sudo gitlab-rake gitlab:elastic:index_projects
    3. # Installations from source
    4. bundle exec rake gitlab:elastic:index_projects RAILS_ENV=production

    这为需要索引的每个项目加入了一个 Sidekiq 作业. 您可以在管理区域>监视>后台作业>队列选项卡中查看作业,然后单击 ,也可以使用 Rake 任务查询索引状态:

    1. # Omnibus installations
    2. sudo gitlab-rake gitlab:elastic:index_projects_status
    3. # Installations from source
    4. bundle exec rake gitlab:elastic:index_projects_status RAILS_ENV=production
    5. Indexing is 65.55% complete (6555/10000 projects)

    如果要将索引限制为一定范围的项目,可以提供ID_FROMID_TO参数:

    1. # Omnibus installations
    2. sudo gitlab-rake gitlab:elastic:index_projects ID_FROM=1001 ID_TO=2000
    3. # Installations from source
    4. bundle exec rake gitlab:elastic:index_projects ID_FROM=1001 ID_TO=2000 RAILS_ENV=production

    其中ID_FROMID_TO是项目 ID. 这两个参数都是可选的. 上面的示例将索引从 ID 1001到(并包括)ID 2000所有项目.

    故障排除:有时gitlab:elastic:index_projects排队的项目索引作业可能会中断. 出于多种原因可能会发生这种情况,但是再次运行索引任务始终是安全的. 它将跳过已经建立索引的存储库.

    当索引器在数据库中存储每个已索引存储库的最后一次提交 SHA 时,您可以使用特殊参数UPDATE_INDEX运行索引器,它将再次检查每个项目存储库以确保对存储库中的每个提交都进行了索引,这很有用.如果您的索引已过时:

    1. # Omnibus installations
    2. sudo gitlab-rake gitlab:elastic:index_projects UPDATE_INDEX=true ID_TO=1000
    3. # Installations from source
    4. bundle exec rake gitlab:elastic:index_projects UPDATE_INDEX=true ID_TO=1000 RAILS_ENV=production

    您还可以使用gitlab:elastic:clear_index_status Rake 任务来强制索引器”忘记”所有进度,因此它将从头开始重试索引过程.

  7. 个人代码段与项目无关,需要单独编制索引:

    1. # Omnibus installations
    2. sudo gitlab-rake gitlab:elastic:index_snippets
    3. # Installations from source
  8. 在建立索引后再次启用复制和刷新(仅在您之前禁用它的情况下):

    1. curl --request PUT localhost:9200/gitlab-production/_settings --header 'Content-Type: application/json' --data '{
    2. "index" : {
    3. "number_of_replicas" : 1,
    4. "refresh_interval" : "1s"
    5. } }'

    启用上述刷新后,应调用强制合并.

    对于 Elasticsearch 6.x,在进行强制合并之前,索引应处于只读模式:

    1. curl --request PUT localhost:9200/gitlab-production/_settings --header 'Content-Type: application/json' --data '{
    2. "settings": {
    3. "index.blocks.write": true
    4. } }'

    然后,启动强制合并:

    1. curl --request POST 'localhost:9200/gitlab-production/_forcemerge?max_num_segments=5'

    此后,如果索引处于只读模式,请切换回读写模式:

  9. 索引完成后,启用Search with Elasticsearch .

Indexing limitations

对于存储库和摘要文件,GitLab 最多只能索引 1 MiB 的内容,以避免索引超时.

GitLab Elasticsearch Rake tasks

耙任务可用于:

以下是一些可用的 Rake 任务:

注意: TARGET_NAME参数是可选的,如果未设置,它将使用当前RAILS_ENV的默认索引/别名.

Environment variables

除了 Rake 任务,还有一些环境变量可用于修改过程:

Indexing a specific project

因为ID_TOID_FROM环境变量使用or equal to比较,所以您可以通过使用两个具有相同项目 ID 号的变量来仅索引一个项目:

  1. root@git:~# sudo gitlab-rake gitlab:elastic:index_projects ID_TO=5 ID_FROM=5
  2. Indexing project repositories...I, [2019-03-04T21:27:03.083410 #3384] INFO -- : Indexing GitLab User / test (ID=33)...
  3. I, [2019-03-04T21:27:05.215266 #3384] INFO -- : Indexing GitLab User / test (ID=33) is done!

Elasticsearch index scopes

执行搜索时,GitLab 索引将使用以下范围:

Guidance on choosing optimal cluster configuration

有关选择集群配置的基本指导,请参考Elastic Cloud Calculator . 您可以在下面找到更多信息.

  • 通常,您将希望至少将一个 2 节点群集配置与一个副本一起使用,这将使您具有弹性. 如果存储使用量快速增长,则可能需要预先计划水平扩展(添加更多节点).
  • 不建议将 HDD 存储与搜索群集一起使用,因为它会影响性能. 最好使用 SSD 存储(例如 NVMe 或 SATA SSD 驱动器).
  • 您可以使用来对不同搜索集群大小和配置的搜索性能进行基准测试.
  • Heap size应设置为不超过物理 RAM 的 50%. 此外,不应将其设置为超过基于零的压缩 oop 的阈值. 确切的阈值会有所不同,但是在大多数系统上 26 GB 是安全的,但在某些系统上也可能高达 30 GB. 有关更多详细信息,请参见设置堆大小 .
  • 每个节点的 CPU(CPU 核心)数通常对应于以下所述Number of Elasticsearch shards设置.
  • 一个好的指导方针是确保每个节点的已配置 GB 堆中的碎片数保持在 20 个以下. 因此,具有 30GB 堆的节点最多应具有 600 个分片,但是越低于此限制,您可以使其越好. 通常,这将有助于群集保持良好的运行状况.
  • 小碎片会导致小段,这会增加开销. 旨在将平均分片大小保持在至少几 GB 到几十 GB 之间. 另一个考虑因素是文档数量,您应该针对此简单的分片number of expected documents / 5M +1公式: number of expected documents / 5M +1 .
  • refresh_interval是每个索引设置. 如果您不需要实时数据,则可能需要将其从默认的1s调整为更大的值. 这将改变您看到新结果的时间. 如果这对您很重要,则应使其尽可能接近默认值.
  • 如果您有大量繁重的索引操作,则可能需要将提高到 30%或 40%.
  • The Number of Elasticsearch shards setting usually corresponds with the number of CPUs available in your cluster. For example, if you have a 3-node cluster with 4 cores each, this means you will benefit from having at least 3*4=12 shards in the cluster. Please note, it’s only possible to change the shards number by using Split index API or by reindexing to a different index with a changed number of shards.
  • Number of Elasticsearch replicas设置在大多数情况下应等于1 (每个分片将具有 1 个副本). 不建议使用0 ,因为丢失一个节点会破坏索引.

Deleted documents

每当对索引的 GitLab 对象进行更改或删除时(合并请求描述发生更改,从存储库中的 master 分支中删除文件,删除项目等),索引中的文档也会被删除. 但是,由于这些是”软”删除,因此”已删除文档”的总数增加了,因此浪费了空间. Elasticsearch 进行段的智能合并,以删除这些已删除的文档. 但是,根据 GitLab 安装中活动的数量和类型,可能会在索引中看到多达 50%的浪费空间.

通常,我们建议仅使用默认设置让 Elasticsearch 自动合并和回收空间. 在Lucene 的”已删除文档处理”中“总的来说,除了减小最大段大小外,最好将 Lucene 的默认值保持原样,并且不要对回收删除时感到担心.”

但是,某些较大的安装可能希望调整合并策略设置:

  • 考虑将index.merge.policy.max_merged_segment大小从默认的 5 GB 减小到 2 GB 或 3 GB. 仅当段中至少有 50%的删除时才进行合并. 较小的段大小将允许合并更频繁地发生.

    1. curl --request PUT localhost:9200/gitlab-production/_settings ---header 'Content-Type: application/json' --data '{
    2. "index" : {
    3. "merge.policy.max_merged_segment": "2gb"
    4. }
    5. }'
  • 您还可以调整index.merge.policy.reclaim_deletes_weight ,它控制如何积极地定位删除. 但是,这可能会导致代价高昂的合并决策,因此,除非您了解取舍,否则我们建议不要更改此决策.

    1. curl --request PUT localhost:9200/gitlab-production/_settings ---header 'Content-Type: application/json' --data '{
    2. "index" : {
    3. "merge.policy.reclaim_deletes_weight": "3.0"
    4. }
    5. }'
  • 不要以删除已删除的文档. 文档中的警告指出,这可能导致很大的网段,这些网段可能永远都无法收回,并且还可能导致严重的性能或可用性问题.

Troubleshooting

Common issues

  • 如何验证我的 GitLab 实例正在使用 Elasticsearch?

    最简单的方法是通过运行以下sudo gitlab-rails console通过 rails 控制台( sudo gitlab-rails console ):

    1. u = User.find_by_username('your-username')
    2. s = SearchService.new(u, {:search => 'search_term'})
    3. pp s.search_objects.class.name

    如果看到"ActiveRecord::Relation" ,则说明您使用 Elasticsearch.

    If you see "Kaminari::PaginatableArray" you are using Elasticsearch.

    注意:以上说明仅用于在索引所有名称空间时验证 GitLab 是否正在使用 Elasticsearch. 这仅用于仅索引方案.

  • 我更新了 GitLab,现在找不到任何东西

    我们会不断更新索引策略,并致力于支持新版本的 Elasticsearch. 进行索引更改时,更新 GitLab 后可能需要重新编制索引 .

  • 我索引了所有存储库,但找不到任何内容

    确保所有数据库数据建立索引.

    除此之外,通过Elasticsearch Search API检查数据是否在 Elasticsearch 端显示.

    如果通过显示,请检查是否通过 rails 控制台( sudo gitlab-rails console )显示:

    1. u = User.find_by_username('your-username')
    2. s = SearchService.new(u, {:search => 'search_term', :scope => 'blobs'})
    3. pp s.search_objects.to_a

    注意:以上说明不适用于仅索引命名空间子集的情况 .

    有关搜索特定数据类型的更多信息,请参见 .

  • 我索引了所有存储库,但随后切换了 Elasticsearch 服务器,现在什么也找不到

    您将需要重新运行所有 Rake 任务,以重新索引数据库,存储库和 Wiki.

  • 索引过程需要很长时间

    GitLab 实例中存在的数据越多,索引过程花费的时间就越长.

  • 有些项目未编入索引,但我们不知道哪些项目

    您可以运行sudo gitlab-rake gitlab:elastic:projects_not_indexed以显示未建立索引的项目.

  • “如果未配置父字段,则无法指定父”

    如果您在 GitLab 8.12 之前启用了 Elasticsearch 并且尚未重建索引,则在许多不同情况下,您将获得异常:

    1. Elasticsearch::Transport::Transport::Errors::BadRequest([400] {
    2. "error": {
    3. "root_cause": [{
    4. "type": "illegal_argument_exception",
    5. "reason": "Can't specify parent if no parent field has been configured"
    6. }],
    7. "type": "illegal_argument_exception",
    8. "reason": "Can't specify parent if no parent field has been configured"
    9. },
    10. "status": 400
    11. }):

    这是因为我们在 GitLab 8.12 中更改了索引映射,并且应该删除旧索引并再次从头开始构建,请参阅8-11-to-8-12 更新指南中的详细信息.

  • Exception Elasticsearch::Transport::Transport::Errors::BadRequest

    如果您有此例外情况(就像上面的情况一样,但实际消息有所不同),请检查您是否具有正确的 Elasticsearch 版本并满足其他 . 还有一种简单的方法可以使用sudo gitlab-rake gitlab:check命令自动检查它.

  • Exception Elasticsearch::Transport::Transport::Errors::RequestEntityTooLarge

    1. [413] {"Message":"Request size exceeded 10485760 bytes"}

    当您将 Elasticsearch 集群配置为拒绝某个大小以上的请求(在这种情况下为 10MiB)时,会看到此异常. 这相当于http.max_content_length在设置elasticsearch.yml . 将其增大到更大的大小,然后重新启动您的 Elasticsearch 集群.

    AWS 根据基础实例的大小对此设置有固定的限制 (” HTTP 请求有效负载的最大大小”).

  • 即使一切似乎都正常运行,我的单节点 Elasticsearch 集群状态也从未从yellow变为green

    对于单节点 Elasticsearch 集群,功能集群的运行状况为黄色 (永远不会为绿色),因为已分配了主要分片,但副本却无法存在,因为没有其他节点可为 Elasticsearch 分配副本. 如果您使用的是 Service,这也适用.

    警告:建议不要将副本数设置为0 (GitLab Elasticsearch 集成菜单中不允许这样做). 如果您计划添加更多的 Elasticsearch 节点(总共超过 1 个 Elasticsearch 节点),则副本数将需要设置为大于0的整数值. 否则,将导致缺乏冗余(丢失一个节点将破坏索引).

    如果您对单节点 Elasticsearch 集群有绿色状态严格要求 ,请确保您了解上一段概述的风险,然后只需运行以下查询将副本数设置为0 (集群将不会再尝试创建任何碎片副本):

    1. curl --request PUT localhost:9200/gitlab-production/_settings --header 'Content-Type: application/json' --data '{
    2. "index" : {
    3. "number_of_replicas" : 0
    4. }
    5. }'
  • 我正在health check timeout: no Elasticsearch node available索引编制过程中 Sidekiq 中health check timeout: no Elasticsearch node available错误

    1. Gitlab::Elastic::Indexer::Error: time="2020-01-23T09:13:00Z" level=fatal msg="health check timeout: no Elasticsearch node available"

    您可能没有在 Elasticsearch 集成菜单的“ URL”字段中使用http://https://作为值的一部分. 请确保在此字段中使用http://https://作为我们使用的Go需要将该 URL 的前缀接受为有效 . 更正了网址格式后,请删除索引(通过 ),然后为实例的内容重新编制索引 .

Low-level troubleshooting

当您遇到其他问题(包括性能不佳)时可以使用 .

Known Issues

  • 正在评估模式和过滤器配置以进行改进. 我们注意到由于我们的模式和过滤器配置, 一些边缘情况未返回预期的搜索结果.

    在中,讨论了code_analyzer模式和过滤器的改进策略.

有时,您的 Elasticsearch 索引数据可能存在问题,因此,如果没有搜索结果并且假定该范围内支持基本搜索,则 GitLab 将允许您恢复为”基本搜索”. 这种”基本搜索”的行为就像您根本没有为实例启用 Elasticsearch 并使用其他数据源(即 PostgreSQL 数据和 Git 数据)进行搜索一样.