普通视图

发现新文章,点击刷新页面。
昨天以前zu1k

从 ASAN Stuck 到 Open Files Limit

作者 zu1k
2023年6月14日 16:00

Sanitizers 是好东西,可以帮助程序员检测错误并提供详细的错误报告。但前两天我遇到了一个问题,在我实验室主机的 Docker 容器中,AddressSanitizer 输出几行 Error 概述信息后,无法输出调用堆栈信息以及后续内容,程序会卡在这里,并且一个子进程会占满一个 CPU 核心。这件事我花了两天时间来排查,最终确定竟然是由于打开文件数限制设置太大导致的。请听我道来。

发现问题

我准备了一个最小的 POC,用来重现本次事件的整个流程。以下是一个简单的 c 程序,如果直接编译运行会出现 SegmentFault,因为出现了越界写。

1
2
3
4
void main() {
    char *str = "abc";
    str[10] = 'z';
}

使用 clang 编译并开启 AddressSanitizer: clang -g -fsanitize=address -fno-omit-frame-pointer -o target_asan poc.c

正常情况下运行应该很快输出调用堆栈信息,如图:

/posts/linux/large-nofile-cause-asan-stuck/asan_normal_works_hu843adcb9f4c3ef501072e5b1b984d972_142890_1243x1001_resize_q75_h2_box_3.webp
AddressSanitizer 正常输出

而这在我的 Docker 容器中就会卡住,通过 top 命令可以看到一个子进程占满一个 CPU 核心:

/posts/linux/large-nofile-cause-asan-stuck/asan_stuck_hu6ff1142a74841c83d7167d84a2641030_34280_947x278_resize_q75_h2_box_3.webp
卡住的情况

我一开始以为程序就这样进入死循环了,谁知道等了几分钟竟然也输出了结果。

于是我开始查资料,在 LLVM 文档 中提到可以通过设置环境变量 ASAN_OPTIONS=symbolize=0 来关闭 symbolize 流程。实验发现关闭符号解析后可以顺利输出后续内容。

/posts/linux/large-nofile-cause-asan-stuck/asan_options_symbolize_off_huad9cb65d0ed5337ff5eff9c1267928d2_70146_1247x311_resize_q75_h2_box_3.webp
关闭 symbolize 可以顺利输出

一开始我以为是符号解析器出 bug 了,尝试切换符号解析器,将默认的 llvm-symbolizer 替换成 GNU addr2line

ASAN_SYMBOLIZER_PATH=/usr/bin/addr2line ./target_asan

/posts/linux/large-nofile-cause-asan-stuck/addr2line_also_stuck_hu8684916663b9aea2101a5b0c731c9e79_37682_915x265_resize_q75_h2_box_3.webp
addr2line 仍然会卡住

仍然卡住,于是我怀疑不是 llvm-symbolizer 的问题,感觉有可能是系统内核的问题,或者因为最新版 Docker 与内核冲突了?具体也不清楚,反正没有头绪。

当我把程序拷贝到宿主机上运行时,这个问题就莫名其妙的消失了。我将容器打包拷贝到同学的 Ubuntu 下,无法复现问题,也是顺利输出。我还尝试了将 Host 内核降级到 5.15,将 Docker/Containerd/runc 版本降级到与同学 Ubuntu 上相同的版本,均无法解决问题。

后面通过 strace 发现 AddressSanitizer 卡在 read 系统调用上,并通过上下文猜到与 llvm-symbolizer 交互的流程。

/posts/linux/large-nofile-cause-asan-stuck/strace_stuck_in_read_hucfed7316ff0b1fed3a9a63b776d472d2_56014_907x471_resize_q75_h2_box_3.webp
strace 发现卡 read 系统调用

这里可以看到 AddressSanitizer 通过 fork 子进程,然后通过 pipe 的方式与子进程通讯,写 CODE "binary_path" offset\n 来请求查询 binaryoffset 位置对应的符号信息,如果查询成功会返回源代码、行号、函数名等符号信息。

我尝试手动运行 llvm-symbolizer,正常输出没有任何问题。

但是这个时候我是一筹莫展,睡觉前在 Twitter 上求助,看看有没有人也遇到过这个问题。

深入

根据网友 whsloef 的回复,我打印了阻塞的进程的调用栈,跟我通过 strace 得到的结论相同,是卡 read 系统调用了。

/posts/linux/large-nofile-cause-asan-stuck/cat_stack_hu91b90d96476c14248a3c1870987a44bd_56594_1253x302_resize_q75_h2_box_3.webp
打印调用栈

然后根据网友 Ningcong Chen 回复 的一个历史 issue,我尝试用 gdb 来附加阻塞进程。(我之前考虑过给占用 100% 的进程做 profile,看看到底是什么行为占满 CPU,但考虑 AddressSanitizer 是 clang 注入的,不清楚好不好做,于是就没做)

/posts/linux/large-nofile-cause-asan-stuck/gdb_attach_1_hu5fd188a493f98ec7189955c1da6cca08_6245292_2503x830_resize_q75_h2_box_3.webp
附加主进程

附加主进程后,发现卡在 internal_read,推测是子进程没有返回。

/posts/linux/large-nofile-cause-asan-stuck/gdb_attach_2_hu6d0f57975e98a16e3a64039d6dd5528d_257129_2384x791_resize_q75_h2_box_3.webp
附加子进程

