V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX  ›  kuanat  ›  全部回复第 3 页 / 共 17 页
回复总数  330
1  2  3  4  5  6  7  8  9  10 ... 17  
在编程语言 Null/Nil/Zero 设计取向这个问题上,我很难说清自己的偏好和立场。这个问题我也尝试去理解、思考过很多次,暂时的结论是,对语言设计者来说这是个技术或者取舍问题,对语言的使用者来说更倾向于是一个工程问题。



我就以 Go/Rust 为例做个对比。

Go 的设计是 make zero useful ,相当于扩大了 zero 的功能,减少了 null 的存在。这样做的好处是:

1. 避免了 c 或其他语言的 UBI 初始化前就使用的情况( go 设计受 c 的影响很大)
2. 简化了编译器开发,go 早期的编译器基本上是手搓的,没有 null 的话数据类型在内存的布局就很简洁
3. 直接支持组合,go 是 duck typing 和组合优于继承思想的产物,基础类型默认零值初始化那么组合类型也间接初始化了
4. 代码稍微简化一点,不太用写 null 判断了

缺点主要是两方面:

1. 零值有歧义
2. 引用类型的 nil 可能不够安全(运行时)

Rust 走的是完全内存安全的路线,所以设计上就没有传统的 Null ,所有 & 引用都永远不会是 Null 。

为了达到这个效果,Rust 强制开发者使用 Option<T> 处理可能的 Null ,同时代码上也要显式初始化变量。即便有默认零值,也是通过 Default trait 来显式指定的。

内存布局方面,因为要在数据本身之外存储是否为 Null 的标记,所以这个内存布局是相对复杂的。为了解决这个问题,Rust 引入了一个叫 Null Pointer Optimization 的优化,具体原理我不太清楚。

总体上代码编译慢和这些设计因素是分不开的。好处是确实不需要写 Null 判断了。

这两个语言在 nil 安全上是没有本质区别的,对 nil 解引用只能在运行时才能发现。而这两个语言都有 ffi 的需要,所以业务层面也是无法避免的。



所以设计起点比较高的语言,根本的目标都是想要优化 Null 处理逻辑,只是方法和路线不一样。

当涉及到具体的业务时,只要用到“数值代表状态”的逻辑,最终总要有代码做判定,区别只是这个代码发生在什么地方。原本这个逻辑和 Null/Zero 不相关,只是因为开发中 Null/Zero 最常用,所以才出现业务代码要判定 Null/Zero 的需求。

所以我的认知里,Null 应当是一个技术细节,而永远不应该是一个业务特性。特别是软件开发越来越强调网络交互而不是单机单体应用的时候,Null 就是个隐患。我更倾向于强制在业务层面上禁止 Null 的使用。但我这种想法实施起来难度很大,几乎稍微有点历史的数据库都是会区分 Null/Zero 的,没有办法禁止其他人使用 Null 特性。
154 天前
回复了 kuanat 创建的主题 NAS 全闪 NAS 的一些心得体会
@hanyuwei70 #16

btrfs 文件系统损坏的话题我特意没有在正文里提,因为我这里无论笔记本还是 NAS 都是 raid1 配置,没有遇到过无法恢复的情况。实际上大部分单副本配置的 btrfs 在底层设备损坏的情况下是无法恢复的,我如果说 btrfs 很稳定会造成误导。



从原理上说,btrfs 和 ext4 这类的区别是:btrfs 不关心也不管理底层块设备的坏块映射,ext4 会有坏块列表。btrfs 认为底层 hdd/ssd 会自己管理坏块的重映射。但这并不能说明 ext4 的处理机制就更完善,实际上 ext4 只有在创建的时候才会初始化坏块列表,日后的使用过程中,只有出现 io 错误且用户主动标记才会更新这个坏块列表。而 btrfs (包括 zfs )这类都是根据数据校验信息来间接判定底层设备出现了问题。

上面这段话的推论是,在使用过程中如果底层存储设备发生了块损坏,btrfs/zfs/ext4 都能发现 IO 类损坏,同时 btrfs/zfs 还可以发现静默类( bit rot )损坏。但是在没有额外副本的情况下,btrfs/zfs/ext4 都没有修复能力。

所谓的修复,仅限于数据和文件系统的信息不一致的情况下,通过假设文件数据本身没有问题,来重建文件系统元数据,使其匹配数据本身。这个假设在存储密度越来越大的今天已经很难成立了,所以新的文件系统都转向了 file extent 级别的校验,而非块级别的校验。

