V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  kuanat  ›  全部回复第 1 页 / 共 12 页
回复总数  226
1  2  3  4  5  6  7  8  9  10 ... 12  
妙哉!
2 天前
回复了 IIInsomnia 创建的主题 Go 编程语言 从 0 到 1 手撸一个协程池
@yuan1028 #22

我一样很少用到,过去几年里都是如此。你可以看 #24 的回复,我跟你的观点是一致的,动态扩容是实例层面的事情,go 应用单体不应该考虑。这里讨论的是真正存在压力的生产环境。

性能指标这方面,还是要具体情况具体分析。我是极其反对单纯以 cpu 或内存占用作为性能指标的,除非它是真正的瓶颈。笼统地说我一般会跑一下火焰图和计时任务,观察一下可能的热点或者瓶颈在哪里,只有确认了瓶颈存在才会考虑优化。网络编程这个领域,多数时候加钱( cpu 和内存)比加人工更有效。

具体到并发相关的参数,考虑一般有限资源环境中的调度问题,调度行为一定会产生损耗,根据特定的业务场景,追求低延迟就看前 5%的耗时,追求高吞吐就看 95% 的完成时间。看统计分布比看单一指标更有意义。
2 天前
回复了 IIInsomnia 创建的主题 Go 编程语言 从 0 到 1 手撸一个协程池
@lesismal #18

我遇到需要极大协程池的只有一个负载平衡路由的 dispatcher ,然而“通用”协程池动态调节对于这个场景也是没有意义的,一次性预热分配好常驻就可以了。

我这里很多资深(职级)程序员都有一种对于 universal/variable/dynamic 方案的迷思,反倒需要我经常强调动态可变实现带来的不可预测性才是大忌。即便是一个理想的动态实现,使用的时候还是会根据硬件、网络实测一个并发上限并一直沿用下去,那这和写一个固定的实现没有什么区别。且不说真正业务产生的 cpu 和内存消耗数量级层面就高于调度器的损耗,即便节省出来资源,也不可能在这种有关键性能的位置搞 cpu 或者内存共享。

也许我这样说有点暴论,但我认为,一个承载能力为 N 的系统和一个承载能力在 0~N 之间变动的系统在生产环境是没有区别的,而前者的复杂度耕地,可维护性更高。
3 天前
回复了 wjpauli 创建的主题 Amazon Web Services 求助: AWS 的 SES 不给出 Sandbox?
这个审核很迷,年初帮朋友做个项目申请没过就改用第三方的了。然后过了大概半年突然发邮件说违规把 ses 停了,又过了几天说封错了,结果 ses 权限就莫名其妙开了。
3 天前
回复了 IIInsomnia 创建的主题 Go 编程语言 从 0 到 1 手撸一个协程池
大概三年半前,由于众所周知的原因,各种会议特别多。团队有过一次讨论,就是要不要引入外部、通用协程池实现。现在我把当初讨论的重点摘录出来,权当抛砖引玉,看看这些观点能否经得起时间的考验。

1.
工程管理层面,我的观点是所有引入第三方依赖的行为都要慎重,当然我并不反对引入依赖,完全自己造轮子的工程量和实现质量都是更大的问题。那这个引入的平衡点在哪里?有几个考量因素:第三方库的规模以及项目中实际用到的功能占比,第三方项目的生产环境成熟度,团队内部 review/debug 甚至换人重写的成本代价。

无论从哪方面看,协程库这种功能单一、实现简单的组件都应该内部实现。额外的初期开发成本,相比维护 debug 甚至人员调整、供应链风险等等方面的收益简直不值一提。

2.
实际上就我个人观点,我认为要不要引入三方协程池实现这件事本身根本不需要上会讨论,之所以拿出来讨论是为团队建设服务的。团队协作的困难在于成员之间建立共识,考虑到团队成员背景、能力和经验不同,最常见的情况就是以为是共识但实际上不是,所以就需要反复沟通交流。还有更常见的情况,技术路线的决策结果很容易自上而下传达,而支撑决策的论据在传递过程中就缺失了,项目成员工作在不知所以然的状态。我更倾向于让成员建立更多的共识,这样可以减少后续的沟通成本。