附加子进程,发现卡在一个 for 循环上,通过调用栈信息,从 GitHub 上下载了源码,开始分析原因。

通过 LLVM compiler-rt 源码,定位到 compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp#L465,我把 StartSubprocess 简化为以下流程:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
pid_t StartSubprocess(const char *program, const char *const argv[],
                      const char *const envp[], fd_t stdin_fd, fd_t stdout_fd,
                      fd_t stderr_fd) {
  
  int pid = internal_fork();

  if (pid == 0) {
    for (int fd = sysconf(_SC_OPEN_MAX); fd > 2; fd--) internal_close(fd);

    internal_execve(program, const_cast<char **>(&argv[0]),
                    const_cast<char *const *>(envp));
    internal__exit(1);
  }

  return pid;
}

这是一个典型的启动子进程的方法,先 fork,然后在子进程中关闭不必要的文件描述符,最后通过 execve 启动目标程序。

但 LLVM 这里通过 int fd = sysconf(_SC_OPEN_MAX) 获取最大文件打开数,然后循环关闭,在文件打开数限制很大的情况下就会进行很多不必要的系统调用,从而导致耗时又占 CPU,最终导致我出现我上面那种假死的情况,实际上进程正在忙着关闭不存在的文件描述符。

通过在容器内运行 ulimit -n 发现容器内的文件描述符限制是 1073741816,而对比宿主机的限制 1024,这种差异就是我将程序拷贝到宿主机就无法复线问题的重要原因。

我尝试在运行容器的时候加一个打开文件数限制 --ulimit nofile=1024:1024,问题顺利解决。

原来网友 lightning1141 的回复 是让我看文件打开数是不是太大的意思啊,我还以为是看看够不够用呢。我之前一直以为这个东西设置的越大越好的,我 too naive too simple.

思考

但既然宿主机限制是 1024,那为什么在 Docker 容器里的限制却有 1073741816

我根据经验查询了以下文件,发现打开文件数均为默认,并未指定特定数值:

  • /etc/security/limits.conf
  • /etc/systemd/system.conf
  • /etc/systemd/user.conf

然后查看 docker 相关限制,因为由 systemd 管理,所以查看以下文件:

  • /usr/lib/systemd/system/docker.service
  • /usr/lib/systemd/system/containerd.service

在服务文件中均指定 LimitNOFILE=infinity,由此导致打开文件数不受限制,通过 cat /proc/sys/fs/nr_open 查看内核默认的进程打开文件数限制,发现是 1073741816。而在同学的 ubuntu 机器上 nr_open 是 1048576

这种发行版的细微差别导致的问题真是难以排查啊!

解决方案

修改 Containerd 文件描述符限制

修改 /usr/lib/systemd/system/containerd.service

1
2
[Service]                                                                                                                     
LimitNOFILE=1048576

无需修改 /usr/lib/systemd/system/docker.service

或者在启动容器的时候添加限制 --ulimit nofile=1048576:1048576

docker run -it --ulimit nofile=1048576:1048576 ubuntu:18.04 /bin/bash

修改 LLVM 中逻辑

可以修改 LLVM 源码,使用 close_range 或者 closefrom 系统调用替换 close.

  • close_range Linux kernel 5.9 增加, 在 BSD 也可用
  • closefrom FreeBSD 8.0 引入, 在 Linux 上需要链接 libbsd

可惜的是这两个都不是 POSIX 规范定义的系统调用,不过我认为这后面会成为主流的。

只改了 Linux 的版本,并且需要 Kernel 5.9 以上。

后续

