Varnish Cache 的架构笔记 已翻译 100%

run_mei 投递于 2013/09/26 13:58 (共 15 段, 翻译完成于 09-29)
阅读 4688
收藏 120
11
加载中

当你接触到Varnish源码,你就会发现Varnish并不是你的那些常见的普通的应用。

这绝不是偶然。

在FreeBSD内核方面我花费了好多年时间,极少有闯入用户空间编程的时候,但是当我有这样的机会时,却总是发现人们的编程方式就像仍然在1975年。

因此当我开始Varnish项目时,我真的不感兴趣,直到我想到我可以尝试将我所知道的硬件和内核运作方面的一些知识充分发挥作用,我才意识到这是一个很好的机会,现在我们进展到了alpha阶段,我可以说我非常喜欢它了。

super0555
super0555
翻译于 2013/09/28 20:33
2

那么1975年的编程有什么问题?

最简短的答案就是,计算机不再有两种存储结构了。

曾经的主存储器,一开始是充满水银的声波延迟器(acoustic delaylines filled with mercury),再到小磁性线圈,再到晶体管触发器,直到现在的动态随机访问内存。

之后辅助存储器出现了:卡带、磁带、硬盘。起先硬盘像房子一样大,继而是洗衣机一般大小,近来它已经变得如此小,女孩子可能会失望,硬盘怎么会像口袋里的MP3一样了,可惜不能听。

人们的编程方式也差不多这样。

他们把变量放在“内存”,用“硬盘”存取数据。
super0555
super0555
翻译于 2013/09/28 20:52
2

以 Squid 为例,一个我曾经看到过的 1975 风格的程序:你告诉它能够使用的 RAM 和磁盘空间。然后它会花费大把的时间来跟踪哪些 HTTP 对象在 RAM 中和哪些在磁盘中,并根据传输的运作模式来回移动它们。

而事实上当今的计算机只有一种存储系统,它通常是某类(存储)盘,操作系统和虚拟内存管理硬件将 RAM 转换成这类(存储)盘存储的缓存。

所以 Squid 精心设计的内存管理机制是在与内核精心设计的内存管理机制作对,且和任何一场内战一样,一事无成。

mingshun
mingshun
翻译于 2013/09/29 11:29
2

事情是这样的:Squid 在“RAM”中创建了一个 HTTP 对象,接着很快就被使用了几次。一段时间后它没有再被命中过且内核注意到了这点。然后某人因为某些用途尝试向内核获取内存,内核便决定将内存中那些暂时没有使用到页面拉出到交换空间并很明智地将它们(缓存RAM)用在某程序中确实要处理的数据上。但这是在 Squid 毫不知情的情况下发生的。Squid 依然以为这些 HTTP 对象还是在内存里,而它们将会是(译者注:就是在未来某个时间内核会将它们再次从交换空间拉回内存)。很快,Squid 想访问它们,但直到那一刻,那段 RAM 正在用于其他的处理工作。

虚拟内存就是这么一回事。

如果 Squid 做点别的,情况会好很多,但这就是 1975 风格编程的开始。

mingshun
mingshun
翻译于 2013/09/29 11:57
2

一段时间后,Squid 也会注意到这些对象是没用的,并打算将它们转移到磁盘中,以让空出来的 RAM 可用于更频繁被用到的数据。Squid 便出来创建一个文件,然后将这个 HTTP 对象写入这个文件。

现在我们切换到慢速回放:Squid 调用 write(2),我所提供的地址是一个“虚拟地址”,内核已经将其标志为“不在家(译者注:不在物理内存中,已被转移到交换空间)”。

所以 CPU 硬件分页单元会发出一个软中断(trap),操作系统中所谓的中断就会告诉它“请恢复一下内存”。
内核尝试寻找一个空闲的页面,如果没有,它会拿将某个不怎么使用的页面,很可能是另一个很少使用的 Squid 对象,将写入到磁盘上的页面池(交换空间)。当那些写入完成后,它会从页面池的另一个数据被分页出去的地方读入到现在不使用的 RAM 页面,再修改分页表,并重试刚执行失败的指令。

mingshun
mingshun
翻译于 2013/09/29 12:19
2

