您的位置:  首页 > 技术 > 前端 > 正文

CDN边缘JavaScript敏捷交付实践

2021-10-27 16:01 OSCHINA 百度开发者中心 次阅读 条评论

本文由百度智能云-视频云-内容分发加速技术架构师——高岩  在百度开发者沙龙线上分享的演讲内容整理而成。内容从CDN应用Serverless的意义出发,详细介绍EdgeJS Serverless服务。

文/ 高岩

整理/ 百度开发者中心

视频回放:https://developer.baidu.com/live.html?id=11

 

本次分享的主题是:CDN边缘JavaScript敏捷交付实践,内容主要分为以下三个方面:

  • CDN应用Serverless的意义

  • EdgeJS Severless服务

  • 沉浸式CDN编程体验

 

 

01

CDN应用Serverless的意义

CDN基本介绍

 

CDN含义:

是指一组分布在不同地理位置的服务器,协同工作以提供互联网内容的快速交付。

 

CDN服务已得到不断普及。如今,大多数web流量都通过CDN提供服务,几乎所有的门户网站、常用的视频 APP(例如,爱奇艺、抖音)都会用 CDN 架构实现更加快速的内容分发,让用户更快地看到视频内容,带来更好的用户体验。

 

这是因为 CDN 允许快速传输、加载互联网内容所需要的资源。以门户网站为例,我们需要加载 HTML 页面、JavaScript、文件 css 等资源;而视频网站则需要加载缩略图、视频文件。

 

CDN 还可帮助保护网站免受某些常见的恶意攻击,例如分布式拒绝服务(DDOS)攻击。

 

使用CDN优势:

1. 缩短网站加载时间

通过将内容分发到访问者附近的CDN服务器(以及其他优化措施),访问者体验到更快的页面加载时间。由于访问者更倾向于离开加载缓慢的网站,CDN 可以降低跳出率并增加人们在该网站上停留的时间。换句话说,网站速度越快,用户停留的时间越长。

 

2. 减少带宽成本

网站托管的带宽消耗成本是网站的主要费用。通过缓存和其他优化,CDN 能够减少源服务器必须提供的数据量,从而降低网站所有者的托管成本。

 

3. 增加内容可用性和冗余

大流量或硬件故障可能会扰乱正常的网站功能。由于CDN具有分布式特性,因此与许多源服务器相比,CDN 可以处理更多流量并更好地承受硬件故障。

 

4. 改善网站安全性

CDN 可以通过提供鉴权、安全证书的改进以及其他优化措施来提高安全性。

 

vCDN的发展

 

早在2009年,伯克利曾针对当时兴起的云计算做过评论,并提出了以下6个潜在的优点:

  1. (理论上)无限可用的计算资源,可在资源池中实现任意的伸缩。

  2. 用户再也不需要承担服务器运维的工作和责任。

  3. 服务的按需付费成为可能。

  4. 超大型数据中心的使用成本显著降低。

  5. 通过可视化资源管理,运维操作的难度大大降低。

  6. 分时复用,物理硬件的利用率大大提高。

 

基于云计算的理念,可以实现一个虚拟化CDN(vCDN), 即可在专有、裸金属、虚拟化或基于容器的基础设施上运行CDN。vCDN作为云上的一个应用,是CDN和云紧密结合的产品。其主要功能特性包括:

硬件虚拟化虚拟化基础架构使软件和硬件功能得以分解,服务器运维大大简化。

低延迟在共享基础设施上运行CDN功能,可以更快的调起其他应用,比如可以实时进行图片处理。

弹性伸缩可以按需使用CDN,在流量高峰和低峰,进行自动的弹性扩容和缩容。

 

但是云计算技术发展到今天,虚拟化并不能解决所有的问题,

在对性能有特别高要求的场景下,面临的主要难点如下:

  • 虚拟机/容器,构建业务应用运维成本较高。

  • 不能做到按需付费,仍然需要独占虚拟机。

  • 开发复杂,需要很多其它的依赖,在开发业务的过程中,需要数据库、对象存储等框架。需要自己掌控运维和使用情况,开发难度较高。

 

Serverless介绍与特点

 

为了解决上述问题,亚马逊的 AWS 在 2015 年推出了 lambda 服务,提出了Cloud Function的概念,引起了业界对于 Serverless 的关注广泛。

 

Serverless 主要包含 Faas、Baas 两种形态。其中,Faas 将 Function 作为服务,Baas 将后端服务作为服务。

 