支持引入一方的核心论据是三方库的性能高,并且辅以 cpu 内存占用等等数据。其实以最朴素的科研思维来看,测试数据集特征、测试方法以及因果相关性匹配程度,都比单纯的跑分结果重要。

补充一点关于网络并发的历史发展,很多年前有过 c1k/c10k 之类的说法,但是之后很少有说 c100k/c1m 的,因为这个过程主要依赖的是横向扩展而非单体。单体应用并发 1m 协程是个极其小众的场景。再就是需要用到协程/线程池这个技术,有一个隐含的前提就是协程/线程昂贵,是事实上的瓶颈。放到二十年前这个前提是成立的,然而随着软硬件的发展,cpu 核心数、内存大小甚至带宽都可能是瓶颈,唯独 golang 协程很难成为瓶颈。

3.
回归技术层面,“通用”协程库的问题有哪些?调度逻辑是个与业务特性强相关的功能,通用实现的性能指标和业务需求很可能不匹配。

再具体到实现细节,“通用”库为了实现其通用性,对于“任务”这个概念的定义实际上被抽象成了“可以执行任务的函数方法”,作为调用方,不得不去匹配一个特定形式的签名,与之相关的超时、重试逻辑和异常处理都要做出调整。继续思考下去会发现,如果要完成与协程的通信,加入 chan 管理又是大工程。这一切的根源都是“通用”协程库对于“任务”这一概念特殊抽象的结果,选择了这样的抽象就注定了这样的处理方式。既然通用库侵入性这么大,实现难度又低,为什么不自己写呢。放弃通用性,可维护性


PS
如果让现在的我来评论,观点会更加极端。“协程池”之类技术的核心是任务调度,而池化是有时代局限性的妥协。Go 语言设计出低心智负担的并发模型,就是为了让开发者不用费尽心力去管理什么协程池。当你觉得有什么需求是非协程池不可的时候,不妨重新思考一下“任务”的本质。在 Go 的思维模型里,任务的本质是数据,任务调度就是数据的流动,完成调度这个行为有太多更简洁的做法,过去把任务理解成执行动作的思路是低效的。
稍微偏个题。

编程这件事的本质是什么?我个人有个粗糙的定义,就是用语言对某种事物、行为或过程做出无歧异的抽象描述。用自然语言给人指路、教人下棋或者介绍产品都是编程,只是这种程序的执行者不是自动化的机器。

从计算理论上说,图灵完备的编程语言之间不存在表达能力的差别。语言特性和编程范式百花齐放,表面上是工具特化的结果,深层次是反映编程者对于现实的认知逻辑和思维方式。

FP 是数学上优美的,非常适合解决真空中球形鸡的问题,现实大多数问题仍旧需要传统经验公式和手段来应对。OOP 是有效解构对世界认知的哲学,但实现 OOP 的方式却不一定。组合( composition )替代继承( inheritance )就是认知层面的进步。

从过去二十年编程语言的发展来看,语言特性 FP/OOP 的进步演化一直在发生,但几乎不存在相互替代的基础。作为工具的编程语言,以当下的视角来看,能够成为主流的一定是具有工程化能力基础的,只有解决问题的范畴和效率提升才会带来工具的替代。
127 天前
回复了 june4 创建的主题 编辑器 未来最牛编辑器 zed 的 Linux 版终于出来了
@lysShub #71

没有说怎么测的,我也没细看,就假定它用的一致的测试方法好了。延迟测试包含了语法分析,但是因为它只是在新的一行里反复按了 10 次 z ,所以这个语法分析的时间可以忽略不计了。
128 天前
回复了 june4 创建的主题 编辑器 未来最牛编辑器 zed 的 Linux 版终于出来了
我这里简单就 Zed 官网宣传的一些特性简单做个总结,同时与 VS Code 对应的部分做个对比。


