从9G到0.3G,腾讯会议对他们的git库做了什么?

news2024/11/25 9:49:48

b3ff2df7ebfcabda62546958c1d7f18c.png

358c7b1e9db8e6d5cc2a8094d3805609.gif

👉导读

过去三年在线会议需求井喷,腾讯会议用户量骤增到3亿。快速迭代的背后,腾讯会议团队发现:业务保留了长达5年的历史数据,大量未进行 lfs 转换,新 clone 仓库本地空间占17.7G+。本地磁盘面临严重告急,强烈影响团队 clone 效率。当务之急是将仓库进行瘦身。本栏目特邀腾讯会议的智子研发团队成员李双君,回顾腾讯会议客户端的瘦身历程和经验,欢迎阅读。

👉目录

1 瘦身成效

2 瘦身前事项

3 瘦身整体方案

4 瘦身具体命令执行

5 新代码库验证

6 解决其它设备本地老分支 push 问题

7 其他平台适配

8 最后的验证

9 瘦身完毕后的知会

10 兜底回滚方案

11 踩坑记录及应对

12 写在最后

*作者所在的腾讯会议智子研发团队是腾讯会议的终端团队,负责腾讯会议 Win、Mac、Linux、Android、iOS、小程序、Web 等全栈开发,致力于打造一流的端产品体验。

01

瘦身成效

腾讯会议瘦身完毕后整体收益:

  • Git 仓库大小,9G 到350M。

  • 新 clone 仓库占用空间,从17.7G 到12.2G。

  • 平常拉代码速度(北京地区测试):macbook m1 pro:提升45%;devcloud win:提升56%。

  • 包构建流水线全量拉代码耗时,从16分钟减少到5分钟以内。

e919c87359ddec4e3fc8579b3cb653a7.png

02

瘦身前事项

   2.1 环境准备

使用有线网,看看能否通过其他办法给机器的上传和下载速度提速?不建议在家中开代理来瘦身,因为家里网速一般都没有公司快;如果在家操作,提前配置好远程桌面,远程公司电脑来瘦身。

使用性能较好的机器,硬盘空间至少要有 xxxG 剩余 (可以提前演练,看看究竟要多大磁盘空间?会议最起码得要求有600G 空余)。会议本次瘦身使用的设备是 MAC Book M1 Pro(16寸)笔记本电脑。

   2.2 周知

工作开发群或者邮件等通知瘦身时间和注意事项:

瘦身时间:选一个大家基本上都不会提交代码的时间,比如十一国庆或者春节;会议选的是春节期间。

注意事项:(开发重点关注)

  • 瘦身期间会锁库,必须提前推送代码到远端,否则需要手动同步;

  • 锁库期间无法进行 MR,且已创建 MR 会失效;

  • 因删除历史记录,会导致本地仓库与远端冲突,请恢复后重新 clone 代码;

  • 需要查询或处理更老的代码,需要去备份仓库查看。

   2.3 代码库锁定

禁止代码库写操作,一般公司的代码管理平台可以提供这个功能,Git 项目的 owner 有权限。

   2.4 第三方 Git 平台禁用

如果 Git 项目被第三方 Git 平台使用了,要保证瘦身前仓库的同步任务禁用。

比如,会议使用了 Ugit(UGit 是腾讯内部的一款自研 Git 客户端,主要是为腾讯内部研发环境特点而定制),就要如下禁用项目同步:

6c5db4d11ffb6c925de9aabde21cdd71.png

03

瘦身整体方案

原仓库继续保留作为备份仓库,另外新建仓库,新仓库沿用原仓库的项目名称、版本库路径和 id,并同步原项目数据。

之所以这么做,是为了保证其他平台无缝对接新的 Git 仓库,不用再更换 Git 地址,另外有些通过 api 调用的系统和工具也不受到影响。

瘦身内容:

  • 历史记录删除,只保留最近半年的历史记录。

  • 将历史大文件以及未加入 lfs 的大文件进行 lfs 处理。

04

瘦身具体命令执行

   4.1 clone 项目,拉取所有文件版本到本地

git clone https://example.com/test.git

为了后面的比对验证,可以拷贝一份 test 文件夹放到和 test 同级目录下面的新建的 copyForCompare 文件夹中。

