我们先来定义下什么是CDN。内容分发网络(CDN)是一种由分布式服务器构成的系统,它会根据用户所处的地理位置,数据内容(通常是网页)的来源,来向用户分发网页内容。但目前这个互联网发达的时代,CDN已经不仅仅用来分发网页内容。
以Cloudflare Workers【1】为例,除了利用它的网络来分发内容,你甚至还可以在它的边缘节点上部署运行你的代码。“可以部署或运行java script代码,这能够帮助你将代码与用户终端设备解耦合,比如支持通过编程实现路由、过滤等功能”。
在当前这个爆炸式发展的互联网时代,高可扩展性是至关重要的能力。CDN和边缘计算(Edge Computing)将会进一步融合式发展。
实时数据的获取——推、拉
目前很多强调实时性的应用需要推送和拉取的数据。被动推送和主动拉取都是非常常见及简单的工程问题,比如应用初始化的过程中可以从CDN拉取历史数据,然后再由其他服务来推送更新数据。
但是,我们想一想能否将这两种机制组合在一起呢?
通过代理来连接Fastly和Fanout
Fastly是一个边缘计算平台(Edge Cloud Platform),它可以使应用在网络的边缘节点执行和提供服务。 本质上,它提供的是高度可扩展的“数据拉取-响应”服务,可以实时监听和响应用户的请求。 相比传统的CDN,Fastly也可以缓存静态内容,同时可以部署和运行应用逻辑。
另一方面,Fanout则是具备高度可扩展性的数据推送服务,比如用作高性能的反向代理服务,通过长链接为客户端实时推送数据。
Fastly和Fanout可以组合使用。它们作为一个整体可以当作源服务器的反向代理,通过Fastly来代理到Fanout的流量,这样客户端就不用直接请求你的源服务器。这会带来一些好处:
映射网络流
通过组合使用Fanout和Fastly,我们就可以重构这个“推-拉”模型中的网络数据流,下面我们来仔细看看它们是如何工作的:
假设我们有一个HTTP Endpoint是 /stream,它会返回一些初始数据,并且在有新数据产生后推送给连接的客户端。配合Fanout,我们可以让这个Endpoint返回带有instruction的response:(以response header为例)
HTTP/1.1 200 OK
Content-Type: text/plainContent-Length: 29Grip-Hold: streamGrip-Channel: updates{"data": "current value"}
当Fanout从源服务器收到这样的response,会将它转换成HTTP streaming的response:
HTTP/1.1 200 OK
Content-Type: text/plainTransfer-Encoding: chunkedConnection: Transfer-Encoding{"data": "current value"}
这样,Fanout到源服务器的请求就完成了,但是客户端到Fanout的请求(连接)仍然是open的状态,用这样的时序图来表示:
因为Fanout到源服务器是短链接的请求/响应模式,可以通过Fastly来转换成长连接:
这样当再有客户端请求/stream这个endpoint时,源服务器就完全不会参与进来:
换句话说,Fastly会给Fanout返回相同的response,带着特殊的headers已经那些初始数据,Fanout到客户端则维护streaming连接。
上述过程,我们只解决了“拉”的过程,还需要实现新数据被实时“推送”给Fanout(客户端)。
清除fastly的缓存
当源服务器的数据改变时我们需要清除掉fastly上的缓存来更新它。
还是上文的例子,假如/stream endpoint的数据产生变化,我们就需要清除fastly的缓存并同时将新数据广播给fanout。
下面这个时序图描述了一个更复杂的场景,已有的客户端将被推送新的数据,之后再来一个新客户端连接:
高效的实现流控
在这种混合架构下,为了提高效率,理想的数据读写模型是:
数据访问:每秒若干新的读
数据更新:每分钟若干写
数据分发:毫秒级投递
如果你的数据每秒都会产生变化,那最好是不要每次数据变更都清除缓存。(容忍一定程度的数据不一致性)
例如在高峰时期,我们可以限制清除的频率,大部分读请求还是由缓存数据来响应,稍候再更新数据。
Demo
这里提供了托管在GitHub上的demo应用源代码,它利用fastly和fanout提供一个live
counter服务。
请求会先到fanout,然后到fastly,最终传递到一个由Django实现的backend server。这个服务实现了简单的计数器逻辑,当计数器的值更新了,fastly的缓存会被清除掉,同时再通过fanout发送出去。清除和更新的过程都由流控来限制,以尽可能提高缓存的效率。
脑洞一下
我们可以设计一个消息内容分发网络,它由完全是地理位置分布的若干组server构成,可以提供近实时的动态内容和静态内容分发。
这种新类型的CDN网络可以使得数据处理延伸到网络边缘,不用管应用本身的源服务位于哪里。这将为移动应用和IoT应用形态带来巨大的想象空间。