Skip to content

Latest commit

 

History

History
104 lines (63 loc) · 10.9 KB

csapp_and_os_is_cache_problem.md

File metadata and controls

104 lines (63 loc) · 10.9 KB

读完 CSAPP/OSTEP 之后我跟学弟分享就是我感悟到了这两本书几乎全书通篇都在讲缓存问题,哈哈想起昨天按摩的时候听牛油果博客听的缓存问题计算机两大问题缓存失效和命名

本文以自己的思考和 GPT4 的精彩对话作为记录和总结

关于operate system the three easy pieces 和 CSAPP这两本书,我怎么觉得贯穿全书的问题其实就是缓存问题,几乎两本书全书都是讲缓存问题,从处理器-内存之间缓存,内存-硬盘之间缓存置换,虚拟内存页表如何缓存,各种时间空间局部性的数学建模,可执行文件的动态链接等等基本绕不开缓存

处理器和内存之间的缓存(CPU缓存):为了减少处理器和主内存之间的速度差异,现代CPU包含了一层或多层的缓存。这些缓存利用了程序的时间局部性和空间局部性来存储最近或频繁访问的数据。

内存和硬盘之间的缓存(磁盘缓存/页面缓存):操作系统会在内存中保持一个页面缓存,来存储最近访问的磁盘数据。当一个进程需要读取磁盘上的数据时,系统会首先检查这些数据是否已经在页面缓存中。

虚拟内存和页表缓存(TLB):转换后备缓冲器(Translation Lookaside Buffer, TLB)是一个硬件缓存,它存储虚拟地址到物理地址的映射关系。由于频繁地进行地址转换是非常消耗时间的,TLB可以显著提高这一过程的效率。

文件系统的缓存:文件系统通常使用缓存机制来优化文件访问效率,例如,系统缓存了文件的元数据或文件内容。

网络缓存:网络设备和软件会使用缓存来减少网络延迟和提高数据传输效率,比如浏览器缓存和内容分发网络(CDN)。

动态链接和可执行文件优化:动态链接器使用各种策略来减少加载共享库所需的时间,比如使用预链接(prelinking)来减少解析符号地址所需的时间。

缓存问题在计算机系统中的普遍性和重要性意味着理解它们的工作原理对于设计和优化系统至关重要。这也是为什么这两本书会在不同的层次和上下文中反复讨论缓存相关主题。一方面,缓存的有效使用可以显著提高性能;另一方面,不恰当的缓存策略可能导致性能瓶颈

关于缓存的指标或者说数学建模,我了解到一个指标是缓存命中率,此外还有一个常用的缓存指标是缓存未命中下访问时间和缓存命中下访问时间的比值,另外还有很多指标metric你能列举下吗

缓存命中率 (Cache Hit Rate)
这是最常用的缓存性能指标之一,表示请求被缓存数据满足的比例。计算公式为:缓存命中次数 /(缓存命中次数 + 缓存不命中次数)。

缓存不命中率 (Cache Miss Rate)
缓存未命中的请求数占总请求的比例,是缓存命中率的补数。计算公式为:缓存不命中次数 /(缓存命中次数 + 缓存不命中次数)或 1 - 缓存命中率。

平均访问时间 (Average Memory Access Time, AMAT)
一个请求的平均访问时间,考虑了缓存命中和不命中的情况。计算公式为:AMAT = (Hit time) + (Miss Rate) * (Miss Penalty)。

缓存穿透率 (Cache Penetration Rate)
指的是缓存不命中导致实际上对下一级缓存或主存储进行访问的比例。
缓存替换次数
表示由于缓存满载而必须替换掉一些内容的次数。高替换次数可能指示缓存太小或者缓存替换策略不够良好。

缓存抖动 (Cache Thrashing)
当缓存不停地加载和替换数据,而这些数据又立即被替换出去,就会导致抖动。这通常表明缓存大小或者其替换策略与应用程序的工作集大小不匹配。

临界字节率 (Critical Word First and Early Restart)
指在缓存行填充过程中,需要的数据被首先加载和提供给CPU的效率。

脏命中率 (Dirty Hit Rate)
在写回缓存策略中,当写操作命中了一个已经被修改(脏)的缓存行时发生的情况。
写策略影响
根据写入时机的不同(写回 vs 写穿),缓存的性能也会受到影响。

局部性使用 (Locality Utilization)
程序对时间局部性和空间局部性的利用效率,影响缓存命中率。
缓存占用率 (Cache Utilization)

请问硬盘缓存中的数据如果跟硬盘实际数据不一样的话,这种问题英文上叫dirty吗?

在计算机系统中,当缓存中的数据被修改了,但这些修改还没有被写回到硬盘或者主存储器时,这些数据就被称为"dirty"。"Dirty"通常用来描述缓存中的数据与它在主存储(例如硬盘)上的原始数据不同步的情况。

在硬盘缓存(也称为磁盘缓存或缓冲区缓存)中,修改了的数据项在被写回到磁盘之前都被视为"dirty"。这种情况通常发生在使用写回(write-back)缓存策略的系统中,这种策略允许缓存中的数据被修改多次而不立即写回到磁盘,目的是减少对磁盘的写入操作,从而提高系统性能。