1. 输入延迟

Zed 在性能方面有个对比,强调的是 Insertion latency ,58ms 相对 VS Code 97ms 算是非常优秀了。这个测试反映的是输入状态下按下按键,到字符出现在屏幕上的时间,如果你玩游戏的话,很容易理解这个就是所谓的输入延迟。

你可能觉得 40ms 影响不大,但这个特性属于有对比才有伤害、或者说像高刷屏用了就回不去那种。不仅仅是在文本编辑器领域,像终端( vte )领域一样对于输入延迟有追求,所以你会看到像 kitty/alacritty 这样通过 GPU 加速绘制的终端模拟器。再比如很多人会觉得 oh-my-zsh 之类的框架会拖慢 shell 的启动,考虑换成 fish 之类作为替代。

2. 渲染模式

也许你会认为 Zed 渲染快延迟小是得益于原生应用相对于 electron 的优势,是有这方面的原因,但是不够全面。同样是输入延迟部分,Sublime Text 4 大概是 75ms ,可以粗略的认为,Sublime 相对 VS Code 的优势来源于原生,但 Zed 相对于 Sublime 的优势有一部分是来自于渲染模式。

包括各种终端模拟器在内的应用,所谓的 GPU 加速更多的是使用 immediate 模式,相对于 retained 模式。前者就是把应用当作 3D 游戏,自己负责渲染每一帧。后者就是一般意义上的原生应用,使用系统控件,只有在状态发生变化时才通知系统,由系统负责渲染。

Zed 使用的是 Vulkan 后端,其 UI 界面就是基于 immediate 模式自渲染的。(技术上说,应用 GPU 加速通常更快,但不总是更快,这一点放到后面说)

3. 语法分析

如果增加一个 Deletion latency 的测试,我相信 Zed 会胜出更多的。原因是无论插入还是删除,后台都要做语法分析,从而提供高亮、补全等等功能。删除相比插入更能反应语法分析器的性能,特别是跨多行或者代码存在语法错误的时候。

Zed 的开发团队的前身就是做 Atom 的团队,而 Atom 当年之所以有底气做编辑器,是因为他们写了 Tree-sitter 这个通用的 parser 生成器。现在 Tree-sitter 是事实上最通用、也是效率最高的语法解析器的“生成器”。不是 parser 而是 parser 的生成器,这一点尤为重要。

在 Tree-sitter 之前,通用的语法解析主要是 TextMate 的,后续包括 VS Code 在内也都沿用了下来。连 VS Code 的开发都说,用 TextMate 这套的原因就是不用为每一门语言都写规则,然后他们也发现很多语言的规则都多年没人维护了。当初 TextMate 设计这个功能的时候想的是,尽可能在不用写 parser 的情况下完成 parser 的主要功能,所以实现方式是正则匹配。放到二十年后的今天来看,这个做法就跟不上时代了。

一方面现在的性能和软件实践来说,写 parser 和实时处理都相对简化了,既然都能完整实现和运行 parser 了,那就没必要用弱化版的了。另一方面,基于正则的弱 parser 实现只能处理一行,也不能支持像是“增量”处理,或者在代码被修改乱了,存在语法错误的时候还能正确输出尽可能有用的信息。

我个人认为,Tree-sitter 在这方面对于写代码的改善是非常明显的,不仅速度快结果还准确,特别是错误状态下依然有用这点十分好用。想要尝试的话可以用 neovim 或者其他基于 Tree-sitter 的编辑器感受一下。

4. 协同

现在没有什么编辑器能做到像 VS Code 的 Remote 功能一样彻底颠覆开发的工作流。即便 JetBrains 这样也算财大气粗的专业开发,照着现有的方案模仿都做得一塌糊涂。所以也不要对 Zed 有什么不切实际的期待。

Zed 目前能做到的是还是本机做 host ,然后可以编辑 remote 的文件而已,对用户隐藏了拉取和推送文件的细节。

