当前位置: 首页 > news >正文

配置 Gitlab 和 Elasticsearch/Zoekt 并使用 Docker Metadata 数据库、Camo 代理服务

配置 Gitlab 和 Elasticsearch/Zoekt 并使用 Docker Metadata 数据库、Camo 代理服务

本文章首发于:连接 Gitlab 和 Elasticsearch/Zoekt 并使用 Docker Metadata 数据库、Camo 代理服务 - Ayaka 的小站

为确保更好阅读格式和阅读体验,更建议前往个人博客阅读 ~,另外本文章部分内部 Issue 链接为个人 Gitlab,不保证链接可用性。

一、简介

1)前提

大家好啊我是 Musicminion。今天这期博客来点小众一点话题——把 Gitlab 接入 ElasticSearch 还有 Zoekt 搜索引擎,以及把 Docker 镜像仓库的 Metadata 迁移到 PostgreSQL 数据库里面。

如果你想要学习 Gitlab 部署,网上还是有不少文章的,这篇文章可能对你不是很适用,因为这个算是比较进阶的内容,前提是需要有一个你部署好的 Gitlab EE (企业版) 实例。关于获取企业版许可证,请参考 Activate GitLab Enterprise Edition (EE) | GitLab Docs。

我知道大部分人部署 Gitlab 可能纯纯的当做内部协作的代码仓库来使用的,但是其实对于热爱折腾朋友来说,探索应该不止于此。Gitlab 作为一个非常优秀的代码存储工具,功能经过数年的迭代还是非常全的,几乎可以当做一个 All in One 的开发工具,比如下面的内容,网上已经有不少教程:

  • Gitlab Pages:个人静态网站部署工具

  • Gitlab Docker Registry:容器镜像库

  • 配置 Github 集成的单点登录

  • CI/CD:流水线和 Runner 的配置

  • 其他一些 Bug 的修复等

但是有些比较小众的功能,比如搜索等,这些功能中文教程很少。得对着说明文档一点一点的配置。因此这篇文章介绍一下 Gitlab 的小众功能。

2)搜索功能简介

Gitlab 的高级搜索还有精确代码搜索都是付费功能,需要企业版许可证。

Gitlab 支持不同类型的 Gitlab 搜索,比如搜索代码,搜索 Issue、项目名字,这些功能统称搜索。

  • 社区 CE 版搜索:只支持最基本的搜索:项目名字等

  • Gitlab 高级搜索:可以搜索具体代码、评论、Issue 内容、里程碑

  • Zoekt 精确代码:高级搜索的代码不一定准确,Zoekt 可以更精准的搜索到代码(beta 版)

因为我平时个人搜索代码还是很频繁的,你要说为什么不本地 vscode 里面直接搜,那肯定是最快的嘛,但是有时候开发很可能就是想起来了,在浏览器里面顺手一搜索的事,能简化肯定是希望更简化的。

这是不同搜索支持的功能,看完之后是不是很心动:

基本搜索 (Basic search)高级搜索 (Advanced search)精确代码搜索 (Exact code search)
范围全局群组项目范围全局群组项目范围全局群组项目
CodeNoNoYesCodeYesYesYesCodeNoYesYes
CommentsNoNoYesCommentsYesYesYesCommentsNo    
CommitsNoNoYesCommitsYesYesYesCommits
EpicsNoYesNoEpicsYesYesNoEpics
IssuesYesYesYesIssuesYesYesYesIssues
Merge requestsYesYesYesMerge requestsYesYesYesMerge requests
MilestonesYesYesYesMilestonesYesYesYesMilestones
ProjectsYesYesNoProjectsYesYesNoProjects
UsersYesYesYesUsersYesYesYesUsers
WikisNoNoYesWikisYesYesYesWikis

这个是部署好后的效果:

精确搜索:仅适用于代码搜索,并且会在搜索框里面显示:精确代码搜索(由 Zoekt 提供支持)已启用。如果你用过高级搜索,你会发现高级搜索代码经常可能会搜出来一堆无关紧要的东西,精确搜索可以保证搜到的所见即所

GitLab 精确搜索

GitLab 精确搜索​

高级搜索:可以搜索 Wiki、Commit 记录等,会提示:高级搜索 已启用

GitLab 高级搜索

GitLab 高级搜索​

3)容器镜像库 Metadata