在 GitHub 上相应仓库提起了 issue,等待改进。虽然自己改了一个 Linux 的可以用了,但是考虑到 LLVM 需要保证兼容性,这里也不敢去提 PR,毕竟要求 Linux 5.9 以上版本可不是一个兼容性好的方案。(我在 ubuntu 18.04 的 docker 里就没办法编译通过,unistd.h 里没有定义 #define __NR_close_range 436

突然想到了一个之前别人问的一个问题:当我运行 >500 个线程时代理开始失败

既然很多发行版单进程最大文件打开数是 1024,那这个问题就好推测了。这个代理程序对每一个连接需要打开两个文件描述符,一进一出嘛,那并发上不了 500,就是因为 1024 太小了。改一下就能解决。

谈谈 Mastodon、Fediverse 和 ActivityPub

作者 zu1k
2023年1月26日 19:29

埃隆·马斯克 440 亿美元拿下 Twitter 后就开始大刀阔斧进行改革,他要做推特 2.0,但没想到他的举措竟然是大量裁员,施行专政。接下来的一系列举措使 Twitter 俨然已经成为某些人自我营销和推广的个人发布平台,想必是之前通过 Twitter 割虚拟货币韭菜割爽了。我想未来老马利用 Twitter 宣传进入政界也不足为奇。于是很多人便开始考虑脱离专制的 Twitter 平台,寻找一个更加开放自由、权力更加分散的平台,Mastodon 凭借多年的技术积累、好看的 UI 和类 Twitter 的交互逻辑,一举跃入众人的视野。

Mastodon

Mastodon 又叫长毛象,我是 21 年左右在某个论坛看到 “草莓县”(cmx.im) 从而接触并了解了 Mastodon。Mastodon 从 16 年就开始开发,在我第一次接触它的时候 UI 就已经很美观了,其在 22 年进入大众视野并受到大家喜爱我一点也不感到奇怪,这么长时间的积累使 Mastodon 的成功成为历史的必然。

Mastodon 开源、去中心化(联邦制)的特性决定了任何个人和组织都可以搭建自己的 Mastodon 实例,从而加入到这个社交网络中来,人们既可以按照爱好、观念聚集在某个实例中,同时又可以与其他实例的用户进行各种交互,这种小邦大连的社交模式真的深得人心。

简单来说,作为用户,你可以从众多实例中根据喜好选择其中一个,注册账号,然后你就可以像推特一样发嘟(类比推特的发推),关注其他用户,查看时间线。与推特不同的一点是,如果你关注的用户注册在其他实例,那你就需要通过用户名加域名的方式来定位他。这有一点需要注意,在不同的实例中可能有多个用户有相同的用户名,所以实例的域名也是非常重要的一部分。因此,如果你想要打造个人品牌,就需要考虑防止有人通过一比一复制你的用户名、头像、介绍等信息来冒充你,也许提供 GPG 公钥是个不错的选择,貌似目前 Mastodon 没有集成成熟的解决方案来避免冒充问题。

据我所知国内部分高校组建了一个自己的小联邦,这个小联邦中每个学校都是一个独立的 Mastodon 实例,每个学校的实例都由本校学生独立自治,同时加入这个高校联邦的所有实例之间又可以互相交互。这个小联邦叫 闭社,感兴趣的同学可以关注一下,搭建自己学校的实例并加入其中。

Fediverse

其实 Mastodon 并不是唯一的 Fediverse,Fediverse 这个词也不是 Mastodon 首创,早在 2008 年就有人提出来了这个概念,并构想社交和内容发布平台要满足独立托管、通过标准化协议通讯等概念。仔细想想,这些概念是不是跟 Email 很像?Email 可是在互联网发明之初就流行的协议,看起来互联网的发展过程也是轮回的,分久必合(商业公司中心化体验好)、合久必分(去中心化自由、自治)。这里我推荐阅读这篇文章: Mastodon, the rise of the Fediverse

目前最流行的 Fediverse 当属社交领域的 Mastodon 和即时通讯领域的 Matrix。据我了解,Matrix 的技术生态更加繁荣,有众多服务端和客户端的实现,同时也可以对接 Slack、Discord、Telegram、QQ、WeChat 等众多通讯 APP,但是目前看起来非技术爱好者用的并不多,大部分用户都是开发者和技术爱好者。而 Mastodon 的客户端虽有很多,但服务端只有官方一个实现,称不上技术生态繁荣,但是用户却遍地开花,特别是普通非技术用户。这种现象需要引起思考,技术虽可以改变世界,但技术并不是唯一,更好的UI、更好的交互、更好的体验,这些才是带来产品发展的外部动力的基础。

目前我的主要社交媒体还是 Twitter,正在慢慢向 Mastodon 转,主要是有很多要关注的人他们并没有在 Mastodon 宇宙安家。即时通讯方面除开熟人通讯必要的 QQ 和微信,陌生人通讯我正在逐渐放弃 Telegram,因为 Telegram 也正在变得封闭、专制、商业化,我在很多 Matrix 实例上都有匿名账户,但是我的朋友并不愿意来到 Matrix 网络,因此目前我的陌生人通讯主力是邮箱,我会对外公开我的邮箱地址,任何人都可以给我发邮件交流。

除了上面提到的两个 Fediverse,还有一些其他的 Fediverse 平台并不为大众所知,覆盖了通讯、社交、图片、音乐、视频等众多领域,大家可以通过以下网站探索:

对了,我还要着重提一个,Rust 语言开发的论坛 Fediverse,Lemmy,可以用来替代 Reddit、HackerNews,轻量好用。

ActivityPub 协议

刚刚提到了 Fediverse 需要标准化协议来进行通讯,而 Mastodon 基于的协议便是 ActivityPub 协议,这个协议历史比 Mastodon 早,并且已经被 W3C 在 2018 年推荐作为标准

这个协议规范了去中心化社交网络交互细节的各方面,包括用户的交互(收发信息、关注、喜欢),还有活动(就是内容、推文、嘟文)的发布、更新、删除、喜欢、屏蔽等等。

如果各个平台都遵循相同的协议,那使用不同平台的用户就可以在同一 Fediverse 中交互,举个例子,我可以在 Mastodon 和 Pixelfed 这两个不同的平台之间进行一些简单的交互。

我测试用 Pixelfed 平台的账号(@zu1k@pixey.org) 关注我的 Mastodon 账号(@zu1k@fosstodon.org),可以成功搜索到用户,显示头像、简介、关注量等信息,可以成功关注。在 Mastodon 平台也可以即时收到被关注的通知,同时可以通过 Mastodon 查看 Pixelfed 的账号信息。

/posts/tutorials/p2p/fediverse/mastodon_pixelfed_hu52eac44f8e02f5abb2301fade121986a_123532_1328x646_resize_q75_h2_box_3.webp

但是我在 Pixelfed 发布的内容,从 Mastodon 却无法看到,这说明两个应用虽然都使用 ActivityPub 协议,但是其在内容封装方面有自己专属的子协议,这些子协议之间并不互相兼容,只有那些公共的兼容的协议才能跨应用使用,例如账户信息、关注这类。

同时我还尝试使用 Mastodon 查看 Lemmy 的用户,可以看到用户信息,发布的部分内容可以看到,有一些出入,说明这两者之间也是有不兼容的地方。

/posts/tutorials/p2p/fediverse/mastodon_lemmy_hu3d786cdeffe43d68657c9af44c7cff39_1770398_3321x2093_resize_q75_h2_box_3.webp

通过 Lemmy 的 issue 和 PR 列表我看到 Lemmy 正在做与 Mastodon 的兼容工作,这很伟大,支持!

同时,一位 GitHub 的员工开发了一个有意思的东西,ActivityPub to Mastodon bridge。pub 的目的不是托管 ActivityPub 社区,而是旨在使拥有自己域并因此控制其身份的人能够参与 Fediverse,这意味着你无需搭建 Mastodon 就可以用自己的域名加入到 Mastodon 联邦中了,这就很方便了,轻量好用啊。

Mastodon 性能问题

Mastodon 目前官方实现使用 Ruby 语言,Ruby 依靠 Rails 框架用来开发 Web 应用简直是不要太快捷,非常适合频繁变化的需求。但是 Ruby 本身的性能并不乐观,去年 Shopify 使用 Rust 开发 YJIT 顺利合入 Ruby 上游,并随 Ruby 3.2 版本正式发布,这将 Ruby 的性能提升了约 40%,但是 Ruby 的性能仍无法与目前流行的 JavaScript 比肩(主要是 V8 引擎的功劳),更不要提 Golang 和 Rust了。而我经过搜索发现,竟无 Golang 和 Rust 的服务端实现,即使有也已经停止了开发,这使 Mastodon 如何支撑即将到来的上亿用户量?如何与 Twitter 竞争?当然,目前已有的实例都没有这么多的用户量,等未来有这个性能需求的时候,自然会有商业公司出钱出力来解决这个问题。

不过我倒是不希望这一天的到来,如果某一个 Mastodon 实例的用户量上千万,这其实就成了另外一个 “Twitter”,大量用户聚集在商业公司运营的单一或几个主流实例上,那联邦制、分布式等概念实际上也就名存实亡了。不要忘记我们逃离 Twitter 来到 Mastodon 的初心啊!

不过虽然这么说,我还是希望 Mastodon 性能能够更好一点,同时我也看到了一些优化 Mastodon 性能的努力。随着 Mastodon 实例数量的增多,单个 Mastodon 实例往往需要连接众多其他实例来进行交互,这带来了巨大的网络性能压力,使得想要自行搭建 Mastodon 实例的小伙伴不得不花更多钱在服务器费用上。这极大概率会导致部分实例脱离 Fediverse,形成自己封闭的,仅有几个节点的小联邦,这应该并不是我们想要看到的。我已经看到了有人开发了 ActivityPub relay Relay 列表,中继服务器与大量实例连接,聚合内容,然后提供给中小型服务器,从而使中小型服务器无需连接大量实例就可以实现相同规模的信息获取。

国外的社交和通讯正在变天,有上天的,有摆脱大公司的。而国内因为各种法律条款的限制,一般人根本没有权力做社交和通讯,会不会就错过这一波改变呢?让我们拭目以待吧。

IPFS 日用优化指南

作者 zu1k
2022年6月6日 23:14

这两天,V2EX 的站长 Livid 发布了 一款基于 IPFS 和 ENS 的内容发布和订阅应用 [Planet],其想法在之前的一期 [播客访谈] 中就提到过,当初就觉得很有意思。也不出我所料,Planet 一经发布就引来了众多关注,Planet 用图形化的方式使更多普通人可以尝试 IPFS 这类分布式内容发布,据说后面还会增加评论功能,这在 IPFS 网络中也算是一个不小的挑战,不知道 Planet 能将易用性做到什么水平,我会继续关注。

我也在很早之前就了解并开始使用 IPFS 技术,在折腾的过程中也积累了一些经验,下面我将向你们分享一些使用技巧,使你的 IPFS 更加易用。

完全新手朋友请先阅读我在 20年写的 《IPFS 新手指北》 这篇文章

搭建网关

相比较使用公共 IPFS 网关,我更推荐自己在家中搭建,不仅能提供更优的体验,还可以避免在每台电脑安装 IPFS 的麻烦。

按照普通教程在服务器上安装好 IPFS 后,你需要修改配置文件,对外开放 Api 和 Gateway。

因为是在家庭网络中,我就不额外介绍访问控制配置,如果你是在公网服务器搭建,需要注意配置访问控制以免被滥用

修改 API 和 Gateway 绑定的 IP 为 0.0.0.0 以开放给局域网,然后修改 API 的 http header 配置跨域:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
"API": {
  "HTTPHeaders": {
    "Access-Control-Allow-Headers": [
      "X-Requested-With",
      "Range",
      "User-Agent"
    ],
    "Access-Control-Allow-Methods": [
      "GET",
      "POST",
      "OPTIONS"
    ],
    "Access-Control-Allow-Origin": [
      "*"
    ]
  }
}

配置子域名网关,可以达到 dweb.link 的效果。例如要使用 *.ipfs.zu1k.com 作为子域名网关,就要先将泛域名解析到 IPFS 网关的 IP,然后在 Gateway 配置中增加以下内容:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
"Gateway": {
  "PublicGateways": {
    "ipfs.zu1k.com": {
      "NoDNSLink": false,
      "Paths": [
        "/ipfs",
        "/ipns",
        "/api"
      ],
      "UseSubdomains": true
    }
  },
}

为获得更好的 IPFS 使用体验,推荐安装 [IPFS 浏览器插件],或者使用 Brave 浏览器,可以让 IPFS 的使用体验更加原生。

Pin 优化

在发布内容后,马上通过公开的 IPFS 网关访问,通常会很慢很慢,甚至到超时都无法访问,这是由 IPFS 的寻址过程导致的。随着访问内容的用户越来越多,他们的 IPFS 节点上会缓存你内容的数据,这个时候新节点再访问同一份内容,通常就会很快。这就是 IPFS 的特性,就跟 BT 下载的原理类似,数据在网络中存在的副本越多,就越能利用 P2P 网络的性能。

但是一个 IPFS 节点也不会无限期的缓存你的数据,默认配置下 GC 频率是 1 个小时一次,也就是说你的数据如果用户不访问,在一个小时后就会从他们的节点中被清理掉。为了能够让我们的数据长久的留在 IPFS 网络中,就需要用户 Pin 住你的数据,以防被 GC 掉。我的做法是利用闲置的服务器搭建 IPFS 节点用来 Pin 自己的数据,然后朋友之间互相 Pin 住,算是合作共赢。

所以大家不妨 Pin 一下我的博客:ipfs pin add /ipns/zu1k.com

如果你使用 IPNS 或者域名的方式对外公开经常修改的内容,就需要设置定时任务来不断 Pin 住新的数据,因为 IPFS 在 Pin 一个 IPNS 的时候,只会 Pin 当前状态对应的 CID ,后面不会自己去更新。

Remote Pinning Service

如果你不想一直运行本机的 IPFS 节点,但又想让别人可以访问到你发布的内容,可以考虑使用 Remote Pinning service,这是由一些中心化的服务商提供的内容 Pinning 服务,其效果与你本机 pin 相当。甚至因为他们的网络质量更好、连接的节点更多,将内容 Pin 在他们的节点上,可以更快的被分发和访问。

我主要推荐两家,[Pinata][web3.storage],具体教程可以看 官方文档

1
2
3
# ipfs pin remote service ls
Pinata       https://api.pinata.cloud/psa
web3_storage https://api.web3.storage

Pinata 是无门槛的,免费提供 1G 的 Pin 容量。

web3.storage 免费提供 1T,但是 Pin Api 需要发邮件申请,一天以内就会有回复。[教程]

开放端口

因为 IPFS 需要 P2P 通讯,所以如果你没有公网的 IPFS 节点 Pin 你的内容,就需要保证自己本机的 IPFS 节点可被访问。检查你的路由器,开启 UPnP 功能,必要时建立端口映射,开放你的 4001 端口(如果没有修改过的话)。

/posts/tutorials/p2p/ipfs-easy-use/nat-mapping_huc68249edc18ae4d99b6de292707b695f_10157_789x82_resize_q75_h2_box_3.webp

资源占用优化

如果你没有做任何的配置优化,只是按照常规流程下载安装运行,你会发现 IPFS 在后台会占用大量的 CPU 资源和内存,你的风扇开始狂转;维持了大量的网络连接,导致你的网络卡顿。这是因为 IPFS 的默认配置并没有针对个人小主机进行优化,如果你在一台 2 核的 Linux 服务器上运行,IPFS 甚至能吃满你所有的 CPU,网络的拥挤程度有可能使你连 ssh 登录都成了一个问题。

/posts/tutorials/p2p/ipfs-easy-use/ipfs-origin-high_hu3eea88f8be2338a28eef177f823f2105_36095_828x210_resize_q75_h2_box_3.webp

这个时候我们就需要调整配置文件中的参数来想办法降低资源占用,以使 IPFS 不影响我们的日常工作。其实 IPFS 已经提供了好几个配置文件,通过 ipfs config profile --help 可查看具体介绍。

profile 不知道怎么翻译合适,翻译成文件不太准确,ipfs 中应用这些 profile 只是修改某些特定选项,并不是配置文件的完全改变

我推荐在低配置的服务器和个人电脑上应用 lowpower 配置,ipfs config profile apply lowpower,这会限制 IPFS 维持的连接数量,降低网络占用,还会降低 GC 频率,这可以明显的降低 cpu 占用,我的测试可以使 cpu 占用从 80% 以上降低到 20% 以下。当然,资源占用的降低也会导致通讯效率的降低,会使内容寻址时间增长,影响使用的体验。如果你的使用方式是类似于 RSS 订阅和离线查看的模式,增长的寻址时间可以忽略不记。

如果你是在拥有公网 IP 的服务器上运行 IPFS,还推荐应用 server 配置,ipfs config profile apply server,这会关闭本地网络的节点发现,因为这是无意义的,这样也可以降低网络占用。

/posts/tutorials/p2p/ipfs-easy-use/ipfs-now-low_hucf37f9c7b9809966f20b342d5b3216f0_47398_813x258_resize_q75_h2_box_3.webp

后言

20 年 11 月底,我发布了 《IPFS 新手指北》 这篇文章,期待 IPFS 能够迅猛发展,成为下一代 Web 基础设施。不知不觉已经过去一年半了,就目前情况来看 IPFS 虽然仍在不断发展,但还是在半死不活的状态,这一点让我非常失望。

但仔细一想,期待某门技术成为下一个主流本身就是不合理的。任何技术都应该是在广泛的需求之下才有可能成长为广泛应用的主流,而不是说你有某些好的特性就一定能够被广泛接受。从需求上讲,我们确实需要基于 P2P 的内容发布,也需要基于内容的寻址方式,这些都具有非常好的优点,但并不能满足我们对互联网的全部需求。我们在期望内容不可变、内容不被删除的同时,也会希望能够拥有删除或者修改某个内容的权利;我们喜欢 P2P 的去中心化内容分发方式,但不能否认任何人都希望延迟更低、速度更快;我们还会希望对内容具有更多控制权,包括细致的访问控制、更灵活的表达形式&mldr;&mldr;

基于以上想法,我不认为 IPFS 就是下一代 Web,也就是都在说的 Web3。但我不否认 IPFS 有巨大的潜力,在下一代 Web 中充当非常重要的角色,只是这个角色并不是全部。而基于 P2P 的内容分发方式早就不是什么新技术,BitTorrent 和 基于 BT 技术的 BtSync、BTFS 也都非常具有竞争力,IPFS 想要与其竞争需要更加努力,使其更加的易用和平民化。

我自己也已经使用 IPFS 接近两年,这两年的时间我自己的感觉是 IPFS 本身没有太大的突破性发展,而围绕其进行的各种营销和唬人活动层出不穷,文件挖矿、NFT 等等,不过这些也的确让更多人关注起 IPFS,并为 IPFS 网络贡献了大量节点和存储空间,但我总觉得怪怪的,这不是发展的长远之道啊。

不过看近几年互联网越发封闭,内容审查越发严格,想必 IPFS 这类分布式内容发布方式会被更多非技术人关注,期待在这个需求激增的关头,有更多优秀的应用浮现,将 IPFS 推展开来,让更多普通人能够更加方便的使用这些新技术,享受新技术带来的权利,那些我们本该拥有但被剥夺的权利。

你应该弃坑吗?

作者 zu1k
2022年1月8日 23:10

当你在做某一件事,貌似已经陷入其中好多时日,某一天猛然反应过来,好像这件事并没有想像那么重要,你应该弃坑吗?

我将以自身经历来向你讲述这一点,我已经经历过这样的抉择好多次了。最初还是非常难以割舍,毕竟已经投入了如此多的精力和时间,就此别过总显得虎头蛇尾。但后来我也算是想通了,人的精力总归是有限,应该尽可能的投入到真正想做的事情中,越能够及早的意识到这一点,在这样的抉择面前越能够坦然做出决定。

我也是近几年才意识到这一点,如果没有记错的话,第一次遇到这样的抉择是在三年前。

起初,在某一天我的脑海中突然有了一个想法。人一旦有了想法便总想要去实现一下,于是我便开始着手做这件事,顺便开源出去看看能不能给别人也提供一点便利,说不定还能拉一波人气。事情最初的发展确实符合我的预期,我便投入更多时间,同时对外做了一些宣传工作。

随着关注的人越来越多,我的心态发生了一些变化,我也不知道到这种心态应该如何表达,也许是对项目、对使用者的责任心,夹杂着一丁点虚荣心。项目的使用者越来越多,他们给出了不少反馈,提了一些问题、要求和请求。作为项目维护者,我常常被这些问题和要求折磨,因为责任感的原因,我的邮件通知就像锁魂咒一样,哪怕是在睡觉,一听到那声通知音,我便能立即醒过来,点亮手机查看反馈。如果我觉得能够在短时间内解决这个问题,我甚至能够在大半夜爬起来打开电脑处理这个问题。白天的绝大多数时间我都在做这个项目的开发,甚至拿不出时间出去玩,有时候因为写到兴头,午饭时间都能被我拖到下午一两点。虽然累,但看到问题被一个个解决,项目不断完善,我觉得自己甚至能够想象到使用者满意的眼神,那一段时间确实乐此不疲。

后来某一天,我坐在床上发呆的时候,回想自己这一段时间的经历,发现自己貌似除了这个项目,没有完成其余的任何一件其他的事情。这很可怕。我突然意识到,如果这个东西在未来的某一天突然没有了价值,甚至说它的价值一直以来都是被我高估了,那我在这么长的一个时间内,做了个什么?我是不是,或者说也许一直是在做一件无意义的事情,这些时间都被我浪费了,可怕的是我一直没有意识到这一点,甚至陷入其中乐此不疲。

带着这个想法,我开始重新审视我做的这个项目。首先这个项目的技术并不是非常复杂,任何一个有良好编程基础的人愿意花点时间都可以做出来;然后这个项目的提供的功能貌似是在法律的边缘摩擦,继续开发可能会带来一定的风险;最后这个项目的用户貌似是那么一群乐于白嫖的人。从以上三点出发,我觉得自己这一段时间确实是浪费在一个永远不会有回报的精力黑洞里面了。此时此刻我的心情是非常的复杂,懊悔自己最初做出的选择,同时又对关停这么长时间完成的东西有那么一些不舍。

最后我还是决定终止该项目了。及时止损,任何一个成年人都应该学会这一点,我也刚刚开始领悟这个道理。我觉得这是我弃坑历程的起始点,有了这一次弃坑经历,我在后面的抉择面前,能够更加坦然的做出决定。

现在回到我最初提出的问题:“当你在做某一件事,貌似已经陷入其中好多时日,某一天猛然反应过来,好像这件事并没有想像那么重要,你应该弃坑吗?”。虽然我上面的故事貌似是在鼓励弃坑,但我的本意并非如此。现在我给出我的观点,我认为最重要的是“初心”。

在面临“我应该弃坑吗?”这样的抉择面前,第一件事并不是要赶快反省甚至批判、贬低自己已经完成工作的价值,而是要好好审视一下自己的内心,“我最初到底是想要什么?”,然后根据这个标准,认真评价当前工作是否还在按照实现初心的路径前进。如果因为一些其他的外界事情干扰,工作偏离了航线,则需要判断是否有挽回的机会,毕竟就此放弃是人都会有不甘。如果最终判断这件事确实已经完全偏离了初心,其价值无法满足自己的期望,则应该坚定的终止。除此之外,还应该找个没人的地方,好好的捋一下,看看到底是一开始就错了,还是中途出现的偏离,为未来的决定收集好经验。

到这里,这篇博文算是可以结束了。至于我为什么要写这样一大段文字,主要是我最近看到跟我差不多年纪的年轻人,应该是比我小一点吧,也在沉迷于自己的项目中,没日没夜的维护、解决问题、开发新功能,这些工作耗尽了他几近全部的时间,以至于一直没有时间供他回过头来审视一下。我仿佛从他的身上看到了自己当初的影子,希望他不会像我一样,在某些地方浪费太多的精力,浪费自己大好的青春年华。(这么说好像我年龄好大了一样,我还很年轻好嘛)

干!有人在卷我

作者 zu1k
2021年6月17日 23:08

“干!他妈的我被卷了。我不能接受!” 一个研究生学长这样告诉我。

这是我提前选修的研究生课程,按照提交的文档评成绩,本是上个学期的课程却拖到这个学期末才出成绩。我很诧异自己拿到的成绩没有过平均线,但历年来该课程老师的极低评价我也有所耳闻,因此自己也算能够勉强接受。

然而那个研究生学长却没听说过该老师,算是踩了个大坑。他的学习态度我是见过的,很努力很刻苦,最后给他不到70分的成绩和倒数的名次给谁也接受不了,我建议其申请成绩复议。后来他跟我说,那个老师给他发了第一名97分的文档,人家提交了21页,足足有1万5千字。而他只提交了3000字。

所以我知道了,我应该也被狠狠的卷了,因为我也只提交了3000字。但我拿到了80分(草,没过平均线),虽然没有什么用。我拿到了那份21页的文档,原来也是提前选修的同学,是个女生,见过几面,挺温柔的,所以我不想批判她。(我劝各位读者不要他妈多想)

亲身经历过内卷(是被卷的一方),这段时期又刮起一阵反内卷风,B站各种《内卷的名义》等反内卷题材小短片,“躺平”这个词被大众广泛接受(我不喜欢内卷,但也不支持躺平),我就想,是时候写点东西了。可能不是很深刻,但也算是我在这个时期的一扑棱,毕竟还是有同学和陌生人来看我写的文字的,感谢大家。

我参与过内卷吗?

在开始之前,我想先回答这个问题:“我参与过内卷吗?”。毕竟大家都不喜欢内卷(我想至少我的读者应该是这样的),我不想一开始就成为大家口中的“内卷人”。

对于这个问题,我想,应该没有吧。

但是我想让大家来评判,请看以下两个例子,算是学生阶段能够遇到的两个最典型最容易产生内卷的场合:

  1. 要交课程报告。虽然没有规定字数,但我坚决不会让我的报告低于3000字,一般写3200-3500字。我认为这是学生提交报告的本分,至少不要让老师觉得你太敷衍吧。
  2. 要期末考试了,得提前复习。虽然平时上课我都会仔细听(认识我的别打我啊,我可是每堂课都坐前几排的,虽然在老师眼皮底下玩手机真的很爽,虽然我不做任何笔记,但是我真的有仔细听课),但考试前还是要好好复习的,提前一个周吧,考试前两天会疯狂背书和做题。

一些身边人的情况

  1. 课程报告,没规定字数和格式是吧,那先来他2w字。什么封面、目录、图片、表格能有的全给他整上,内容要分章节,最好不少于5章,最后还要有总结和引用文献。关键内容要加粗和标红,不能让审阅老师看不到啊。什么,你说内容?内容谁看啊,管他合不合适,只要与主题有点关系的先写上再说,反正多出来的又不会扣分。(真事,大一下,找那个老师理论,她坦然承认自己评阅标准有问题,但是不能改分。她承诺我后面如果哪门课感觉要挂,可以找她,她帮我去找相关老师求情。???????去她妈的!我会挂科吗?她这算放了一个屁吧朋友们)
  2. 期末考试,那不得提前两个月甚至半个学期就开始复习和刷题了。课后题啥的做不到完全背过那答案总得背过吧。光看课本和PPT那怎么行,吉米多维奇不得刷他个3遍以上,然后历年考试题也得整一下吧。到考试了,全他妈是吉米多维奇上的原题,这不得写他个两种甚至三种解法。(也是真事,这些人也真是,我可不想为了八十分与九十分的差距付出这个时间)

所以,你说我参与过内卷吗?这样看来我是不是很正常吧。

是什么造成了内卷?

内卷的产生不是偶然,内卷的环境+不合理的评判标准+竞争的人导致了内卷的必然发生,至少我是这样认为的。

所谓内卷的环境,那必然要是金字塔形状,底层占绝大多数,只有少数人可以上升,这样就会形成竞争的原因。甚至要严格限制上升的人数,这样才能使竞争更加激烈,才会孵化出各种竞争手段。

有了引起竞争的条件,形成的是竞争的行为,如果评判标准合理,最终的结果是通过健康的竞争选拔出真正有实力的人,这应该是一个正向的积极的过程。可惜,绝大多数情况这个评判标准并不合理,更有为了利益为了压榨故意采用恶心人的标准的,比如企业里面单纯通过工作时长来评判、比如老师单纯通过字数来评判等等。

这就是恶心人的地方,拥有决定权的人通过设立不合理的评判标准,故意引起底层内卷,从而满足自己的利益。而作为内卷的主要参与者———竞争的人,却是这三个条件中最可怜的那一部分,不仅需要付出大量努力、时间等参与到内卷中,还有很大几率无法在内卷中脱颖而出,从而白白浪费了自己的时间精力等;他们还需要承受内卷同仁的满满的恶意,竞争者之间往往就是这样,在内卷局中的人难以看清形势,难以把矛头对准真正掌握规则、真正引起内卷的上层管理者和标准制定者,他们只会在底层互相伤害。真是可悲啊。

如何摆脱内卷?

这个问题我无法给出答案,因为我也不知道。毕竟就目前的形势而言,只要内卷的条件还存在,就总会有人参与其中。我个人认为要打破这个局,还是需要从上而下的反内卷,底层难以闹出风浪。

但就目前情况来看,貌似上面并不想真正反内卷。可能迫于底层舆论压力,他们会增加反内卷的宣传。可这有什么用,不打破内卷的条件,只要内卷的环境和不合理的评判标准还存在,内卷就不会减轻。他们可真是坏啊,他们想要从底层的内卷中获利。

也许,真正的社会主义社会是划破黑暗的那一束光,她会是吗?

我是否曾从内卷中获利?

这个问题我必须回答“是”,甚至还有点小开心。因为我不是以内卷者的身份参与其中,不需要付出任何努力,通过他们的内卷和恶性竞争,我作为一个旁观者可以直接获利。

不说当年的各种打车软件之间恶性竞争、疯狂烧钱,打一次车只需要一分钱,那个时候我还上初中,哪懂什么内卷。

就看大学这两年,校外那条小吃街。起初只有一家羊肉汤店,算是这条街羊肉汤方面的绝对垄断,价高味不美,肉还不多。去年其隔壁新开了另一家羊肉汤店,一开始还只是两家的老板娘到店门口招呼人进各自的店,慢慢的两家开始让利,一家店搞抽奖送饮料送凉菜,另一家店直接进店即送葱油饼。

两家店卷起来了,我们这些看热闹的吃客可开心的很,免费的饼吃着,免费的饮料喝着,连碗里的羊肉也变多了。

你说内卷好不好?老板娘肯定烦得很,但我们这些从中获利的人怎么会放过她们。

卷我可以,请换种方式

这个环境就是这样一个环境,大家都是底层,都想要更高的名次、更好的待遇、更多的钱,那就总有人要付出更多的努力和汗水。对于这些努力的人,我选择原谅他们上进的心,但我绝对不原谅他们卷我采用的手段和方式。我看不起你刷更多的题而没有把时间投入到自己真正感兴趣的领域,我看不起你拼凑更多的文字却没有包含自己丁点的思考,用这种方式来卷我简直就是在侮辱我,在侮辱每一个共同学习一起进步互相竞争的同伴。

如果你真想卷我,请换种方式。我希望你的内容包含更深刻的理解,或者在追寻更尖端的研究热点;我希望你的工作有更高的技术含量,或者给更多的人带来便利;我希望你的答案有更深入的思考,或者有你自己的东西在里面。请让被卷的我感受到来自竞争者的尊重,让我输的心服口服,让我能够去尊重你。

最后,可乐

这个也是前段时间看到的,你说可口可乐和百事可乐也是在竞争,为啥可乐的价钱不下跌呢?

之前也没思考过这个问题,一开始也就想已经把价格压到一个比较低的价位了,再降价可能不太值?毕竟一些国产汽水的价格也不低。

现在想想肯定没有这么简单,已经是完善的大规模工业化生产流程了,生产瓶汽水平均成本很低,这个价应该还有不低的利润空间,那他们为何不通过降价来抢夺市场,为啥不像国内之前打车软件那样甚至不惜倒贴钱来竞争呢?

我怀疑是他们脑子正常,搞明白了内卷的损人不利己,清楚恶性竞争的危害&mldr;&mldr;

最后祝大家都能够成功摆脱内卷,可以像交大cxs一样,可以不参与内卷但仍有机会凭借自己的实力得到自己满意的结果。

❌
❌