所以 Zed 就专注做了协同功能,在本地编辑器上实现了多人实时编辑同一文档的在线编辑器体验。这个功能基于 CRDT 思路,有兴趣可以去看看。



关于“GPU 渲染为什么不会总是更快”这个说法的解释:

一般来说,GPU 渲染会更快一点,但就文本编辑器(或者终端 vte )这个场景来说,GPU 渲染不一定比 CPU 更快。这是因为 GPU 更快是建立在全渲染的前提之上的,而文本编辑这个场景很多时间并不需要全渲染。

比如输入的时候,发生变化的一般只有当前行。浏览代码的时候,代码内容不变只是显示位置变了。这样的场景里,使用 damage tracking 类算法,就是类似 vnc/xdp 那种检测改变部分的算法,可以极大降低渲染的工作量。以游戏渲染的思路来看,无非就是 framebuffer 的手动控制更新。

所以我个人并不喜欢使用 GPU 渲染的文本编辑器或者终端模拟器。当然,如果它像浏览器那样,将字体渲染过程中的处理交由 GPU 完成,我还是很支持的。
128 天前
回复了 june4 创建的主题 编辑器 未来最牛编辑器 zed 的 Linux 版终于出来了
虽然“未来最牛”这个说法值得商榷,Zed 作为一个编辑器还是有很多亮点的。目前来说想挑战 VS Code 的生态地位不太可能,但作为一个有潜力的(部分)替代说句未来可期不过分。至少从执行力上(当初说要做就真做了),还有第一个算是 public beta 的成品质量都是很靠谱的。

晚一点我写一下 Zed 相对比较优秀的特性,然后和 VS Code 做个简单的对比。

另外 Linux 用户应该不用担心中文输入的问题,目前只有 sway 存在不显示候选词的 bug ,其他支持 text_input_v3 的主流桌面都正常。sway 主要是维护上游 wlroots 所以发版慢,实际上自身早就支持了。
131 天前
回复了 barathrum 创建的主题 NAS 到底还是 all in boom 了
尴尬,总是一半就发出去……

如果非常在意的话,可以借鉴风险管理的思维,你能承受的损失有多大,能够接受的恢复周期有多久,由此来制定 rto rpo 策略,进而指导架构的方针。

举个例子,比如我不能接受 all in boom 带来的断网,那就把网络单独拿出来,做个硬件备份,以应对和切换。如果是不能接受存储文件的损失,那就把存储后端独立出来。凡是没有高可用需求的大可放心地集成到一起。
131 天前
回复了 barathrum 创建的主题 NAS 到底还是 all in boom 了
如果非常在意的话,可以借鉴风险管理的思维,你能承受的损失有多大,能够接受的恢复周期有多久,由此来制定 rto rpo 策略,进而指导架构的方针。

举个例子,比如我不能接受 all in boom 带来的断网,那就把网络
131 天前
回复了 barathrum 创建的主题 NAS 到底还是 all in boom 了
备份是个小事情,能不能从备份中恢复才是大事情。
这一套跑起来要多少内存属于常识性问题,不是说那遇到过才知道的。另外企业级代码也要有企业级的运行环境做支撑啊,没有配套的环境谈什么企业级。

不如反过来你尝试回答这样一个问题,这个需求你还能用别的方式熟练的完成么?不能的话那你没得选,能的话说明决策有问题。

比如这个需求 mysql 换成 sqlite 不行么,裸写 sql 不行么,甚至说存自定义格式不行么?既然都是 http 请求加 json 解析,换成 Python 不行么,如果 python 不方便部署,换成 go 之类的不行么。

特别当你知道运行环境就是 1c1g 的时候,更应该考虑这些变通的手段啊。如果换成我的话这个需求我连 self host 都不会用,免费的 cf worker 比你的小主机可用性高太多了。也许你都没考虑过长期维护的事情。这种需求要的是省心,但你现在的选型和实施都没自动化的考量,配置一个简单的 cd/ci 之后这个差距会更大。