由于存在"dirty"数据,当发生系统崩溃或断电等意外情况时,可能会导致数据丢失或不一致,因为这些"dirty"数据还没有被保存到磁盘上。为了防止数据丢失,系统通常会实现一些持久化机制,如定期的写回策略,或者在关键操作之前确保所有"dirty"缓存被刷新(flush)到磁盘上

关于数据库和缓存的话题,我记得有一篇论文说操作系统很多设计上就不利于数据库系统,看来似乎操作系统的一些设计反而限制了高性能数据库系统

您提到的观点在数据库研究界确实有一定的共识。数据库系统和操作系统在设计上有着不同的目标和优化点,有时操作系统的通用设计会限制数据库性能。这是因为操作系统需要服务于广泛的应用,而数据库系统往往对性能有更高的要求和更专门化的需求。以下是一些导致潜在冲突的操作系统特性:

I/O操作:操作系统的I/O层通常为了通用性而设计。数据库系统可能因为额外的抽象层和不必要的数据复制操作而遭受性能损失。数据库系统更倾向于直接控制I/O操作(如直接I/O)以减少开销。

缓存管理:操作系统使用页面缓存来减少对磁盘的访问。然而,数据库也实现了自己的缓存机制。这种双重缓存可能导致不必要的数据冗余和一致性维护问题。

调度和上下文切换:操作系统调度程序可能不了解数据库工作负载的特性,导致了不理想的线程/进程调度或频繁上下文切换。

虚拟内存管理:虚拟内存系统通过页表和TLB提供了一个抽象层,以便于内存管理。但是,这可能会带来额外的开销,特别是在数据库系统进行大量随机访问时。

系统调用开销:数据库操作频繁地使用系统调用,比如文件操作和网络通信。每个系统调用都会引入开销,因为它包含了从用户空间到内核空间的上下文切换。

针对上述问题,数据库系统可能采取不同的策略来规避操作系统带来的限制:

裸机安装(Bare-metal deployment):在没有操作系统介入的环境下直接在硬件上运行数据库系统。 定制操作系统内核:修改操作系统内核以优化数据库操作,例如通过添加特定的调度策略或者减少系统调用开销。 用户空间数据库管理:在用户空间中实现数据库管理功能,例如通过用户空间文件系统和网络堆栈来绕过操作系统。 内核旁路(Kernel bypass)技术:使用技术如DPDK(Data Plane Development Kit)直接在用户空间处理网络I/O,避免系统调用和内核干预。 这些策略可能会导致系统复杂性增加,但可以显著提高数据库系统性能。然而,这样的解决方案通常需要专门的知识和维护,这可能并不适合所有的使用场合。

数据库和操作系统之间的这种紧张关系也激发了许多创新的研究,例如提出了专门为数据库设计的操作系统,或者开发了用于特定工作负载的数据库系统

你提到应用进程workload的概念确实引发我思考,tokio被人诟病很多原因就是并不是适合很多业务场景的工作负载,例如加密货币量化交易需要非常低的延迟不需要IO负载均衡用tokio有些上下文切换延迟(无栈协程的切换甚至比有栈协程的goroutine还有高)。很多时候听上去要根据业务去定制线程池任务调度,不过听说有一种操作系统叫libOS也就是整个操作系统只为一个业务应用服务

您提到的libOS,或称作库操作系统,是一种专门针对单一应用程序或应用服务集进行优化的操作系统。这种操作系统实现通常作为库的形式存在,将操作系统的某些功能嵌入到应用程序中,允许应用程序直接调用操作系统级别的服务,从而规避了一些传统操作系统带来的开销,例如系统调用的上下文切换。

Tokio 是 Rust 语言的异步运行时,设计上适用于编写高性能的异步I/O应用。它使用无栈协程(也就是轻量级的任务或者 futures),这些协程在内存上更为高效,因为它们不需要单独的调用栈。然而,正如您所提及的,在某些极端要求低延迟的场景下(比如加密货币量化交易),任何形式的任务调度和上下文切换都可能引入不可接受的延迟。

libOS的一个典型例子是Unikernels。Unikernels 是将应用程序与运行它们的操作系统库紧密结合,构建为单一优化的可执行映像,直接运行在虚拟机监控器上,如Xen或KVM。这种结合可以显著减少传统操作系统中的资源开销和攻击面。

还有类似的概念叫unikernel,它指的是将应用程序与操作系统中最必要的部分打包在一起形成一个单一的、专门化的、轻量级的单元。这样的单元可以在虚拟机上运行,无需传统操作系统的全部功能和开销。

在专门化的场景下,依据业务特性定制线程池和任务调度确实是一种常见的实践。例如,在高频交易中,可能会采用专门调整过的线程池,以确保处理线程能够实时响应,可能会采用固定线程策略(避免动态线程创建带来的延迟),并将线程绑定到特定的CPU核心上(CPU亲和性),以减少上下文切换和缓存失效的开销。

开发者在设计系统时需要根据应用的性能要求、工作负载特性以及硬件环境来选择或设计合适的运行时和操作系统模型。在这个选择过程中,除了考虑延迟和吞吐量之外,还要考虑开发成本、可维护性和系统的健壮性等因素。

以前还指望加一些群能有大佬分享技术观点,现在觉得有 gpt4-turbo 之后问答式反馈学习真的学习效率很高