在应用了 vCDN 后,也可以用 Baas 的方式运行服务。Serverless 旨在让开发人员不需要再关注服务器,云会帮自动实现服务器的运维和伸缩。

 

具体而言,Serverless 具有以下特点:

1. 计算的无状态化,服务的储存和计算完全分开部署的,开发者只需要关心计算的实现,可以通过其它云上的独立服务进行储存,容易进行迁移和扩缩容。

2. 资源透明化的,无需要再关心服务器、虚拟机、容器需要多少资源、带宽、磁盘空间,可以通过调用函数在平台内实现资源的自动管理。

3.  按需计费,根据调用时长、调用次数进行计费。目前,vCDN 可以为客户提供 Baas 服务。如果用户需要更通用的函数计算产品,推荐使用百度云的 CFC,可以配置 CDN 的触发器。

 

CDN应用Serverless的意义

 

 

早在 2018年,云管理公司 RightScale 开展的一项调查显示,Serverless 是增长最快的公共云服务。

据统计,AWS 上超过一半的用户已经在使用 Serverless 服务。Serverless 一直在高速发展,呈现出越来越大的影响力。

Serverless 将无处不在,CDN也必须拥抱Serverless理念,提供边缘可编程能力,使用户可以在控制台上通过 API 设置代码,形成编程能力,更有效地控制 CDN。

 

在 CDN 业务中实践 Serverless 理念可以提供敏捷交付的能力,具有以下优势:

  • 编程能力 对于刚接触CDN的客户来说,可编程能力,即便不理解CDN的具体运作流程,也能快速编写出可用的代码。

  • 敏捷交付 对于CDN研发人员,serverless节省了他们部署和运维的时间,让他们能够更加专注于解决和优化应用本身的问题。

  • 场景下沉结合编程能力,可以和其他场景更方便的结合在一起。

  • 边缘计算在CDN的边缘,可以进行更加自由的计算,节省端上处理的时间和延迟。

     

 

02

EdgeJS Serverless服务

EdgeJS Serverless服务目标

 

Serverless 的目标是使用户可以更容易地编写和部署代码,而无需关注底层结构。尽管目前的 CDN 业务可以实现按需付费,但是仍然不够灵活。

 

为此,我们推出了 EdgeJS Serverless 服务。该服务在百度智能云 CDN 上使用JavaScript 语言去提供的一种可编程的配置能力,实现高并发、低成本的敏捷交付,使 CDN 能够体现出 serverless 的思想,进行靠拢或者是计划。

 

该服务具有以下特点:

  • 嵌入式 JavaScript runtime,而非独立的 runtime。出于对性能的考虑,在支持 JS 标准库的同事,避免了独立 runtime 带来的冷启动时间。

  • 提供请求对象 request,可以在代码中进行随意更改。

  • 提供对外访问能力。

 

作为一种 Serverless 服务,EdgeJS 需要实现用户隔离、具备较高的性能,能够动态编码。具体而言,EdgeJS 具有以下特性:

  1. 动态编码。

  2. 即时编译。即用户代码在边缘区编译之后,可以被缓存,无需进行重复编译,理论上大大提升了执行的效率。

  3. 风险隔离。即严格隔离不同用户的代码,为用户可以使用的资源设置最高上限。

     

EdgeJS Serverless服务的特性

EdgeJS致力于让CDN更易用,向serverless服务能力迈进。所以EdgeJS的定位一开始就是完全免费,在CDN按需使用的带宽费用之外,不会产生额外的费用。

 

在降低CDN使用门槛的初衷下,必须还得保持CDN的高可用、低延迟、就近服务的能力。

 

EdgeJS的设计,是完全嵌入到CDN接入层的JavaScriptruntime,无需冷启动时间,没有性能损失,并支持标准ES6语法的JavaScriptAPI,各种特性陆续补齐中。

 

而且相比传统交付,开发上线至少周级别的交付周期,EdgeJS真正能做到秒级交付,用户在控制台配置上代码,就可以秒级生效。当然建议在正式发布前,先使用预发布功能来灰度验证。EdgeJS,可以根据请求进行各种特征处理,这极大丰富了CDN接入的场景。

 