如果你已经运营了一段时间的 Gitlab 的容器镜像库,就会发现你的 Gitlab 数据越来越大,经过排查我发现是 Gitlab 的容器镜像库默认情况不会自动做垃圾回收(GC)。(即使你通过 Web 界面删除了一个 Docker Image,容器镜像依然存储在你的 Gitlab 中)

有关垃圾回收的教程,请参考 Running the garbage collection on schedule | GitLab Docs,具体就是运行下面这个命令:

sudo gitlab-ctl stop  # 停止 gitlab
sudo gitlab-ctl registry-garbage-collect # 运行垃圾回收
sudo gitlab-ctl start # 重启 gitlab

注意,Gitlab 的垃圾回收需要停止 Gitlab 服务的运行,不能支持在线回收。那要做到支持在线回收,必须迁移使用 metadata database,也就是把容器的元数据存储到数据库里面。这里推测 Gitlab 之前可能采用了 Docker 官方的 Registry 的方案,后面发现存在种种限制,因此又做了一些数据的迁移工作。

You can run garbage collection in the background without the need to schedule it or require read-only mode, if you migrate to the metadata database.

开启了 metadata database 后,就可以愉快的统计容器镜像库

镜像容量统计

镜像容量统计​

4)Camo 代理服务

不知道有没有小伙伴仔细看过 Github 里面引用的一些外链图片的链接。如果你检查过就会发现,所有 Github Readme 引用的外部图片链接,全部变成了 https://camo.githubusercontent.com/​

官方解释:为托管图像,GitHub 使用开源项目 Camo。 Camo 为每个文件生成匿名 URL 代理,以隐藏您的浏览器详细信息和来自其他用户的相关信息。 URL 以 https://<subdomain>.githubusercontent.com/​ 开头,子域不同,具体取决于图像的上传方式。

这样的好处就是,假如有人为了恶意统计用户的访问 IP,然后引用于一个自己服务器的图片,这样每次用户打开这个 Readme 的时候,浏览器就会顺着这个图片的 URL,去抓取对应的图片,这样就可能导致隐私泄露的问题。

此外,因为国内的一些网络环境不好,一些引用的外网的图片,也可能全部变成了诡异的加载失败,如果能搭建一个自己的图片代理,就会好很多力!

Gitlab 的官方文档其实也是支持 Proxying assets | GitLab Docs,只不过可能很少有朋友关注到了这一点。部署好后的效果如下,可以看到所有的图片全都经过了我的个人 Camo 服务,成功加载:

Camo 效果演示

Camo 效果演示​

二、部署具体功能

废话不多说,首先介绍一下我自己是使用 Docker-Compose 的 yml ​文件来部署的 Gitlab,我喜欢所有的配置文件集中管理,这样可以很好的迁移。关于 Docker 部署 Gitlab 教程已经烂大街我这里就不需要额外介绍了。

我们三个功能由易到难依次介绍:

1)Camo 代理服务