这是存在于大量用户认知中的误区,认为底层设备坏了,运行个命令就能修复,这是不可能的。这也是我坚持 raid1 的原因,本质上它不是备份而是可用性手段,基于两个 ssd 发生相同数据映射的块同时损坏概率非常低这个假设,可以快速(自动)判断数据正确的那个副本,而不是必须要立即去其他备份副本提取。



假设现在有一个不开启 raid 默认配置的 btrfs ,文件系统元数据(目录结构、权限属性这些)是双副本的,单个文件的元数据( inode 和时间戳这些)因为是文件系统元数据的一部分,所以也是双副本的,只有文件数据本身是单副本的。

底层设备损坏有两种情况:

1. 主控坏掉了,多发生在 ssd 设备上
2. 部分物理块损坏,然后这个块可能对应着纯数据块,也可能对应着元数据,还可能同时对应着数据和元数据,甚至损坏量大的话,元数据的双副本也会损坏

前者的情况对于所有文件系统都一样,第二种情况这里可以简单分析一下。

- 如果只是数据块损坏了,它是系统文件可能就无法引导,普通文件的话就是坏掉了。这种情况下 btrfs 检测到,两份元数据是一致的,而数据校验信息和元数据对不上,就会非常明确地提示用户数据损坏,但是很显然 btrfs 是没有修复这个损坏数据的能力的
- 如果恰好只坏了某个文件的元数据一个副本,那文件系统是可以根据数据和它另一个元数据副本校验正确这个事实,来推断出前一个元数据副本损坏了,从而完成元数据副本的修复
- 如果大量物理块失效,数据和元数据都损坏了,就无从判断了

由于目前 ssd 的存储密度太高了,一旦发生损坏基本都是大量块同时,所以容易造成 btrfs 不稳定不安全的错觉。传统机械硬盘存储密度低,

我想表达的是,当出现明显的数据异常的时候,还假定数据本身没问题,想要文件系统去尝试修复,这个行为是错误的,在这个情况下 btrfs 之类的文件系统撂挑子反而是非常正确的行为。



由于我非常清楚这个底层的机制,同时坚持使用多硬盘的 raid ,所以即便 ssd 上有坏块,也被 btrfs 自动修复了。很可惜我没有遇到过主控好而颗粒坏的情况,没有相关的经验。在 NAS 的机械硬盘版本上,我是有遇到过硬盘损坏的,系统大量报错,然后因为硬盘自身坏了,btrfs 自动修复行为也反复失败导致降级。最终的结果就是我把坏的硬盘换掉,重新 balance 就好了,不会去尝试修复。我现在没有什么数据支撑,因为它没有坏过,所以我也确实不关心 btrfs raid1 在后台 scrub 的过程修复了多少错误。
155 天前
回复了 kuanat 创建的主题 NAS 全闪 NAS 的一些心得体会
@ndxxx #14

数据并没有完全本地化,有一部分冷备用的是公有云最便宜的一档,按目录价来说大概 100 元/TB/年,协议价会少一半吧,总体并不便宜。

公网环境就是普通的 300Mbps ,没有上到千兆。之前有因为移动合约拉过第二条,仅仅是作为备份用,没有真正做过双接入或者负载平衡的设计。

主要原因是我的大部分数据并非来源于 pt ,而是日常工作、生活的私有数据,所以不太依赖公网。

我的算力需求主要是编译 Android 系统(自己刷机用)和一些个人应用,另外是编译 linux 内核和一些 rust 工程。这类 cpu/ram 需求用抢占式实例非常便宜,大概几毛钱一小时。但是类似服务器转码 h264 h265 就不太合适,因为流量费用并没有折扣。
155 天前
回复了 kuanat 创建的主题 NAS 全闪 NAS 的一些心得体会
@totoro625 #7

物理上如果数据不能存在于单一存储池中,就必须要用物理手段对存储设备打标签。比如我之前只有六个盘位但有二十块盘的时候,只能把冷备盘打个 tree 结构用来检索了。后面就只说软件层面的检索问题。

Linux 有个 fsearch 和 everything 的原理比较接近,但它只能做元数据实际上也就是文件名的检索。我研究过 Spotlight 之类的系统级索引工具,提供内容检索的方式手段有两个,一个是增加特定数据格式的解析,比如 office 系列用的 xml 格式,二是应用程序主动适配系统的检索接口。

所以我缺少的只是基于内容的检索,涉及到元信息的检索可以用这些已有的工具。