ulimit -n 9999999 # 解决可能出现的报错too many open files的问题
ulimit -n # 查看改成9999999了没

# 遍历拉取所有分支的 lfs 最新文件,并追踪远端分支到本地

# 以下这段 shell 脚本可以直接拷贝到终端运行,也可以创建一个.sh 文件放到根目录执行

cur_index=1
j=1
git branch -r | grep -v '\->' |
  while read remote
  do 
    echo ”deal $cur_index th branch“
    cur_index=$[cur_index+1]
    git branch --track "${remote#origin/}" "$remote"
    echo "begin to lfs fetch branch $remote"
    git lfs fetch origin $remote
    if [ $? -eq 0 ]; then
      echo "fetch branch $remote success"
    else
      echo "fetch branch $remote failed"
      lfs_fetch_fail_array[$j]=$remote
      j=$[j+1]
    fi
  done
if [ ${#lfs_fetch_fail_array[*]} -gt 0 ]; then
    echo "git lfs fetch error branches are: ${lfs_fetch_fail_array[*]}"
else
    echo "fetch all branches success. done."
fi

# 获取所有分支的文件和 lfs 文件版本

git fetch --all
git lfs fetch --all

   4.2 使用 git filter-branch 截断历史记录

这次瘦身只保留最近半年的历史记录,2022.6.1之前的提交记录都删除,所以截断的 commit 节点按如下所述来找:

提前用 sourceTree(或者别的 Git 界面工具)找出来需要截断的那个 commit,以主干 master 为例,找到 master 分支上提交的并且只有一个父的提交节点(如果提交节点有多个父,那么所有父节点都要处理),该节点必须是所有分支的父节点,否则需要考虑其他分支特殊处理的情况,该情况后面的【特殊分支处理】会有说明。

e85fc098ae0b277b2d3d379e3aeaf3ec.png

可以看到选中的截断 commit id 是  ff75cc5cdbf0423a24b4f5438e52683210813ba0

  • 根据上面的 commit id,带入下面的命令,找出其父

git cat-file -p ff75cc5cdbf0423a24b4f5438e52683210813ba0

819ef706c6158e8b43e6220a917267ca.png

可以看到只有一个父,其父是7ffe6782272879056ca9618f1d85a5f9716f8e90 ,所以该提交 id 就是要置为空的。如果有多个父都需要处理。

  • 执行命令

注意:对于普通提交节点,下面命令的 parent 值是"-p parentId";对于合并提交节点,下面命令的 parent 值是"-p parentId1 -p parentId2 -p parentId3 ..."

git filter-branch --force --parent-filter '
    read parent
    if [ "$parent" = "-p 7ffe6782272879056ca9618f1d85a5f9716f8e90" ]
    then
        echo
    else
        echo "$parent"
    fi' --tag-name-filter cat -- --all
  • 重点验证:上述命令执行完毕后,一定要用如下命令检查是否修改成功

注意:因为执行完了命令已经修改了历史记录,此时 Git log 命令执行会慢点,大概5分钟可以出结果,另外可以用这个在线时间戳转换工具来转换时间戳。

工具链接:https://www.beijing-time.org/shijianchuo/

如果执行成功会把之前的文件版本取最新的 add 到这个截断的提交节点里面,如下图:

git log --all-match --author="xxxx" --grep="auto update .code.yml by robot" --name-status --before="1654043400" --after="1654012800" --all

19c06675c928daeb2055489579dd5a8b.png

   4.3 使用 git-filter-repo 清理截断日期前的所有历史记录,并将截断节点的提交信息修改

注意此步骤要谨慎处理,因为这步会真正地删除提交记录。

提前安装好 git-filter-repo,执行下面的 python 代码。

import os
try:
  import git_filter_repo as fr
except ImportError:
  raise SystemExit("Error: Couldn't find git_filter_repo.py. Did you forget to make a symlink to git-filter-repo named git_filter_repo.py or did you forget to put the latter in your PYTHONPATH?")


k_work_dir = "/Volumes/SolidCompany/S_Shoushen/test"
# 2022.6.1 00:00:00
k_clean_history_deadline = b"1654012800"
# 2022.6.1 07:05:07
k_clean_deadline_commit_date = b"1654038307"
k_clean_deadline_commit_author_name = b"xxxxx"
k_new_root_commit_message = "仓库瘦身历史记录裁剪,截断提交记录后新根结点新增历史文件;如果想查看更多历史记录,请去备份仓库:https://example.com/test_backup.git"


def commitCallBackFun(commit, metadata):
    [time_stamp, timezone] = commit.committer_date.split()
    if time_stamp == k_clean_deadline_commit_date and commit.author_name == k_clean_deadline_commit_author_name:
        commit.message = k_new_root_commit_message.encode("utf-8")
    if time_stamp >= k_clean_history_deadline:
        return
    commit.file_changes = []


def main():
    os.chdir(k_work_dir)
    print("git work dir is", os.getcwd())
    args = fr.FilteringOptions.parse_args(['--force', '--debug'])
    filter = fr.RepoFilter(args, commit_callback = commitCallBackFun)
    filter.run()


if __name__ == '__main__':
  main()

验证下截断提交结点的提交信息更改成功了没?

git log --all-match --author="xxx" --grep="仓库瘦身历史记录裁剪" --name-status --before="1654043400" --after="1654012800"

如下就对了:

35b5bae6b78816894fc178149283b7f3.png

以上执行完后做个简单验证:

用 BeyondCompare 工具跟刚开始备份的 copyForCompare 目录下的 test 仓库对比,看看有没有增删改文件,期望应该没有任何变化才对。

  • 特殊分支处理

说明:以上历史记录裁剪并删除历史提交记录执行完后,对于基于截断提交节点的提交节点创建出来的分支或者其子分支会出现文件被删除或者整个分支被删除的情况。

afe2b451bf4902fe3255daa452cc37e9.png

所以要提前弄清楚有没有在截断节点之前早就创建出来一直在用的分支,如果有就得特殊处理上面的2和3步骤了:

第2步中截断历史记录的时候,要类似分析 master 分支那样分析其它需要保留的特殊分支,找出各自的截断节点的父提交 id;然后执行的 shell 脚本里面条件判断改成判断所有的父提交 id;类似这样:

git filter-branch --force --parent-filter '
 read parent
 if [ "$parent" = "-p 85f5ee6314f4f46cc47eb02c6af93bd3020a1053 -p cd207e9b3372f68a6d1ffe06fcf189d952e3bf9f" ] || [ "$parent" = "-p 7ffe6782272879056ca9618f1d85a5f9716f8e90" ]
 then
   echo
 else
   echo "$parent" 
 fi' --tag-name-filter cat -- --all

第3步中删除截断节点前提交记录的 python 脚本里面,按照分支名字和自己分支的截断日期来做比对逻辑进行删除提交记录的操作。类似如下:

#!/usr/bin/env python3
import os
try:
  import git_filter_repo as fr
except ImportError:
  raise SystemExit("Error: Couldn't find git_filter_repo.py. Did you forget to make a symlink to git-filter-repo named git_filter_repo.py or did you forget to put the latter in your PYTHONPATH?")


k_work_dir = "/Users/jevon/Disk/work/appShoushen/shoushen/test"


# 2022.6.1 07:05:07
k_master_cut_date = b"1654038307"


# 2022.3.25 19:32:00
k_private_new_saas_sdk_master_cut_date = b"1648207920"


k_new_root_commit_message = "仓库瘦身历史记录裁剪,截断提交记录后新根结点新增历史文件;如果想查看更多历史记录,请去备份仓库:https://example.com/test_backup.git"


def commitCallBackFun(commit, metadata):
    [time_stamp, timezone] = commit.committer_date.split()
    # 每个特殊分支的截断提交点的提交信息修改
    if (time_stamp == k_master_cut_date and commit.author_name == b"xxx_author1") or \
       (time_stamp == k_private_new_saas_sdk_master_cut_date and commit.author_name == b"xxx_author2"):
        commit.message = k_new_root_commit_message.encode("utf-8")


    # 每个特殊分支的截断提交点前的提交记录,需要根据各自截止日期来做比对删除日期前的历史记录
    strBranch = commit.branch.decode("utf-8")
    if strBranch.endswith("refs/heads/master"):
        if time_stamp < k_master_cut_date:
            commit.file_changes = []
    elif strBranch.endswith("refs/heads/private/feature/3.12.1/new-saas-sdk-master"):
        if time_stamp < k_private_new_saas_sdk_master_cut_date:
            commit.file_changes = []
def main():
    os.chdir(k_work_dir)
    print("git work dir is", os.getcwd())
    args = fr.FilteringOptions.parse_args(['--force', '--debug'])
    filter = fr.RepoFilter(args, commit_callback = commitCallBackFun)
    filter.run()


if __name__ == '__main__':
  main()

以上[特殊分支处理]没有实验过,但是个解决思路,具体实践结果待补充,也欢迎实验过的同学交流。

   4.4 进行 lfs 转换

rm -Rf .git/refs/original
rm -Rf .git/logs
git branch | wc -l # 看一下本地分支总数
# 拷贝原来的仓库到新目录下面
git clone file:///Users/jevon/Disk/work/appShoushen/shoushen/test  /Users/jevon/Disk/work/appShoushen/shoushen/test_new
cd test_new
git branch -r | grep -v '\->' |
  while read remote
  do 
    git branch --track "${remote#origin/}" "$remote"
  done
git fetch --all git branch | wc -l # 看一下本地分支总数,和拷贝之前是否一样
# 分析仓库中占用空间较大的文件类型(演练的时候可以提前分析出来,节省瘦身时间)
git lfs migrate info --top=100 --everything

命令结果如下,是按照文件所有的历史版本累加统计的,只有未加入 lfs 的才会统计。

a380162953880238779bd3f644bfe741.png

git rev-list --objects --all | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | sed -n 's/^blob //p' | sort --numeric-sort --key=2 | cut -c 1-12,41- | $(command -v gnumfmt || echo numfmt) --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest | grep MiB

该命令执行结果如下,是把所有大于 1Mb 的文件版本都列出来了,不进行累加,从小到大排序,已经加入 lfs 的不会统计。

d28b6ffd7b57d9921979d6911444c53b.png

# lfs转换
# --include=之后填入根据实际分析的大文件列表
git lfs migrate import --everything --include="*.jar,tool/ATG/index.js,xxx"
# 上面lfs转换执行完后,看一下根目录的.gitattribute文件里面是不是加入了新的lfs文件了

   4.5 新建新仓库,推送所有历史记录修改

新创建目标仓库 test_backup.git ,然后运行下面代码:

git remote remove origin
git remote add origin https://example.com/test_backup.git
git remote set-url origin https://example.com/test_backup.git
git remote -v # 确保设置成功新仓库地址

此时可以用下面的命令看看还有没有大文件了(可选)。

git rev-list --objects --all | git cat-file --batch-check='%(objecttype) %(objectname) %(objectsize) %(rest)' | sed -n 's/^blob //p' | sort --numeric-sort --key=2 | cut -c 1-12,41- | $(command -v gnumfmt || echo numfmt) --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest | grep MiB

用以下命令看看还有没有未转换的大的 lfs 文件了(可选)。

git lfs migrate info --top=100 --everything
# 推送历史记录修改到目标新仓库:
git push origin --no-verify --all
git push origin --no-verify --tags

   4.6 回到原来的 test 目录,推送 lfs 文件

cd ../test
git config lfs. https://example.com/test_backup.git /info/lfs.access basic
git lfs env # 看一下改成了basic了吗
# 设置成远端目标仓库test_backup.git
git remote remove origin
git remote add origin https://example.com/test_backup.git
git remote set-url origin https://example.com/test_backup.git
git remote -v # 确保设置成功新仓库地址

c7e71e21212d2ad8d765ed9f4574ab27.png

将 upload_objects.sh 拷贝到 test 目录,然后执行  sh ./upload_objects.sh

upload_objects.sh 内容如下:

#!/bin/bash


set -e


count=$(find .git/lfs/objects -type f | wc -l)
echo "-- total objects count is $count"


index=0
concurrency=25


find .git/lfs/objects -type f | awk -F '/' '{print $NF}' | while read -r obj; do
  echo "-- $(date) -- uploading ($index/$count) $obj"
  git lfs push origin --object-id "$obj" &
  index=$((index+1))
  if [[ $index%$concurrency -eq 0 ]]; then
    echo -e "\r\n-- $(date) -- waiting --------------------------\r\n"
    wait
  fi
done

注意脚本里面的并发值不能设置太高,不然会报错./upload_objects.sh: line 12: echo: write error: Interrupted system call,测试发现设置25是比较合适的。

8fd77dd8e78127ba8c24c57df185a6fd.png

确保像上图这样,最后一个也上传成功。

05

新代码库验证

git clone https://example.com/test_backup.git

使用 git lfs pull 先拉取主干分支所有的历史文件进行测试,保留瘦身的本地仓库; 后续如果发现有其他分支的 lfs 文件没有上传成功,再单独上传即可。

上传命令:

git lfs push --object-id origin "$objId"

对比新旧代码库主干最新代码是否一致,可使用 beyond compare 工具进行验证。四端编译不同代表性的分支运行验证。

06

解决其它设备本地老分支 push 问题

在公司的代码管理平台上设置瘦身后的 test_backup 仓库单文件大小上限为1.5M。

一般公司自己的代码管理平台都会提供设置单个 git 文件上传大小上限的功能,得管理员才有权限设置;腾讯的代码管理平台是像下图这样设置的:

44eb64b6e4cb495b736b00d8762f5751.png

解释:之后的步骤将会把新老仓库互换,新旧仓库互换后,其它机器本地的老仓库分支还是有 push 上去的风险,这样就会把瘦身前的历史记录又推送到瘦身后的 Git 仓库,造成瘦身白费。

07

其他平台适配

   7.1 代码管理平台

找代码管理平台协助完成下面的操作:(需要提前预约沟通好)

会议用的代码管理平台是工蜂:

项目名称、版本库路径互换:test_backup 重命名为 test,test 重命名为 test_backup。

将两个项目项目 id 进行调换:新项目沿用旧项目的项目 id,以此保证通过 api 调用的系统和工具不受到影响。

项目数据同步:同步项目成员和权限相关的数据、保护分支规则组到新仓库。

自己工蜂适配(可以提前进行)。对照老工蜂的所有配置,在新工蜂上手动同步修改。

   7.2 第三方 Git 工具

如果使用了第三方 Git 工具平台做过瘦身仓库与其他项目仓库的同步,需要处理下(会议使用了 UGit 第三方工具):

  • 通知 UGit 相关负责人把旧的工作区移除一下,重新 clone test 仓库。

  • 把 Ugit 里面 test 仓库的同步任务恢复(如有需要)。

   7.3 出包流水线构建平台

因为执行完瘦身后,Git 的 commit id 都变了,历史记录也变了,而 coding 的构建机如果不清理缓存删掉老仓库的话,会导致构建机本地仓库历史与远端冲突,执行 Git 命令会异常,所以 coding 必须要清理掉老仓库,重新 clone。

08

最后的验证

代码管理平台以及出包构建平台都处理完成后,进行最后的验证。

本地验证:

  • 本地是否能正常 clone 代码。

  • 本地对比新旧仓库主干最新代码是否一致。

  • 本地随机抽取分支对比新旧仓库文件个数以及最新代码是否一致。

  • 本地编译验证,程序启动主流程验证。

出包构建平台验证:

  • 主干分支、发布分支、个人需求分支、个人分支等的构建验证。

代码管理平台验证:

  • 代码库基础、高级配置是否正确

  • 保护分支规则配置是否正确,是否有效

  • 项目成员是否和原仓库一致

  • MR 是否可正常发起、合并,能否正常调起检测流水线

代码库写权限恢复:

  • 保证瘦身后的 Git 仓库恢复写权限;备份仓库禁用写权限。

09

瘦身完毕后的知会

知会参考模板:

xxx 仓库瘦身完成了!

接下来需要开发重点关注:

  • 本地旧仓库已经失效,必须删掉重新 clone 代码【最最重要】

  • 未提前push到远端的本地新增代码需要手动同步

  • 旧的未完成的MR已经失效,需要关闭后重新发起

  • 需要查询或处理更老的代码,需要去备份仓库查看(xxxx/xxxx.git)

开发过程中有任何疑问,欢迎请随时联系 xxx

10

兜底回滚方案

因为使用了备份仓库,所以不会修改原始仓库,但只有代码管理平台(工蜂)在第七步的时候修改了原始仓库,对于这个工蜂的协助修改,需要提前确认好工蜂那边做好了回滚的方案。

11

踩坑记录及应对

   11.1 上传 lfs 的时候报错 User is null or anonymous user

9556864543b88211b0c5f99704cc6473.png

LFS: Git:User is null or anonymous user.

解决:git config lfs.https://example.com/test_backup.git/info/lfs.access basic

输入 git lfs env 看一下输出结果改成了 basic 了吗?

6384825ad7b01653a059cc0f640596e3.png

   11.2 git push 的时候报错

5f15446466dcea0f89edf66866826f14.png

把远程链接改成 https 的:

git remote set-url origin https://example.com/test_backup.git
git remote -v

如果~/.gitconfig 中有如下的内容要先注释掉。

url.git@example.com:.insteadof=http://example.com/ url.git@example.com:.insteadof=https://example.com/

最后再 push 即可。

如果上述还不行,那么在命令行中执行:

git config --global https.postbuffer 1572864000git config --global https.lowSpeedLimit 0git config --global https.lowSpeedTime 999999


如仍然无法解决,可能是用户的客户端默认有设默认值限制 git 传输包的大小,可执行指令:

git config --global core.packedGitLimit 2048m
git config --global core.packedGitWindowSize 2048m

   11.3 window 如何在 git batch 里面运行 git-filter-repo?

安装 python:打开 cmd 窗口,运行 python -m pip install git-filter-repo,安装 git-filter-repo;

用 everything 查找 git-filter-repo.exe;

cmd 窗口,运行 git --exec-path,得到路径类似:C:\Program Files\Git\mingw64\libexec\git-core;

把上面找到的 git-filter-repo.exe 拷贝到 git-core 文件夹里面;

此时在 git batch 窗口中,输入命令 git filter-repo(注意输入的git后面没有-),会提示 No arguments specified.证明 ok 了。

   11.4 如果想让 git-filter-repo 作为一个 python 库来使用,实现更复杂的功能该怎么办?

比如,不想这么用了 git-filter-repo --force --commit-callback "xxxx python code...",因为这么用只能写回调的 python 代码,太弱了。

解决:python3 -m pip install --user git-filter-repo,不行就 python3 -m pip install git-filter-repo,安装这个 git-filter-repo包,然后就可以在 python 代码中作为库使用:import git_filter_repo as fr。

   11.5 瘦身后发现 coding 的 win 构建机器在 clone 代码时出问题,怎么办?

卡在 git lfs pull:

1b2d21b95ed4fd442f60644fe8e1f744.png

卡在 git checkout --force xxxxx 提交 id:

1c3ce0704204c2cc11d03dab22ff8abe.png

卡在 checking out files:

1505fb561462d1cd21b2ed665bf9f86d.png

调查发现,是 lfs 进程卡住,不知道什么样的场景触发的,官方有个类似 issue,以上问题均是因为 git 或者 git lfs 版本过低导致的,升级到高版本即可解决。

据当时出错 case 总结得出结论,以下 git 和 git lfs 的版本号可以保证稳定运行不出问题,如果版本号低于以下所示,最好升级。

127c0bf96abe0f07580e09d7505f2a51.png

   11.6 执行 git lfs fetch 的时候报错 too many open files 的问题

解决办法:ulimit -n 9999999

12

写在最后

仓库瘦身是个细致耗时的工作,需要谨慎认真地完成。最后腾讯会议客户端仓库的大小也从 9G 瘦身到 350M ,实现的效果还是不错的。

本次我们分享了仓库瘦身的全历程,把执行命令也公示给各位读者。希望可以帮助到为类似困境而头疼的开发者们。这篇文章对您有帮助的话,欢迎转发分享。

-End-

原创作者|李双君

技术责编|陈从贵、郭浩伟

c82ea165762d68e5112192a4a255a543.png

欢迎分享你使用Git库的小技巧,我们将选取1则最有意义的评论,送出腾讯云开发者-透明手袋1个(见下图)。8月2日中午12点开奖。

fcd638dc1f5d6adc7d43ee0ace32ad26.png

37a9a399c8c6b35183ffb4d8acdcd983.png

97ca0091283c0033ee8546770d954413.png

578d74864c5ae199977fcfd48d80cc9a.png

18382617d2b41af0befa0296a8ea902b.png

关注并星标腾讯云开发者

第一时间看鹅厂技术

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/795740.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

FastSAM 论文解读

论文名称&#xff1a;Fast Segment Anything 论文地址&#xff1a;http://export.arxiv.org/pdf/2306.12156 代码地址&#xff1a;GitHub - CASIA-IVA-Lab/FastSAM: Fast Segment Anything 1. 关键内容 基于YOLOv8-seg实现了FastSAM&#xff0c;它比SAM快50倍&#xff0c;且…

数仓学习---15、数据仓库工作流调度

1、数据仓库工作流调度 1.1 调度工具部署 工具部署链接 1.2 新数据生成 1.2.1 用户行为日志 1、启动日志采集通道&#xff0c;包括Kafka、Flume等 &#xff08;1&#xff09;启动Zookeeper zk.sh start&#xff08;2&#xff09;启动Kafka kf.sh start&#xff08;3&…

【雕爷学编程】Arduino动手做(95)---GY9960手势传感器模块3

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…

电容触摸屏(TP)的工艺结构

液晶显示屏(LCM),触摸屏(TP) “GG、GP、GF”这是结构分类&#xff0c;第一个字母表面材质&#xff08;又称为上层&#xff09;&#xff0c;第二个字母是触摸屏的材质&#xff08;又称为下层&#xff09;&#xff0c;两者贴合在一起。 G玻璃&#xff0c;FFILM&#xff0c;“”贴…

华为eNSP:路由引入

一、拓扑图 二、路由器的配置 1、配置路由器的IP AR1&#xff1a; [Huawei]int g0/0/0 [Huawei-GigabitEthernet0/0/0]ip add 1.1.1.1 24 [Huawei-GigabitEthernet0/0/0]qu AR2&#xff1a; [Huawei]int g0/0/0 [Huawei-GigabitEthernet0/0/0]ip add 1.1.1.2 24 [Huaw…

HarmonyOS学习路之方舟开发框架—学习ArkTS语言(状态管理 一)

状态管理概述 在前文的描述中&#xff0c;我们构建的页面多为静态界面。如果希望构建一个动态的、有交互的界面&#xff0c;就需要引入“状态”的概念。 图1 效果图 上面的示例中&#xff0c;用户与应用程序的交互触发了文本状态变更&#xff0c;状态变更引起了UI渲染&#x…

Blazor实战——Known框架多表增删改查

多表增删改查示例 本章介绍学习多张表增、删、改、查功能如何实现&#xff0c;下面以销货出库单作为示例&#xff0c;该业务栏位如下&#xff1a; 销货出库单栏位 销货单号、销货日期、状态、客户、备注 销货出库单明细栏位 商品编码、商品名称、规格型号、数量、单位、单价、…

详解rocketMq通信模块升级构想

本文从开发者的角度深入解析了基于netty的通信模块, 并通过简易扩展实现微服务化通信工具雏形, 适合于想要了解netty通信框架的使用案例, 想了解中间件通信模块设计, 以及微服务通信底层架构的同学。希望此文能给大家带来通信模块架构灵感。 概述 网络通信是很常见的需求&#…

065、故障处理之OMM_TiKV

TiKV Server OOM 对业务的影响 TiKV 上的请求失败造成异常退出region leader重新选举 raft group 开始选举新的 region leader新的region leader 上报信息给PD Server region cache频繁更新 在访问TiDB Server的region cache时&#xff0c;出现TiKV rpc相关报错后台自动进行Ba…

解放程序员,加速创新,缺少的就是一个工具而已

随着科技的不断进步和应用场景的不断扩大&#xff0c;软件开发已经成为当今世界的核心驱动力之一。 然而&#xff0c;传统的软件开发模式往往存在着繁琐的编码过程、复杂的架构设计和漫长的调试周期&#xff0c;使得程序员们难以专注于创新和高难度的研究。 很多程序员上班的时…

基于解析法和遗传算法相结合的配电网多台分布式电源降损配置(Matlab实现)

目录 1 概述 2 数学模型 2.1 问题表述 2.2 DG的最佳位置和容量&#xff08;解析法&#xff09; 2.3 使用 GA 进行最佳功率因数确定和 DG 分配 3 仿真结果与讨论 3.1 33 节点测试配电系统的仿真 3.2 69 节点测试配电系统仿真 4 结论 1 概述 为了使系统网损达到最低值&a…

一分钟学会利用GPT编写爆款标题

&#x1f3c6; 文章目标&#xff1a;学习利用GPT编写爆款标题 &#x1f340; 入门篇&#xff1a;一分钟学会利用GPT编写爆款标题 ✅ 创作者&#xff1a;熊猫Jay ✨ 个人公众号: 熊猫Jay字节之旅 (文末有链接) &#x1f341; 展望&#xff1a;若本篇讲解内容帮助到您&#xff0c…

Web网站性能压测实践 | 数据平台

一、 为什么要做压测&#xff1f; 首先解释下为什么要做性能压测&#xff1a;根据 Amazon 统计&#xff0c;每慢 100 毫秒&#xff0c;交易额下降 1%。这个统计数据为大家敲响了警钟&#xff0c;也客观说明了性能压测对于企业应用的重要性。从具体的OKR上讲&#xff0c;我们希望…

常见排序算法-Python实现

python 排序 算法 1.二分法 ​ python 32行 #codingutf-8 def binary_search(input_array, value): """Your code goes here.""" length len(input_array) left 0 right length-1 if length 1: return 0 if value input_value[0] els…

Linux 多线程并发Socket服务端的实现( 11 ) -【Linux通信架构系列 】

系列文章目录 C技能系列 Linux通信架构系列 C高性能优化编程系列 深入理解软件架构设计系列 高级C并发线程编程 设计模式系列 期待你的关注哦&#xff01;&#xff01;&#xff01; 现在的一切都是为将来的梦想编织翅膀&#xff0c;让梦想在现实中展翅高飞。 Now everythi…

3秒快速打开 jupyter notebook

利用 bat 脚本&#xff0c;实现一键打开 minconda 特点&#xff1a; 1、可指定 python 环境 2、可指定 jupyter 目录 一、配置环境 minconda 可以搭建不同的 python 环境&#xff0c;所以我们需要找到 minconda 安装目录&#xff0c;把对应目录添加到电脑环境 PATH 中&#…

prepros.crack.7.8.5 by Xacker

您友好的 Web 开发伙伴 Prepros 编译您的文件&#xff0c;转译您的 JavaScript&#xff0c;重新加载您的浏览器&#xff0c;并使开发和测试您的网站变得非常容易&#xff0c;这样您就可以专注于使它们完美。 适用于 Windows、macOS 和 Linux 试用版包括所有 Prepros 功能。 编…

【数据结构】树状数组和线段树

树状数组和线段树 下文为自己的题解总结&#xff0c;参考其他题解写成&#xff0c;取其精华&#xff0c;做以笔记&#xff0c;如有描述不清楚或者错误麻烦指正&#xff0c;不胜感激&#xff0c;不喜勿喷&#xff01; 树状数组 需求&#xff1a; 能够快速计算区间和保证在修改…

了解 MySQL 中 MVCC 的原理

点击上方↑“追梦 Java”关注&#xff0c;一起追梦&#xff01; 要解决读一致性的问题&#xff0c;保证一个事务中前后两次读取数据结果一致&#xff0c;还有一种 MVCC 的方式&#xff0c;又叫多版本的并发控制&#xff08;Multi Version Concurrency Control&#xff09;。 MV…

Flink状态的理解

Flink是一个带状态的数据处理系统&#xff1b;系统在处理数据的过程中&#xff0c;各算子所记录的状态会随着数据的处理而不断变化&#xff1b; 1. 状态 所谓状态State&#xff0c;一般指一个具体的 Task 的状态&#xff0c;即线程处理过程中需要保存的历史数据或历史累计数据…