说这么多其实是想表达,不要把完成需求仅仅局限在写代码的层面上,当成项目来管理运营会更容易做出整体上更合理的决策。
136 天前
回复了 d0x0b 创建的主题 程序员 我至今仍感到羞愧的代码
大概十多年前约 2013 年前后,我写过很多用于设备追踪和用户识别相关的代码,那个时候收集用户隐私几乎是稀松平常的存在。现在相关的技术一般叫做指纹。

如果现在让我评价,我认为这些代码属于作恶性质的。丝毫没有对用户隐私的尊重,收集的信息数据最终都变成了商品。我有的时候会宽慰自己,即使我不做也有别人去做。这么说确实没错,但是放到十多年后的今天,别人可能只会抱怨环境恶劣,而作为曾经参与其中并推波助澜的一员,我会有种非常微妙的感受,就是恶心别人到头来终究恶心到了自己。

我个人认为在当时我这里“研发”的一些技术属于思想和实现都比较领先的,甚至有些技术在十年后依旧被广泛应用。

随便举个例子,当时大概是 iOS 7 的样子,我这里就在使用 url scheme 去判断用户安装了哪些应用。当然系统是不会提供这样的 api 接口了,让应用可以直接查询到哪些 url scheme 被注册。于是我就把当时软件商店按下载量拉回来主流应用并解包,获得相关的 url scheme 。通过这样的方式,可以在静默的状态下获得已知应用(有注册 url scheme )列表中应用的安装状态。一两年之后,iOS 才对访问 url scheme 的行为增加 UI 提示。

这个方法看起来很粗糙,但是它的思想是很深刻的,实际上行业内普遍应用都是好几年之后的事情了。甚至同样的技术手段,三年前还在用于桌面浏览器的指纹识别,桌面浏览器封堵相关漏洞也是很晚的事情。

说它粗糙是因为在十多年前,使用 url scheme 的应用数量有限,即便如此,十个应用即可获得 10bit 信息,16bit 就足够识别 65536 个用户了,这在当时已经超过了大多数用广告 sdk 的客户的用户数量。(实际的有效信息量会有损失,因为像微信支付宝这样的国民应用基本不具有可辨识度)

说它深刻是因为现如今所有的指纹技术,核心思想都是通过多渠道手段,采集在统计意义上独立的特征信息,大概 32bit 在实际应用中足够非常精准的识别了。当然现如今 app 根本不用这么麻烦,因为它们几乎都是随意采集。
主要问题是这个报错 `RPM: error: Unable to change root directory: Permission denied` 因为 dnf 是脚本,最终还要调用 rpm 的。dnf 的参数 `--installroot` 根据文档的描述是类似 chroot 之后 dnf 的,这个过程里 dnf 提前设置一下 rootdir 用到的配置文件等等。这个 chroot 的操作实际上是由 rpm 完成的。上面的报错是说 rpm 没有获得 CAP_SYS_CHROOT 这个权限导致的。(另外实际安装的时候也应该也需要 CAP_CHOWN 权限,也就是说单独给 chroot 权限不够,不过 chown 权限比较复杂,后面说)

同样因为 dnf 是个脚本,所以它只是机械地检查自身是否为 root 来判断自己能否执行。所以在不改动 dnf 的前提下,只能把 dnf 放到 root/uid0 去执行(不管是不是真的)。

fakeroot 的原理是通过 LD_PRELOAD 拦截并替换需要 root 权限的 syscall ,让被调用的程序认为自己是 root 。#9 失败的原因我猜测是 dnf 是个脚本,如果是 subprocess 的方式去调用 rpm ,那么 rpm 不会实际获得 chroot 权限。

顺便说一下 fuse 的原理,它是用户空间的实现,如果用 `-o fakeroot` 的话,相当于这个文件系统还是 ext4 ,原本所有操作都应该检查 ext4 里面的权限,开启 fakeroot 之后会强制可读可写,即 RWX 那一套不起控制作用。虽然名字也是 fakeroot 但不是一个实现方式。