我解决内容检索的思路是:首先明确我需要快速检索的内容有哪些(多数非我自己产生的内容可以不需要检索),然后确定我需要用什么方式来检索(就是建立哪些索引),最终就是构建我自己的索引数据库并开发配套的后台索引和检索工具。

我这样做的底层逻辑是,数据索引一定要在数据产生时就同时构建,类似于数据库,想要查得快,就一定要提前花时间写索引。我又是长期的 Linux 用户,生态上来说只能自己造轮子了。



数据库方面有三个选择,csv/sqlite/嵌入式 kv ,最终选择了 csv 。因为我想了一下,这个方式用 grep 之类的工具检索最简单,存储结构比 sql 灵活,也不需要额外依赖。同时 csv 基本只有追加和按行检索,数据量几十 MB 放内存也没什么性能问题。一条典型的数据大概是这样的:

XXXX.pdf, /path/to/pool/location, keyword1, keyword2, keyword3, ...

第一栏固定为文件名,用于检索到之后再去使用元信息定位文件本身。第二栏是我自己习惯的存储路径,人能看懂就行。后面全是关键词,有关键词就能匹配到。



基于这个数据结构,所谓的建索引就是根据文件内容手动或者尽可能自动生成关键词。后台索引就是基于 inotify 监听我关心的数据文件夹,每当有文件变动时,后台索引模块就根据文件格式去匹配我的索引规则脚本,执行脚本更新索引数据库。

例如项目代码之类的我就忽略掉了。纯文本类文档的处理脚本就是做个分词,去掉无意义的,然后保留五到十个高频关键词。pdf 类的不太好处理,我一般手动标记一下。

之前视频和图片类也不太好处理,大概从前年开始,我给图片加入了处理逻辑。原理就是用文生图的反向 CLIP 模型,通过图片来生成文字描述,同时 ocr 过一下提取一些文本。本身这个检索就是为我自己服务的,如果需要类似于人脸识别归类,这些放到 NAS 上面用专门的工具去做。

检索前端就是 dmenu 配合 fzf 去检索这个 csv 数据库,基本上任何一个 launcher 类应用都能胜任,也能用于命令行。通过串联脚本可以实现类似实时预览的高级功能。


总体来说这是个非常原生态、专注吃狗粮的做法。思路不难,实现难度也不高,只是实践起来有比较高的初次迁移成本。还是那句话,每个人的需求不同,没有标准化的普适方案。
155 天前
回复了 kuanat 创建的主题 NAS 全闪 NAS 的一些心得体会
@totoro625 #7

1. 我在 zfs/btrfs 上都不用 dedup 功能。有过一次人工去重,前后花了大概一个月吧……

2. 笔记本->m6->NAS 或者 笔记本->NAS 的数据流是单向的,严格来说不能叫同步,如果是双向的脑子就不够用了。我大概五六年前就不再使用类似 dropbox 的多节点双向同步盘方案,作为人来说很容易确认哪个设备上的副本是权威副本,但机器处理这种分布式同步问题是比较无力的。

3. 我用过退役的机架服务器,待机功耗就有 100w 左右,主要还是工艺太落后了吧,但也没到不能接受的程度。只是这个设备在家不好放,也没有好用的散热和静音方案。后面改用超微标准板型的,用主流设备就好很多。这个平台上主要是 hba 卡,网卡虽然也会增加基础待机功耗,功耗的大头已经转移到十多块盘本身上面了。所以我不再关心功耗问题,更关心长期维护的事情。

检索方案有点复杂,我单独开个回复来说。
155 天前
回复了 kuanat 创建的主题 NAS 全闪 NAS 的一些心得体会
@idontunderstand #4

如果电源瓦数低,可以直接限制 ssd 本身的功率。一般 ssd 有几个功率等级,高的话能到 8w 左右,限制到 2~4 档位就比较稳了。
155 天前
回复了 kuanat 创建的主题 NAS 全闪 NAS 的一些心得体会
@dilidilid #3

现在 zfs 扩容也方便了很多,在我开始用的时候还没学习到,走了不少弯路。

btrfs 的 raid 5/6 我没用过,因为几乎所有文档都说不稳定。

除了笔记本上因为盘位限制只能 raid1 ,一般 NAS 多盘位的情况下,只需要决定冗余程度(数据和 meta 副本数量),或者说能承受几个盘数据损失就够了。从数据恢复的角度上说,多条带不是很友好,多副本更灵活一些。

我没用 zfs 主要是它不在内核主线里。
155 天前
回复了 kuanat 创建的主题 NAS 全闪 NAS 的一些心得体会
@thetbw #8

