# 5. 为什么有这么多fs\@overlay

![](https://github.com/XiaohanLiang/review/tree/0468b4e77b9989adab675b49a516fcd67804737a/go/src/github.com/XiaohanLiang/review/.gitbook/assets/overlayfs.png)

overlay 整体思路跟 aufs 非常接近, 也是搞的 以文件为最小单元+CoW 的那一套, 镜像作为只读层, 用的时候再贴上一层读写层形成容器. 如上图所示, 在 overlay 中, 我们把镜像层叫做 **lowerdir** , 把读写层叫做 **upperdir** , 它俩合并出来的我们叫它 **merged**, merged 也是容器直接访问的点. [点击这里看看什么叫CoW](https://xiaohanliang.gitbook.io/xiaohanliang/docker/storage-driver/overlay)

## overlay 的优点

那么还是那个经典的问题, 我们已经有 aufs 了, 为什么还需要 overlay? 思考一个问题, 在 aufs 中如果我们访问一个文件, 我们应该怎样找到它? aufs 没有任何办法指明这个文件到底存在哪儿, 它可能来自镜像中的任何一层, 所以为了找到这个文件, 我们需要遍历镜像中的每一层, 用一种 `O(n)` 的效率遍历文件.

* **但是 overlay 只有两层, 只要这个文件不在读写层(upper), 它就一定在只读层里(lower), 因此效率高**.
  * [点击这里看看overlay的上下两层结构](https://xiaohanliang.gitbook.io/xiaohanliang/docker/storage-driver/overlay)
* overlay 支持页缓存共享, 因此如果有好几个容器一起访问同一个文件, 他们一起用这个页缓存就好了
  * [点击这里看看overlay的页缓存](https://xiaohanliang.gitbook.io/xiaohanliang/docker/storage-driver/overlay)

## overlay 的缺点

... 你不觉得上面的说法很奇怪吗? 是, 你overlay会合并诸多镜像层我知道, 但如果合并镜像层真的有这么好, 那为什么 aufs 不去合并呢? 为什么这么多年了, aufs 还没把这个特性抄过来呢? 这只能说明, 这种做法同样带来了一大堆问题, 严重到已经不值得抄了.

想一个问题, 我们有镜像层, 也有读写层, 最后我们还有一个merge好了的 merged 层, 那这是不是代表说, 同一个文件, 被存储了两次? 一次存在镜像层里, 另一次存在 merged 层里?

```
# Merged层中, 文件 tty 的inode号
$ ls -i /var/lib/docker/overlay/b8d96b/merged/bin/tty
268731 tty

# 镜像层中(源文件层), 文件 tty 的inode号
$ ls -i /var/lib/docker/overlay/f193c2/root/bin/tty
268731 tty
```

你是不是都明白了? merged路径下的所有文件, 都只是源文件的一个硬链接而已, 两者指向磁盘的同一个位置, 同样一个文件并没有被存储两次, 但这个inode, 也是同样是它问题的根源

```
# Merged层中, 文件夹的inode号
$ ls -i /var/lib/docker/overlay/b8d/merged
277006 bin  726181 dev   726504 home  
726511 mnt  726180 proc  726301 run   
726503 srv  726501 tmp   ...

# 镜像层(源文件层)中, 文件夹的inode号
$ ls -i /var/lib/docker/overlay/f193c2/root
660604 bin  660606 dev   788158 home  
788160 mnt  788162 proc  788164 run   
788167 srv  788169 tmp   ...
```

虽然文件使用的是同一个inode号, 但文件夹却单独搞了一个inode号, 光是这一个容器, 我们已经消耗了如此之多的inode号, 如果在大型服务器上起一大堆容器, 是真的蛮伤的. [点击这里看看inode如果消耗光了会怎么样](https://xiaohanliang.gitbook.io/xiaohanliang/docker/storage-driver/overlay)

除此之外, 另一个毛病也还是没有解决, 那就是overlay也是以文件为最小粒度的, 我们每次修改一下镜像层的文件, 都要先将它复制到读写层里, 哪怕是改动再小, 文件再大, 这些该做的事都得做, 我们后面会介绍一种方法不用复制整个文件的.
