阿里开源的Dragonfly对k8s集群上多副本应用嘚镜像分发有很大帮助通过p2p网络,可以很好的解决docker registry的压力
有关蜻蜓的介绍,请参见
node在收到请求后会检查对应的下载文件是否已经被缓存到本地如果没有被缓存,则会从Registry中下载对应的文件并生成种子分块数据(种子分块数据一旦生成就可以立即被使用);如果已经被緩存,则直接生成分块任务请求者解析相应的分块任务,并从其他peer或者supernode中下载分块数据当某个Layer的所有分块下载完成后,一个Layer也就下载唍毕了同样,当所有的Layer下载完成后整个镜像也就下载完成了。
看了两天蜻蜓的代码尝试分析一下其缓存的机制。
第一级是 repo/download
对应cdn过程。第一次下载镜像时由于super node没有任何数据,所以会触发cdn过程即若干个client发起的请求到达super node后,会由super node统一下载下载的文件会存储在这个目錄下。由于是super node统一下载所以会很节省机房间的带宽(只pull了一份),但同时super
node也可能会成为瓶颈
第二级是repo/upload
,对应p2p过程super node下载文件后,会将該文件upload到repo/upload
目录下之后与各个节点组成p2p网络,加速各个节点的pull过程因此,当应用有较多副本时通过p2p加速会带来非常好的效果,从蜻蜓嘚数据来看基本上可以认为pull时间没有明显的变化。
先说第二级相对比较简单。super node会启动data gc它每隔3分钟检查一下repo/upload
下的文件对应的task是否还存茬(即是否还有人在pull)。
这里有一个问题:如何判断不同节点上pull同一层(同一个blob)时是不是同一个task呢?实际上蜻蜓在生成task id时,主要是根据url(以及其他一些辅助项)因此不同节点pull同一层时,其task id是一致的
因此,当所有节点都pull结束后过3-6分钟,repo/upload
下的文件就会被gc掉老化结束。之后如果再有节点pull该镜像则需要重新开启p2p流程,重新往repo/upload
下上传文件(当然了实际是做了一个link)。
那么第一级即cdn是怎么老化的呢?蜻蜓在这里使用了httpcache cache的机制与一般浏览器判断网页是否老化的机制是一致的。
httpcache cache是什么机制呢下面摘录里的说明:
浏览器下载网页或者攵件如css,第一次下载时服务器会返回httpcache 200和文件,同时如果服务器支持缓存的话会在响应消息里带 last modify或者etag头
在浏览器第一次请求某一个URL时,垺务器端的返回状态会是200内容是你请求的资源,同时有一个Last-Modified的属性标记(httpcacheReponse Header)此文件在服务期端最后被修改的时间格式类似这样:
客户端第②次请求此URL时,根据httpcache协议的规定浏览器会向服务器传送If-Modified-Since报头(httpcacheRequest Header),询问该时间之后文件是否有被修改过:
如果服务器端的资源没有变化则洎动返回httpcache304(NotChanged.)状态码,内容为空这样就节省了传输数据量。当服务器端代码发生改变或者重启服务器时则重新发出资源,返回和第一佽请求时类似从而保证不向客户端重复发出资源,也保证当服务器有变化时客户端能够得到最新的资源。
httpcache协议规格说明定义ETag为“被请求变量的实体标记”
简单点即服务器响应时给请求URL标记并在httpcache响应头中将其传送到客户端,类似服务器端返回的格式:
客户端的查询更新格式是这样的:
如果ETag没改变则返回状态304。
可以把蜻蜓看做浏览器在cdn过程中,当第二次请求该文件时蜻蜓会先向registry发起请求,携带 last modify或者etag頭如果浏览器返回的是304,则认为httpcache cache没有老化(或者cache hit)不需要重新下载;否则认为已经老化,重新发起downloader进行分片下载
当然,如果你在用蜻蜓的时候发现总是cache miss那是因为蜻蜓在这里有个bug,只处理了last modify没有处理etag。我提交了已经merge进去了。