为了更好地配合 CDN 业务,EdgeJS 具有以下特性:

  • 使用 EdgeJS 在边缘进行计算(如一些特殊的鉴权等不能缓存的动态需求),将预计算任务部署在边缘设备上,大大减轻源站的压力。

  • 做到秒级交付,使用户在控制台上配置代码,秒级生效。

  • 根据请求进行各种特征处理,极大丰富 CDN 接入场景(包括不限于跨域访问、重定向、访问控制、单请求限速、自定义鉴权、m3u8改写、请求改写、A/BTest自定义错误页面等。

 

除此之外,EdgeJS还可以利用fetch等能力,和远端进行协同,包括不限于远程鉴权、云服务协同和请求画像打点上传。这些能力已经远超CDN的传统场景,向serverless服务能力靠拢。

 

在CDN庞大的算力加持下,可以减轻源站的性能压力和支出。而且,当增加了新的特征或者增加了新的计算方法,可以随时修改JavaScript代码,进行实时控制。

 

 

03

沉浸式CDN编程

 

url改写与复杂文件名改写

 

CDN 控制台本身支持一些 URL 改写的基本功能,但这些预定义的功能灵活性较低。我们可以通过 EdgeJS 根据用户的要求确定配置。EdgeJS 使用标准的 JS 语法,需要用户建立一个请求对象 request。

如上图所示,我们首先将 URL 中的大写字母转成小写,接着我们将请求的 variables 参数改成小写。variable 映射的是 UNIX 的变量,而这的规则完全一致的。

 

EdgeJS 支持复杂的文件名改写,这里涉及到三种情况:

(1)参数 attname 存在且不为空字符串

(2)参数 attname 存在且为空字符串

(3)参数 attname 不存在。

 

回源鉴权头

在一些对象存储场景下,我们可以通过 EdgeJs 构建回源鉴权头 authorization。首先生成一个随机数,获取当前时间,并生成请求 URL。接着,我们利用以上三者根据 crypto 算法生成鉴权头。

我们可以通过请求的 headersIn 特性获取请求头。有些特殊的请求头只能存在一份,如果重复则会被忽略(例如,host、connection,详见官网)。此外,重复的 Cookie 的请求头会返回所有的重复部分,并以分号分隔开来。如果我们想要获取所有的请求头,我们需要使用 rawHeadersIn 特性,如果请求头有多个,则会输出数组。

 

r.headersIn{}

请求头对象,可写Foo请求头可以使用r.headersIn.foo或者r.headersIn['Foo']来访问

"Host",  "Connection",  "If-Modified-Since", "If-Unmodified-Since", "If-Match",   "If-None-Match", "User-Agent", "Referer",

"Content-Length", "Content-Range",  "Content-Type", "Range", "If-Range", "Transfer-Encoding", "TE", "Expect",

"Upgrade", "Accept-Encoding", "Via", "Authorization", "Keep-Alive", "X-Real-IP", "Accept", "Accept-Language", "Depth",

"Destination", "Overwrite", "Date"这些请求头只能有一个,重复的会被忽略

 

重复的“Cookie”请求头,会返回所有的重复部分,并以分号(;)分隔,

重复的其他请求头,会返回所有的重复部分,并以逗号(,)分隔,

r.headersIn.foo ='foo',赋值会覆盖所有的重复部分。

 

r.headersIn ['Foo']= ['a', 'b'],赋值数组,会产生两个重复的请求头:

Foo:a和Foo:b

 

r.rawHeadersIn{}

请求头KV Array,只读。

比如请求头Host:localhost;Foo: bar ;foo: bar2

 

r.rawHeadersIn输出类似于['Host', 'localhost'],  ['Foo', 'bar'], ['foo', 'bar2']  

获取所有的请求头foor.rawHeadersIn.filter(v=>v[0].toLowerCase()

== 'foo').map(v=>v[1])

输出['bar', 'bar2']

 

文件名改写

EdgeJS Serverless 服务通过请求的 headersOut 特性可以实现文件名改写、跨域访问、设置相同的响应头等功能。

如上图所示,我们可以使用请求参数 filename 命名下载文件,使用请求头 Origin 赋值给跨域响应头 Access-Control-A。在设置相同的响应头时,我们可以通过赋值数组,产生重复的响应头。

 

r.headersOut{}响应头对象,可写Foo响应头可以使用r.headersOut.foo或者r.headersOut['Foo']来访问。

"Server", "Date", "Content-Length", "Content-Encoding",

"Location", "Refresh", "Last-Modified",

"Content-Range", "Accept-Ranges",

"WWW-Authenticate", "Expires", "E-Tag", "ETag", "Content-Type", "X-Override-Charset",

"Cache-Control", "Link", "Age",

"Retry-After",这些响应头只能有一个,重复的会被忽略

 

重复的"Set-Cookie"响应头,会返回一个数组,例如,r.headersOut['Set-Cookie'].forEach

(element=> console.log(element));

 

重复的其他响应头,会返回所有的重复部分,并以逗号(,)分隔

r.headersOut.foo ='foo',赋值会覆盖所有的重复部分。

 

r.headersOut ['Foo']= ['a', 'b'],赋值数组,会产生两个重复的响应头:

Foo:a和Foo:b

 

r.rawHeadersOut{}

响应头KV Array,只读

用法类似于r.rawHeadersIn{}

 

自定义错误页面

 

我们可以使用 EdgeJS 实现自定义的错误页面,当源站返回 404 时,可以重定向到一个对用户友好的页面。

如上图所示,我们通过 respHeader 回调实现上述功能。类似地,我们可以通过 respHeader 实现 A/B 测试,

如果源站返回了特殊头 a,可以命中一个升级的逻辑,重定向到一个应用升级的页面。

 

IP黑名单

EdgeJS 支持通过百度自有的库提供一些常用的访问控制功能:

(1)IP 黑名单,如果客户端地址在 192.168.1.1/32 或 192.168.2.1/24 等ip段内,则返回 403。

(2)Referer 白名单,如果 referer 不匹配某些通配符的形式,则返回 403。

(3)UA 黑名单,如果 UA 包含 curl 或 AppleWebKit,则返回 403。

 

代码示例:

r.remoteAddress

客户端地址,只读

 

baidu_utils库

function ipInCidr(ipv4,cidrs)

参数:

ipv4为点分十进制的ipv4地址,比如'192.168.2.100'

cidrs为CIDR地址列表,比如['192.168.1.1/32','192.168.2.1/24']

 

使用示例:

if (baidu_utils.ipInCidr ('192.168.2.100',['192.168.1.1/32','192.168.2.1/24'])) {

r.return(403);

}

function matchWildcard(str,rule)

 

参数:

str为待匹配的字符串,比如'http://www.baidu.com/'

rule为有通配符的字符串,比如'http://*.baidu.com/*'

 

使用示例:

if (baidu_utils.matchWildcard('http://www.baidu.com/', 'http://*.baidu.com/*')

{

r.return(403);

}

 

鉴权

 

百度云基于 EdgeJS 提供了 B 类防盗链等鉴权功能。原始的 URL 包含协议头 HTTP、域名、文件名。在加密之后,URL 变成了协议头、域名、时间戳、MD5 编码,文件名。

在上图的第一段代码中,CDN 服务器收到请求之后,首先拆分 URL,得到时间戳、MD5 、文件名。

在第二段代码中,时间戳的格式并非 Unicode,而是可读的格式,我们需要进行时间戳格式的转换,将秘钥与时间戳、文件名拼接,并进行 MD5 加密编码的比对。

 

子请求

CDN本身是一个缓存体系,对于hls或者dash来说,其索引文件中包含的防盗链信息,在用户请求的时候很可能过期了,所以在用户请求的m3u8或者mpd的防盗链验证通过之后,需要将这个请求中的防盗链信息改写到索引文件内容中。

 

Fetch

 

 

Fetch

ngx.fetch(url, [options])

类似于JavaScript原生的Fetch,请求URL,并返回解析Response对象的Promise。参考Using_Fetch

目前仅支持http协议,重定向需要调用者处理

类似于js fetch,options支持body/ headers / method。

 

ssl选项如下:

ssl_name 指定sni,默认为url中的域名

ssl_verify是否开启证书校验,默认开启

 

Response

标准的JavaScript内置对象

 

我们可以通过 EdgeJS Serverless 服务实现 Fetch 功能,请求远程鉴权服务器,根据远程服务器的响应进行处理,如果得到非 2xx 状态码,则返回 403 禁止访问。Fetch 返回的是一个 Promise 对象,包含类方法,可以将异步的操作变为序列化的操作,只要需要关心业务逻辑。与 Fetch 一同上线的还有 Await、SubtleCrypto 等功能。

 

以上是老师的全部分享内容,有任何问题可以在讨论区提出。

点击进入获得更多技术信息~~

扫描二维码,备注:音视频开发,立即加入音视频开发技术交流群。

  • 0
    感动
  • 0
    路过
  • 0
    高兴
  • 0
    难过
  • 0
    搞笑
  • 0
    无聊
  • 0
    愤怒
  • 0
    同情
热度排行
友情链接