所以理论上,只需要运行 `unshare -m -r dnf ...` 就可以创建一个 ns 让 dnf 以 root 权限运行,`-m` 创建 ns ,`-r` 将 ns 内的 uid 映射为 root 。

我个人不建议用上面的方式来运行,因为 `unshare -m -r dnf ...` 执行的是宿主机的 dnf 所以你需要传递一些 dnf 相关的参数,尽管 dnf 是做了很多工作,但还是有可能出问题。我更建议的方式是 `unshare -m -r chroot /path/to/fedora_rootfs dnf ...` 这样直接 chroot 进虚拟机系统,然后用虚拟机的 `dnf` 完成包管理。

另外实际上这样做还是太粗糙了,有几个问题:

- ns 里面环境变量不一定正确
- 一些特殊的 /proc 之类的文件系统不会绑定
- chown 需要额外的 uid/gid 映射表才能正常工作

所以一般会用 `podman unshare` 来解决上面这些麻烦。这个命令的实现来自于 `buildah unshare`,buildah 是 RH 系的构建系统,podman 也是 RH 开发的,所以就把这个功能用同样的方式实现了。

之所以要用 `podman unshare` 而不是直接用 `unshare` 是因为你自己处理 uid/gid 映射是比较麻烦且容易出错的。而 chown 的调用在 rpm 包中很常见,rpm 在安装包的时候会执行创建用户/组以及更改权限等相关的脚本。

当以非特权用户执行 unshare 的时候,只能够映射自身 uid 或者将自身映射为 fakeroot 。这个设计的初衷是防止 ns 内部冒充宿主的 root 以避免被漏洞提权。实现方式也比较简单粗暴,比如宿主机上 uid 范围是 0~65535 那么 ns 里面就是 100000~165535 这样,ns 里面的 0 对应的是宿主机上的用户。

所以实际上要满足 ns 中支持多 uid/gid ,那么宿主机上普通用户权限是不够的,但是又不希望以 root 权限创建 ns ,于是就通过具有 CAP_SETUID 权限的 /usr/bin/newuidmap 来实现。如果你要自己手动通过 `unshare` 来完成上述工作,就需要借助 newuidmap/newgidmap 。
143 天前
回复了 gesse 创建的主题 程序员 讨论一个 UDP 问题,关于监听。
如果是 connected 可以通过 UDPConn.LocalAddr() 获得,如果是 unconnected 要通过 ReadMsgUDP 的 oob 信息获取,底层实现应该还是 IP_PKTINFO 。

如果嫌麻烦可以每个 ip 对应一个实例或者 goroutine ,这样就知道本地绑定的 ip 了。
看起来是 bug 。

F40 changeset 里面有一些关于 NM 的改动,然后看打包情况 F40 现在是 1.46 ,而 F39 是 1.44 ,可能是中间某个版本引入的。

这个直接向上游 NM 反馈可能比较麻烦,可以试试先向 Fedora Bugzilla 报一下 bug 试试。
@bigbigeggs #11

你没有理解我的意思,我是说当你的设计目标是千万级的时候,这些优化一点都不重要。

当你考虑做成比如说十亿级别服务的时候,瓶颈就不在什么 hash 算法这些你关注的细节了。

过早优化是万恶之源。
假设 URL 的最大长度是 2KB ,一千万( 10M )条数据占用的内存不过 20GB 而已。
149 天前
回复了 XuYijie 创建的主题 程序员 接口加密问题
@XuYijie #18

可能是比较机械地执行等保规定吧……既然这样的话,按照对面的要求执行就是了。

如果直接用非对称加密,你只需要拉取公钥。如果用对称加密,你一样要拉取公钥,对称加密的密钥肯定是用非对称公钥加密保护一起传回去的。

不论哪种情况你都不需要保存私钥。
1  2  3  4  5  6  7  8  9  10 ... 12  
关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2608 人在线   最高记录 6679   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 34ms · UTC 10:37 · PVG 18:37 · LAX 02:37 · JFK 05:37
Developed with CodeLauncher
♥ Do have faith in what you're doing.