苹果稍微有点不同,可以认为是强制开启 FDE 全盘加密,而主控在 SoC 里面,所以扩容是可以的,但主控和存储颗粒分离就会因为无法解密而丢失数据。
156 天前
回复了 eurstein 创建的主题 NAS 零刻 ME mini 6 盘位固态 NAS 值得入手吗
好不好关键看是不是匹配需求。这个价位的全闪 nas 对于手里有前些年淘汰下来 256g 512g 或者 1t 存储的用户比较友好。

以我个人经验来说,盘位越多越舒服,特别是全闪 nas 4/6 盘位几乎没有体积差别,而 hdd 能差 50%。体验改善这主要得益于软件进步,一方面存储卷可以无视底层硬件,老旧 ssd 也可以发挥余热,另一方面可以渐进升级,基于 file extent 的各种软 raid 可以以一块盘为单位做替换。比如新淘汰的 1t 可以替换掉系统原有的 256g 的盘,这个 rebalance 过程很快,灾难恢复也简单。
假如你很关心 bit rot ,然而硬件上又没有 ecc 内存,还有一个替代方案。

这个方案是利用 intel/amd cpu 自带的内存加密技术,intel 这边叫 Total Memory Encryption TME ,amd 叫作 Transparent Secure Memory Encryption TSME 。大概 intel 是在 11 代消费级 cpu 上开始支持,amd 大概 3000 系就有了,但是具体还要看主板 bios 是否有对应开启选项。

这个功能的原理是 cpu 内部在每次启动后自动生成一个 aes 密钥,对内存数据进行透明加密,单个加密块的大小为 512bits/64Bytes 。

当发生 bit rot 的时候,1 bit 的变化最多会造成 512bit 的数据变化,极大概率会造成 crash 或者用户可见的数据异常。
写的很好啊,有很多点我也有类似的经历。

我补充一点关于定责和复盘这些非技术的事情。因为这些年我做过一线、负责人和老板,所以各个角度都有体验。定责复盘,实际上可以分为负责人(项目、组织经理)向老板汇报、向团队成员复盘两个部分,只是经常放在一起,而且以前者居多。

我的建议是负责人要勇于承担责任,团队成员的失误就是负责人的失误。即使承担责任压力很大,也切忌甩锅。(开发、测试和运维团队之间可以适当相互帮忙背锅,分担一下压力。)从老板的角度上说,损失已经发生了,也不会非要把直接责任人找出来开掉。老板也需要台阶下,不然后续还怎么继续展开工作。从权责对等的角度上讲,如果一个团队总是不粘锅,那它就不重要,所以是极有可能最先被优化掉的那个。

作为负责人,向团队成员做技术复盘的时候,更要注意对事不对人。本质上换个人并不能解决根本问题,能解决问题的只有排除人为失误的可能。那种出事临时工背锅的思路是不利于带团队的,人心散了。
161 天前
回复了 tenzinjamyangzhs 创建的主题 Linux 为什么 fedora 的性能释放这么拉胯?
tuned-adm 看一下,切换到 latency-performance 之类的配置试试。这个东西替代了之前 power profile 。

另外 fedora 默认 selinux 开启可能会有一点影响,这个我隐约有个印象测试能差 5%,记不清了。
@shalingye #21

考虑先实现出来吧,就用系统的 api 这样可以覆盖所有情况,延迟和性能的问题先不去处理。

粗略估计 4k 120hz 10bit 无压缩每帧数据量在 30MB 左右,单帧时间 8.3ms ,单从数据量上来说,如果是通过某种网络协议传输是没有带宽压力的,主要困难是延迟,发送接收涉及编解码。obs 有个 ndi 实现(现在叫 DistroAV ),就是在一台设备上采集,然后通过网络将数据传输到另一台设备上进行编码,可以参考一下它去掉网络开销的延迟水平。



共享内存的路线,Linux 的实现方式大概是这样的:

1. Linux 宿主机内核驱动 virtio 实现了 IVSHMEM

2. Linux 虚拟机或者 windows 虚拟机也通过 virtio 的驱动模块启用 IVSHMEM

3. 虚拟机和宿主机通过指定相同的物理地址实现内存共享( IVSHMEM 本质是虚拟 PCI 设备)

4. 虚拟机内的特定应用(你要开发的)将 framebuffer 封装好后写入 IVSHMEM 的特定区域(手动管理)

5. (可选)宿主机应用通过 IVSHMEM 读取对应的 framebuffer 并做后续处理