Squid 对此一无所知,对 Squid 而言这只是一次常规的内存访问罢了。

所以现在 Squid 让这个对象出现在内存中的页面上,还将其写到磁盘上,这就出现了两个副本:一个在操作系统的页面空间里,另一个在文件系统中。

Squid 现在将这段 RAM 作其他用途,但一段时间后,这个 HTTP 对象被命中了,所以 Squid 需要将它取出来。

首先,Squid 需要得到一些 RAM,因此可能打算将其他 HTTP 对象放到磁盘上(重复上述的步骤),然后从文件系统的文件中读入这个 HTTP 对象,再然后向网络连接套接字发送这个 HTTP 对象的数据。

这听起来是不是在给你做无用功啊?

mingshun
mingshun
翻译于 2013/09/29 15:42
2

这是 Varnish 的做法:

Varnish 先分配一些虚拟内存,并告知操作系统将这段内存备份到磁盘上的一个文件的存储空间中。当需要向客户端发送对象时,它只要提交那块虚拟内存空间,剩下的就交给内核即可。

如果/当内核认为它需要 RAM 作其他用途时,那个页面会被写到后备文件并将这段 RAM 用于其他地方。 当 Varnish 下次提交这段虚拟内存时,操作系统会查找一个 RAM 页面,也可能会释放一个,并从后备文件中读入其内容。

仅此而已。Varnish 并不会去控制哪些内容缓存在 RAM 中或哪些不是,内核代码和硬件维护程序会处理好这些事情,并且的确处理好了。

mingshun
mingshun
翻译于 2013/09/29 15:59
1

Varnish 也只是使用了一个磁盘文件,而 Squid 却将每个对象放到各自独立的文件中。HTTP 对象不需要像文件系统对象那样,所以对于每个对象都在文件系统命名空间(目录、文件名和诸如此类的东西)上浪费时间没有任何意义,在 Varnish 中所需要的就是一个虚拟内存的指针和一个长度值,剩下的就是内核的事了。

虚拟内存就是为了在实际数据量大于物理内存容量的时候让编程变得更容易而出现的,而人们却仍然不明白。

mingshun
mingshun
翻译于 2013/09/29 16:16
2

更多缓存

可是现在我们已经有越来越多的cache,硅工程师可以生产出差不多主频达到4GHz的CPU,他们甚至在CPU和RAM( 事实上是4级cache)之间能放上一级、二级、有时是三级的cache。当然也会有其他的一些东西,比如写缓冲、流水线和页模式的存取,所有这些都为了能更快得从内存中读取数据。

由于它们已逼近4GHz的极限,但随着硅材料尺寸减小,可以有越来越多的晶体管一起工作,多CPU的设计也开始在世界上变得越来越流行,尽管作为一个编程模型它们实际上很糟糕。

多CPU系统没什么新鲜的东西,不过写程序时可以每次使用多个CPU很棘手,而且现在仍然是这样。
super0555
super0555
翻译于 2013/09/29 18:25
2

在多核系统上写出运行优良的程序事实上更加棘手

假设我有两个用来统计的计数值:

        unsigned    n_foo;
        unsigned    n_bar;

现在一个CPU在运行,并要执行n_foo++。

为了做到这个,它先读n_foo,然后把n_foo写回。它有可能把它加载到CPU的寄存器中,也可能不会,这并不是很重要。

要读某个内存地址意味着要检查它是否在CPU的一级cache中。除非它被频繁使用,一般都不会在的。然后检查二级cache,我们假定也是cache失中。

如果这是单CPU的系统,游戏在这里 结束了,我们会从RAM内存取出数据并继续执行。
super0555
super0555
翻译于 2013/09/29 18:33
2
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(8)

pangee
pangee
NICE
jiangyuan
jiangyuan
这种架构风格值得推广。
UMU
UMU
squid 的各种中枪
FalconChen
FalconChen
这个值得研究
我叫张大熊
我叫张大熊
是真的不錯 公司從squid換到varnish的很不錯 2345.com
蟋蟀哥哥
蟋蟀哥哥
@红薯 varnish真的不错。。
snail_pang
snail_pang
不错的文章!
乌龟壳
乌龟壳
符合unix哲学的设计
返回顶部
顶部