内部 Issue 链接:2025.08 Week 2: 给自建 Gitlab 增加 Camo 服务图片代理 (#5) · Issue · Musicminion/personal-plan

Github 上有一个开源项目 cactus/go-camo: A secure image proxy server,采用 Go 语言编写,同时具有轻量还有高效的特点,并且还提供了 Docker 的部署方式。

我这里是在一台自己的海外服务器上运行的,这是 docker-compose.yml​:

services:go-camo:image: ghcr.io/cactus/go-camo:latestrestart: unless-stoppedports:- "52380:8080"command: ["-k", "somekey"]

注意,你应该生成一个自己的密钥,然后用来代替上面的 somekey​,这个 key 后面会用来签名使用。然后就是 Nginx 的配置这个也是老生常谈了的:

server {listen 80;server_name camo.example.com;# 强制跳转到 HTTPSreturn 301 https://$host$request_uri;
}server {listen 443 ssl http2;server_name camo.ayaka.space;ssl_certificate /path/to/fullchain.cer;ssl_certificate_key /path/to/*.example.com.key;# 建议加上一些现代 TLS 配置ssl_protocols TLSv1.2 TLSv1.3;ssl_ciphers HIGH:!aNULL:!MD5;ssl_prefer_server_ciphers on;location / {proxy_pass http://localhost:52380;   # 这里是 docker-compose 里的服务名:端口proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme;proxy_hide_header Cache-Control;proxy_hide_header Expires;add_header Cache-Control "public, max-age=3600" always;}
}

然后需要自己去你的 Gitlab 的个人设置里面,生成一个 PRIVATE-TOKEN 个人访问令牌,权限你可以暂时全部选上,或者勾选 sudo 也行。

Gitlab 个人访问令牌设置界面

Gitlab 个人访问令牌设置界面​

然后使用命令行,记得把 <my_private_token> ​替换为你的个人访问令牌:

curl --request "PUT" "https://gitlab.example.com/api/v4/application/settings?\
asset_proxy_enabled=true&\
asset_proxy_url=https://camo.example.com&\
asset_proxy_secret_key=somekey" \
--header 'PRIVATE-TOKEN: <my_private_token>'

之后重启 GitLab,你应该就可以看到图片是不是走的你的代理服务器加载的了。

Camo 服务启用后的效果

Camo 服务启用后的效果​

顺便提一嘴,其实这里还可以个性化的配置缓存过期的时间,具体可以参考 Nginx 的缓存时间配置。

2)ElasticSearch 搜索配置

ElasticSearch 是一个 Java 写的全文搜索工具,说实话非常吃性能,没有 16G 的大内存基本很难跑。而且这个东西的 Docker 部署小有复杂。

首先给你的 Gitlab 的 Docker compose 的文件里面加上以下内容:

  elasticsearch:image: docker.elastic.co/elasticsearch/elasticsearch:8.10.2container_name: elasticsearchrestart: alwaysenvironment:- discovery.type=single-node- TZ=Asia/Shanghai- xpack.security.enabled=false- http.max_content_length=1024mbvolumes:- ./elasticsearch/data:/usr/share/elasticsearch/data- ./elasticsearch/config:/usr/share/elasticsearch/config- ./elasticsearch/logs:/usr/share/elasticsearch/logs- ./elasticsearch/plugins:/usr/share/elasticsearch/pluginsports:- '9200:9200'- '9300:9300'mem_limit: 16gcpus: '8'

然后不要着急,先把容器里面的文件数据偷出来:

# 启动一个临时容器(不运行服务)
docker run --name temp_elasticsearch -d docker.elastic.co/elasticsearch/elasticsearch:8.10.2 tail -f /dev/null# 拷贝数据
docker cp temp_elasticsearch:/usr/share/elasticsearch/data ./elasticsearch/data
docker cp temp_elasticsearch:/usr/share/elasticsearch/config ./elasticsearch/config
docker cp temp_elasticsearch:/usr/share/elasticsearch/logs ./elasticsearch/logs
docker cp temp_elasticsearch:/usr/share/elasticsearch/plugins ./elasticsearch/plugins# 删除临时容器
docker rm -f temp_elasticsearch

因为其实是这样的,我们稍后会把这些目录挂载出来,但是实际上这些目录里面本身又有文件了,所以我们必须先把配置偷出来,然后才能运行,特别是像那些插件目录,我们必须挂出来。记得启动后检查一下 ES 的日志,如果发现有问题可能还需要对应的解决。

然后就是熟悉的改配置:

services:gitlab:image: gitlab/gitlab-ee:18.3.0-ee.0container_name: gitlabrestart: alwaysshm_size: '4g'extra_hosts:- "host.docker.internal:host-gateway"environment:GITLAB_OMNIBUS_CONFIG: | # Add any other gitlab.rb configuration here, each on its own line# ... 已有的配置gitlab_rails['elasticsearch_enabled'] = truegitlab_rails['elasticsearch_url'] = ['http://elasticsearch:9200']gitlab_rails['elasticsearch_indexer_enabled'] = truegitlab_rails['elasticsearch_aws'] = false

然后就是进入管理页面配置了:

  • 勾选开启 ElasticSearch 索引

  • 然后注意 URL 必须配置为从 Gitlab 容器里面可以访问到的搜索的 URL,为了安全起见可以考虑配置一下密码之类的,我这里仅仅是内部访问,就直接忽略了。

  • 配置完成后点 索引实例​,然后静候佳音

高级搜索设置面板

高级搜索设置面板​

另外据说还有一个中文的分词器可以考虑一下,方法是进入 Elasticsearch 容器里面执行:

sudo bin/elasticsearch-plugin install analysis-smartcn

至于 Elasticsearch 不停机重建索引,这个一般适用于更新了 Gitlab 之后,发现搜索搜不了了,或者出现故障的时候,需要重建索引,就点一下,不要点的太频繁。

等所有的项目索引完成,就可以快乐的搜索了!注意,一般开始索引实例之后,上图里面暂停 ElasticSearch 索引的选项会自动打开,如果你发现索引好了,可以取消勾选然后保存。

3)Zoekt 精确代码搜索

内部 Issue 链接:2025.08 Week 3: 给个人 Gitlab 新增代码精确搜索功能 (#8) · Issue · Musicminion/personal-plan

先简要介绍一下 Zoekt 的架构,Gitlab 和 Zoekt 是怎么配合的?Zoekt 会运行一个 indexer,负责构建索引。Zoekt indexer 启动之后,会去找 Gitlab 一直拉取自己的作业需求,比如知道我现在要索引 /root ​下面的所有仓库,然后他就会通过 Gitaly 的 socket 接口去拉取这个对应的数据。这就会导致两个问题:

  • Zoekt indexer 需要和 Gitlab 共享数据目录(socket 通信目录等)

  • 需要解决权限问题,UID/GID 需要手动配置

此外,Zoekt 会把自己的 URL 通过心跳包的形式发送给 Gitlab,当用户搜索的时候,Gitlab 通过心跳包里面获得的 URL,然后发送给 Zoekt web server。web server 搜索然后返回结果理论是这样。

Gitlab 的 Zoekt 容器的版本和 Gitlab 基本算配套发布的。

关于 Docker compose 部署 Zoekt 的流程,参考这里:example/docker-compose · main · GitLab.org / Gitlab Zoekt · GitLab,但是其实这个有些问题,有个环境变量没写会导致一直启动失败。

配置文件里面的几个问题:

  1. 你需要找到 gitaly 目录,然后 ls -ln​ 看一下权限,一般 docker 部署的权限号码应该是 998

  2. ​gitlab_shell_secret ​这个文件可能需要你手动去找一下 gitlab 的这个文件的位置,find / ​一下理论有,我这里也记不清楚,但是你最好拷贝一份放给 zoekt 专门用

  3. ​git.example.com ​就是你的 Gitlab 的 URL

  4. 最重要的一个事情:Gitlab 主容器里面的 /var/opt/gitlab ​这个挂载到宿主机出后,你需要把挂出来的这个目录,重新挂载到 zoekt 里面去!这样才能保证里面可以通过 socket 文件访问 gitaly,因为需要拉取仓库数据。

   gitlab:# 其他配置volumes:- './gitlab/config:/etc/gitlab'- './gitlab/logs:/var/log/gitlab'- './gitlab/data:/var/opt/gitlab' # 注意观察 /var/opt/gitlab 的挂载点# registry.gitlab.com/gitlab-org/build/cng/gitlab-zoekt:v18.2.4-fipszoekt_webserver:image: registry.gitlab.com/gitlab-org/build/cng/gitlab-zoekt:v18.3.0container_name: zoekt_webserverrestart: always# 998 is the UID for ./gitlab/data/git-data/repositories/+gitaly# use ls -ln to checkuser: "998:998"ports:- 6070:6070environment:GITLAB_ZOEKT_MODE: webserverWEBSERVER_PORT: 6070GITLAB_URL: https://git.example.comGITLAB_ZOEKT_SELF_URL: "http://zoekt_webserver:6070"GITLAB_ZOEKT_VERSION: "v18.3.0"GITLAB_ZOEKT_SECRET_PATH: /.gitlab_shell_secretZOEKT_ENABLE_DEBUG_LOGGING: truevolumes:- ./zoekt/zoekt_index_data:/data/index- ./zoekt/.gitlab_shell_secret:/.gitlab_shell_secret- ./gitlab/data:/var/opt/gitlab # 注意模拟挂载到 /var/opt/gitlabdepends_on:- git.ayaka.spacezoekt_indexer:image: registry.gitlab.com/gitlab-org/build/cng/gitlab-zoekt:v18.3.0container_name: zoekt_indexerrestart: always# 998 is the UID for ./gitlab/data/git-data/repositories/+gitaly# use ls -ln to checkuser: "998:998"ports:- "6065:6065"environment:GITLAB_ZOEKT_MODE: indexerSERVICE_URL: http://zoekt_indexer:6065WEBSERVER_PORT: 6070GITLAB_URL: https://git.example.comGITLAB_ZOEKT_SELF_URL: "http://zoekt_webserver:6070"GITLAB_ZOEKT_VERSION: "v18.2.4"GITLAB_ZOEKT_SECRET_PATH: /.gitlab_shell_secretZOEKT_ENABLE_DEBUG_LOGGING: truevolumes:- ./zoekt/zoekt_index_data:/data/index- ./zoekt/.gitlab_shell_secret:/.gitlab_shell_secret- ./gitlab/data:/var/opt/gitlab # 注意模拟挂载到 /var/opt/gitlabdepends_on:- git.ayaka.spacemem_limit: 8gcpus: '4'

这些工作做完之后,你就可以启动 zoekt,先看容器是否是正常启动的。然后你先可以进入 Web 界面开启:

精确代码搜索设置面板

精确代码搜索设置面板​

在默认情况 Gitlab 18.2.4 之前,他默认只会给新的 Group 或者用户开启这个搜索,不会开启之前旧的名字空间的索引作业的,需要手动指定。比如 <top-level-group-to-index> ​改成你的 root​,就可以索引当前 root 用户下面的项目。

参考链接:Zoekt chart | GitLab Docs

# 需要进入 gitlab 容器然后执行下面的命令
gitlab-rails console
node = ::Search::Zoekt::Node.online.last
namespace = Namespace.find_by_full_path('<top-level-group-to-index>')
enabled_namespace = Search::Zoekt::EnabledNamespace.find_or_create_by(namespace: namespace)
replica = enabled_namespace.replicas.find_or_create_by(namespace_id: enabled_namespace.root_namespace_id)
node.indices.create!(zoekt_enabled_namespace_id: enabled_namespace.id, namespace_id: namespace.id, zoekt_replica_id: replica.id)

处理好后你应该可以看到索引已经重新建立,然后可以在 Web 界面愉快的搜索了。

4)Docker Registery Metadata
a)迁移教程

内部 Issue 链接:2025.08 Week 3: 给个人 Gitlab Registry 迁移到新的 metadata DB (#9) · Issue · Musicminion/personal-plan

首先,Gitlab 18.3 其实默认会运行一个迁移脚本,把容器镜像仓库迁移到新的 Meadata 数据库中,所以最推荐的做法是直接升级到 18.3。

对于旧版本的 Gitlab,如果不想升级,并且又需要开启容器镜像仓库的元数据数据库,需要参考论坛的链接:论坛教程链接

首先需要创建数据库专用用户(友情提示:建议看完 b 部分我写的迁移导致的问题在运行脚本):

gitlab-psql -c "CREATE USER registry WITH PASSWORD 'registrypassword'"
gitlab-psql -c "CREATE DATABASE registry_database WITH OWNER registry"

需要指定数据库的位置、允许外部用户链接:

registry['database'] = {'enabled' => false, # Must be false!'host' => '/var/opt/gitlab/postgresql/','user' => 'registry','password' => 'registrypassword','dbname' => 'registry_database','sslmode' => 'disable'
}postgresql['custom_pg_hba_entries'] = {registry_db: [{type: 'local',database: 'registry_database',user: 'registry',method: 'md5'}]
}

然后配置好之后,参考教程:Gitlab Docs | 开启容器镜像仓库元数据数据库。

# 注意这里 storage 的配置,因为我用的本地存储,所以要指定目录:
registry['storage'] = {'filesystem' => {'rootdirectory' => '/var/opt/gitlab/gitlab-rails/shared/registry'} 'maintenance' => {'readonly' => {'enabled' => true # Must be set to true.}}
}

然后运行迁移脚本:

sudo -u registry gitlab-ctl registry-database migrate up
sudo -u registry gitlab-ctl registry-database import --log-to-stdout

因为在 Docker 里面 sudo 是不可用的,直接可以删掉 sudo -u registry​ 这一部分的,如果不是 Docker 部署,直接在物理机器运行就可以。

迁移完成后,原来的用 false 就可以关闭了,此外 'maintenance'​ 那一栏目也需要删掉,这样用户可以读写了。

registry['database'] = {'enabled' => true,'host' => '/var/opt/gitlab/postgresql/','user' => 'registry','password' => 'registrypassword','dbname' => 'registry_database','sslmode' => 'disable'
}

迁移完成后,容器镜像仓库是可以自动做垃圾回收 GC 的了,理论来说磁盘空间可以节省不少。

发现容器的数据统计不对,需要参考 Gitlab 的教程:Gitlab Issue | 容器镜像仓库 size 为 0 的原因修复,意思就是这个容器镜像占用的空间是静态更新的,或者通过 notifer,配置 notifer 教程在这 配置 Notifer 的官方文档。所以需要再 Gitlab 的配置文件里面添加:

registry['notifications'] = [{'name' => '<test_endpoint>','url' => 'https://<gitlab.example.com>/api/v4/container_registry_event/events','timeout' => '500ms','threshold' => 5, # DEPRECATED: use `maxretries` instead.'maxretries' => 5,'backoff' => '1s','headers' => {"Authorization" => ["<AUTHORIZATION_EXAMPLE_TOKEN>"]}}
]gitlab_rails['registry_notification_secret'] = '<AUTHORIZATION_EXAMPLE_TOKEN>' # Must match the auth token in registry['notifications']

这个 notifer 本质是一个 webhook,当用户推送 docker 镜像之后,就会触发一个作业 worker 的请求,重新统计当前仓库的 Docker 镜像大小。

其中 <AUTHORIZATION_EXAMPLE_TOKEN>​ 需要随机生成的 32 位字符,生成命令如下:

< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c 32 | sed "s/^[0-9]*//"; echo

配置好之后,当你推送镜像,就会触发这个重新计算的操作,并不是立刻显示数据,时延大概是 5 min。效果如下所示,可以看到你用的用量占用了多少 size 了。

使用量配额效果图

使用量配额效果图​

b)迁移导致的问题

补充:如果你已经做了迁移,在更新到 18.3 的时候,注意一个小问题。就是 18.3 的迁移脚本会默认创建一个新的用户。更新之后我发现自己 gitlab 容器镜像数据 30 多 G 全丢,然后排查了很久。

其实按照我前面的迁移教程我已经做了一次了,但是 18.3 启动脚本里面又做了一次迁移。按照我之前的配置,迁移脚本告诉我数据库密码不对。所以启动失败。我首先直接偷懒,把之前配置的数据库用户名密码的部分全都删了,然后发现迁移脚本启动成功了就没管。晚上发现数据都不在了(

然后一看数据库里面有两个 registry 的数据库(一个叫registry​,一个叫registry_database​),显然registry_database ​是新创的,但是巧妙的是,新创的默认 db 的用户名是和我之前做迁移的时候用户完全一样的,所以推测启动迁移脚本可能创建了一个用户,然后正好把这个密码给改掉了,导致迁移脚本告诉我数据库密码不对。所以启动失败。所以我就把用户名密码都删除了。

Gitlab 的数据库的示意图如下:

GitLab 数据库列表

GitLab 数据库列表​

然后创了另外一个用户registry_user​,把数据库的 Owner 修改到新的用户registry_user​,然后修改 Gitlab 里面的配置文件,所有的数据终于回来了。

内部 Issue 链接:2025.08 Week 3: 修复 Gitlab 更新到 18.3 之后容器镜像仓库 Metadata 的问题 (#13) · Issue · Musicminion/personal-plan

http://www.dtcms.com/a/355232.html

相关文章:

  • 鸿蒙Harmony-从零开始构建类似于安卓GreenDao的ORM数据库(五)
  • QP原理讲解
  • 企业微信配置LangBot通信机器人
  • Javascript》》JS》》ES6》》总结
  • 企业招聘难题破解:主流AI面试工具实测对比
  • 【Linux知识】Linux 设置账号密码永不过期
  • Day15 (前端:JavaScript基础阶段)
  • 健永科技RFID技术在羊智能分群管理系统的使用案例
  • leetcode 3446. 按对角线进行矩阵排序 中等
  • 3446. 按对角线进行矩阵排序
  • 前端异常监控,性能监控,埋点,怎么做的
  • 响应式编程框架Reactor【1】
  • React 类生命周期 和 React Hooks 比对
  • 算力沸腾时代,如何保持“冷静”?国鑫液冷SY4108G-G4解锁AI服务器的“绿色空调”!
  • 第五章:Go运行时、内存管理与性能优化之性能分析与pprof工具
  • 配置windows下apache+PHP环境
  • 前端技术之---复制文本
  • docker安装kafka、zookeeper详细步骤
  • 【TEC045-KIT】基于复旦微 FMQL45T900 的全国产化 ARM 开发套件
  • COLMAP 和 SFM的关系是什么?
  • 微服务即时通信系统(十三)--- 项目部署
  • 第十七章 Java基础-常用API-System
  • ArkTS 与 TypeScript 的关系及鸿蒙开发常见错误案例
  • Upload Symbols Failed
  • 万字详解架构设计:业务架构、应用架构、数据架构、技术架构、单体、分布式、微服务都是什么?
  • 只用三招,无招重启钉钉
  • Video Ocean 接入 GPT-5
  • GeoScene Maps 开发-核心地图-标记点管理-用户交互弹窗
  • 大白话拆解力扣算法 HOT 100 - 哈希/双指针/滑动窗口
  • Mac Pro M4芯片 安装 VMware Fusion 和 windows