这里可以看到 IVSHMEM 实际只是非常粗糙的共享内存机制,还需要在它的基础上实现用它完成 fb 数据交换。之前提到的 looking-glass 就是实现了一个叫 KVMFR 的模块,在 IVSHMEM 的基础上封装了一个用于 fb 数据交换的接口(硬件设备),同时实现了宿主与虚拟机之间的同步、锁,另外它用来做数据交换的格式是 dma-buf ,这样宿主机上的窗口合成器可以直接使用。之后,虚拟机的采集应用( obs/ffmpeg/系统采集)直接将数据写入 KVMFR 。

如果你要在 windows 实现类似的功能,需要把 vmbus 当作 IVSHMEM ,然后在上面实现一个 windows 版本的 KVMFR 。



估计这样表述应该就清楚了,由于我对 windows 不是特别了解,所以上面的方案不一定正确。
@kuanat #19
@shalingye #16

中间发不出来的一段是关于如何获取 framebuffer 的。通过系统 api 会有二次复制的延迟,通过显卡特定 api 更合适。
@kuanat #18
@shalingye #16


最后再回到之前说的共享内存方案。实际上 framebuffer 的数据结构某种程度上说是硬件相关的。也就是说,即便在虚拟机和宿主机之间通过虚拟设备共享了内存,一方面要对接这个虚拟内存的读写接口,另一方面需要将 framebuffer 封装成一种统一的格式。这样在宿主机上,用于显示虚拟机内容的窗口可以直接将 framebuffer 提交给窗口管理器进行合成,即再次 DMA 到显卡。

如果我说得不是很清楚的话,可以参考 https://looking-glass.io/ 这个项目,它的核心实现是 KVMFR https://github.com/gnif/LookingGlass/blob/master/module/kvmfr.c 这个模块,基于 IVSHMEM 完成我之前说的流程。理论上 windows 上实现相同效果的原理是一样的。
@kuanat #17
@shalingye #16

我之前回复的是满足第二个要求的方法。先不考虑虚拟机里的视频信号从哪里来的,假设你已经获得了实时 framebuffer 流,可以走网络协议,同时由于宿主机和虚拟机在一起,也可以走共享内存。技术上说,所有走网络协议的方案因为存在编解码、封装,都不可能比直接内存共享延迟更低。就拿 kvm 常见的虚拟化方案来说,SPICE 是个网络协议,但与 qxl 搭配的时候,使用的是共享内存。

从原理上说,kvm 这边直接用 SPICE 就可以了。我搜了一下 vmbus 的文档,虽然提到了共享内存,但我感觉用它来共享 framebuffer 需要做的工作还很多。
@shalingye #16

如果我没理解错的话,你的需求是这样的:宿主机上运行的虚拟机,然后宿主机的某个客户端窗口,显示虚拟机的视频输出内容。

为了达到目标性能要求,一方面需要虚拟机本身能够实现高分辨率高刷新率,另一方面这个达标的显示输出能够在宿主机上正确还原,中间的通信延迟要足够低(输入设备还在宿主机上并没有直通到虚拟机)。



为了达到第一个要求,一般有两个方案:

1. 使用半虚拟化驱动设备,比如 qxl ,virgl 还有一些都属于这种,在虚拟机里面使用虚拟的显卡设备,这个设备会将渲染指令传递给宿主机,通过宿主机执行后再将结果传回虚拟机

2. 直通物理显卡或者利用 sriov 直通物理显卡虚拟出来的显卡

我对 windows 不熟悉,猜测 windows 的几个实现原理上应该都是上面两个思路。



不知道触发了什么关键词,我二分一下拆开回复。
@kuanat #68

vscode 不行哈哈,原因就是 #73 说的。
Linux 这边 virtio 也有类似的需求和实现方案。

我个人的理解是:

- 如果虚拟机内部是虚拟的 gpu ,那么就可以直接共享内存,宿主机直接访问虚拟机内虚拟 gpu 的 framebuffer

- 如果虚拟机内部有直通的 gpu ,那就只能从 framebuffer 入手抓取视频源(比如 nvfbc ),然后再共享给宿主机

应该不存在比直接内存映射更高效的 IPC 方式了。
1  2  3  4  5  6  7  8  9  10 ... 17  
关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1112 人在线   最高记录 6679   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 22ms · UTC 18:19 · PVG 02:19 · LAX 11:19 · JFK 14:19
Developed with CodeLauncher
♥ Do have faith in what you're doing.