Day20 X CDN

https://ithelp.ithome.com.tw/upload/images/20211005/20113277srBHTjApHM.png

CDN 这个名词在前面的篇章应该出现过蛮多次的,一直感到困惑的朋友们不用担心,今天终於要来好好介绍它了!

什麽是 CDN ?

CDN 的全名为 Content Delivery Network 内容传递网路

要知道距离不仅仅是爱情的毒药(误),也是影响 response time 的重大因素。假设你身在台湾,跟一个架设在台湾的 server 取资料,花费的时间只要 500 ms,但如果去跟一个架设在美国的 server 取相同的资料,这时候的 response time 可能就增长为 3000 ms。

CDN 就是透过在各个地理位置建立 edge server 来避免取资源时都要跟距离遥远的 server 沟通,造成效能的低落。当使用者对被 CDN 加速过的域名发出 request 时,CDN 会自动将 request 导到地理位置离使用者较近或是流量较不吃紧的 edge server,尽管第一次取资源时因为 CDN 还没有快取的资料,所以仍然需要跟 original server 要资料,不过之後的 request 就可以透过地理位置离使用者较近的 CDN cache 取得,加快 client 端资源载入的速度。除了 cahce 机制以外,CDN 某方面也算是增强了服务的可用性、负载功能、安全性(降低 DDOS 对网站的影响)。

是的,跟前两天的主题一样,CDN 也提供了 Cache 机制。

这边出一个问题让各位思考一下:

到目前为止我们介绍了几种 Cache:

- `Memory Cache`
- `Disk Cache`
- `Service Worker Cache`
- `CDN Cache`

那你知道各种 Cache 的优先层级吗?
意思是指在需要资源时会先去哪种 Cache 看看有没有你要的资料,没有的话再到另一种 Cache 找。大家可以思考一下,我会在本篇的最後告诉各位解答。

为什麽需要使用 CDN ?

我们先从一个网站的运营者的角度出发,你会期望你的网站可以有以下特性:

  • 网站载入的速度够快
  • 可以 handle 大流量
  • 不管在世界的哪个角落都可以顺利且快速的访问网站(不考虑网速差异)

使用 CDN 最重要的原因就是 - 加快网站的访问速度

当然使用 CDN 还有一些额外的好处:

跨地域的全网覆盖与有效节省频宽

先前也提到 CDN 可以覆盖遍及全球的网路,所有用户都不再向同一个服务器读取资料,充分利用了网路频宽资源与平衡了网站的流量,也大量降低了原本主机的频宽及负载。

节省成本

基本上现在要使用 CDN 都会透过第三方的 Provider,我们不必自己购买与维护 server。它们也帮忙处理了不同节点 server 之间的状态与资料同步,大大节省了人力与成本。

更专注於业务逻辑开发

CDN Procider 通常除了 CDN 以外,还会提供许多多元的服务。例如 AWS 的 CDN 服务 CloudFront 就可以与 AWS 其他不同的服务串接,AWS 也会尽量确保提供高可用性、高可靠性的服务给使用者,让我们可以更专注於业务逻辑的开发,而不用时时刻刻手动监控系统的运行状况。

异地备援 & 提高可用性

当某个 server 故障时,系统会自动切换到另一个临近且健康的 node 来处理请求,提高系统的可用性,尽量让系统做到永远不中断服务。

提高安全性

CDN 的 Load Balancing 与分散式储存技术可以加强网站的可靠性,也让网站变的更能应对恶意攻击,例如上个段落提到的可以降低 DDOS 攻击对网站的影响。

CDN 基础架构

最简单的 CDN 架构可以由多个 DNS server、Load Balancer 与 Cache server 组成。

我们来模拟使用者造访一个放在 CDN 上的网站,假设叫 https://i-use-cdn.com 好了,背後的流程如下:

  1. 当使用者在浏览器输入 https://i-use-cdn.com ,会经过 local 端的 DNS server 解析,这个 local 的 DNS server 会将域名的解析权交给 CNAME 指向的 CDN 专用 DNS server。(CNAME 记录用於将一个域名映射到另一个域名,域名解析服务器遇到 CNAME 记录会以映射到的目标重新开始查询。不熟悉的读者可以参考这里)

  2. CDN 的 DNS server 将 CDN 的 Global Load Balancer IP address 返回给使用者

  3. 用户向 CDN 的 Global Load Balancer 发出请求。

  4. CDN 的 Global Load Balancer 根据用户的 IP address,以及用户请求内容的 URL,选择一台用户所属区域的「区域 Load Balancer」,并告诉用户向这台机器发出请求。

  5. 区域 Load Balancer 会为用户选择一台 cache server 来提供服务,但负载平衡器是怎麽决定要把请求导到哪一个 cache server 呢?首先它会根据用户的 IP address,判断哪一台 server 离用户比较近,再来根据使用者的请求内容,看看哪台 server 有用户想要的资源。它还会根据当前不同 server 的负载状况,看看哪台 server 还有余力可以处理用户的请求。经过这些判断之後,区域的 Load Balancer 会向 Global Load Balancer 返回一个 cache server 的 IP address。

  6. Global Load Balancer 把 cache server 的 IP address 给用户。

  7. 之後用户向 cache server 发起请求,如果快取中有用户想要的资料,就会回传给他,如果快取中没有用户要的资料,则这台 cache server 就要往上一个层级的快取看有没有自己要的资料,最远则会回到 origin server 取得资料,再更新到这台 cache server 的快取中,以备未来用户又再次请求同样资料时可以返回快取的结果。

一些常见疑问

我发现一些观念用问答的形式来讲解似乎蛮适合的,这些观念刚好也是第一次接触 CDN 的人心中可能会有的疑问,那就来个自问自答吧!

CDN 到底是对什麽加速?

CDN 是对网站的「域名 Domain」加速!如果同一个网站有多个域名,却只针对其中一个域名做 CDN 加速,那麽就只有访问该域名时会通过 CDN 快取加速,其他的域名则无法获得加速效果。

要启用 CDN 需要大改网站架构吗?

基本上,不用修改任何程序码就可以获得 CDN 加速,记得吗?CDN 是针对「域名」加速的。

哪些资源适合放到 CDN ?

CDN 适合放一些长时间不会变动的资源,例如图片、影音串流或是一些 CSS 与 JS 档案,甚至是整个静态网站也可以放。当然会变动的资源也可以放,不过既然改了就要更新快取,以避免使用者仍然拿到旧的资料,所以如果是太常改变或者是动态生成的资源就不太适合放到 CDN 上。

既然也是快取,那 CDN 如何处理内容更新的状况?

只要是 Cache,就一定会遇到更新快取的问题,如果网站的静态资源如图片更改了,CDN 快取却没有更新,那使用者看到的就还会是旧的内容。

通常 CDN Provider 都会提供 URL 推送的功能,通知 CDN 节点某些资源更新了,要把对应资源快取的资料清除掉。

通常 URL 推送服务可以透过给予完整资源 URL 针对单一资源如图片更新快取,不过如果一次改动的太多,也可以使用 folder 的形式,例如指定 kylemoironman.com/articles 代表把 kylemoironman.com 这个域名的 articles folder 内的资源的快取都做更新。

关於修改或删除快取,蛮推荐看看这篇文章,像淘宝这样大型的电商一定会有大量的商品图片需要放到 CDN 上,在遇到例如双 11 时会因为促销需要改图片上的价钱,这时旧的快取势必要更新,可以参考它们的快取架构与更新快取的机制,会对 CDN 的架构更加了解。

如何区分需要被快取与不需要被快取的资源?

有些动态的内容或资料并不适合被快取,因为经常变动,需要经常更新快取,造成 cache miss 的机率很高,整体来说没什麽效益。那要如何区分要快取与不用被快取的资料呢?其中一种做法是将网站分成两个域名,一个透过 CDN 加速,一个不使用 CDN。变动性或即时性比较高的资源就放到没有使用 CDN 的域名下。

CDN Provider

以上几个是业界较常使用的 CDN 服务,想看看更多 CDN Provider 可以看这个网站

Demo Time (For 没有设定过 CDN 的人)

还记得当初刚学习 CDN 时,概念是听懂了,但完全不知道到底怎麽帮网站加上 CDN 啊!!!有点类似拿到魔杖却不会用的感觉,真难受QQ

为了让你们不要跟我经历一样难受的心情,今天就来个最简单的 Demo 吧!

今天会 demo 使用 AWS S3 部署 React 应用程序,并整合 AWS CloudFront 这个 CDN 服务。

虽然内容会有点繁琐,但我认为可以让刚认识 CDN 的朋友更快速了解 CDN 的绑定过程,虽然每家 Provider 的流程会有些许不同,但概念都是差不多的。如果会设置的朋友就可以直接跳过 demo 罗!

What is AWS S3 ?

AWS S3,全名为 Amazon Simple Storage Service,是 AWS 提供的一个云端储存服务,可以让我们 host 一些静态资源,在本篇的范例中,我们会使用 S3 来 host 被 Webpack build 过的 React 档案,作静态网页的托管。

What is AWS CloudFront ?

AWS 提供的 CDN 服务,也就是今天的主角。

而 AWS 不同服务间的整合是非常容易且方便的,这点在等等的 demo 中读者也定会深刻体会到。

Let's Start !

既然是要部署一个 React 应用,首先就用 create-react-app 来快速兜一个专案出来吧 ! 在 terminal 输入

npx create-react-app deploy-sample

接着随便改改内容让你看得出是自己改过後的网站,接着试着跑

npm run start

确认 react app 可以正常在 local 启动,并显示自己改动後的内容。

AWS Console 设定

AWS console 就是 AWS 提供的 web 管理介面,可以设定各种 AWS 服务,首先你得先注册一个 AWS 的帐号,这边要特别注意的是,AWS 的计价方式是按照使用量付费的,也有许多种方案,可以参考这里,通常新的使用者会有一年的免费用量,可以拿来练习,不过关於费用还是请读者自行研究,万一突然被收费不要告我喔喔喔喔 ?

关於这次的部署流程,我们会需要设定三个 AWS 的服务:

  • AWS IAM
  • AWS S3
  • AWS CloudFront

AWS IAM

AWS Identity and Access Management,可以对各种服务的存取权限作管理,我们可以透过 IAM 建立多个使用者,并给予不同使用者不同的权限。以这个部署范例来说,我们需要建立一个有权限操作 S3 与 CloudFront 的使用者。

在登入 AWS console 後,我们首先寻找 IAM 服务

进到 IAM Dashboard 後,点选左侧的使用者

接着点选新增使用者的按钮

名字可以随意取,存取类型选择程序设计方式存取,点选下一步。

接着点选连接现有政策,在 filter input 输入 S3 与 CloudFront,会看到很多权限种类,这边为了方便 demo,一律选择 full access(实际就看读者的需求了)

两个都选取後,点选下一步

当使用者建立成功後,会看到上面的画面,并出现两组 KEY,这两组 KEY 只会出现这麽一次,所以务必要好好保管好,未来如果需要在 CLI 或是 CI/CD workflow 做权限验证都会需要用到它们!

AWS S3

首先一样先搜寻 S3,进入 S3 的 Dashboard

点选右上角的建立储存实体(bucket)

进到创建 bucket 的页面後,bucket 的名字可以随意取,然後将「封锁所有公开存取权」的选项取消勾选。

点击建立实体後,回到 S3 bucket 列表,会看到刚刚建立的 bucket,此时点击 bucket 连结进行更详细的设定,进到单一 bucket 的 Dashboard 後会看到

react-deploy-sample 是我自己取的 bucket name,接下来点选「属性」这个 tab,往下滑动会看到像下图一样的静态网页托管这个区块,预设是不会开启静态网托管的,在这边记得要启用它,下图中最下面的「储存贮体网站端点」这个 URL 我们得先记起来,待会在 CloudFront 的设定会用到。

接下来再切换到「许可」这个 tab,会看到如下图的区块

预设会是空的,读者必须点选编辑然後贴上以下的 JSON 格式:

{
    "Version": "2012-10-17",
    "Id": "Policy1611823861546",
    "Statement": [
        {
            "Sid": "Stmt1611823850414",
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "s3:GetObject",
                "s3:*"
            ],
            "Resource": [
                "arn:aws:s3:::换成你自己的 Bucket Name/*",
                "arn:aws:s3:::换成你自己的 Bucket Name"
            ]
        }
    ]
}

回到 react 的 project,在 terminal 输入

npm run build

产生 bundle 後的静态档案,再回到 S3 console 上传上去。

那麽 S3 的设定就完成了,最後剩下 CloudFront 的设定罗!

AWS CloudFront

首先一样搜寻 CloudFront 服务并进入 Dashboard (很简单,就不放截图了),接着点选建立分布

会进到一个要填写很多资料的页面

源网域名称要填入上面要读者记住的 S3 的「储存贮体网站端点」,也就是说 CloudFront 会从我们的 S3 bucket 去抓资料,「检视器通讯协定政策」则要改成勾选第二个「重新导向 HTTP 到 HTTPS」。

如果你有自己的 domain name 的话,可以在分布设定这个区块做设定,不过这篇文章只会使用预设的 CloudFront 网域。

接着点选建立分布,回到 CloudFront Dashboard 会看到列表中出现自己刚创建的分布,一样点击他做更细部的设定,点选「一般」tab 并选择编辑会看到

预设根物件填入 index.html,储存後回到「一般」tab

要特别注意状态的部分,因为创建 CloudFront 分布需要一点时间,所以得确认等到状态变为「已启用」才代表 CloudFront 成功生效喔!

最後在浏览器中访问上图 CloudFront Dashboard 显示的网域名称,应该就可以看到自己的 react app 了!

Demo URL : https://d1aik19n6llqss.cloudfront.net/

注意看左上角的网域名称,我们的 react app 已经成功 host 在 AWS S3 上,并且由 CloudFront CDN 作快取服务器罗!(如果想要用自己的 domain name 要记得去额外设定)

如果不放心的话可以到 DevTool 的 network tab 看看有没有 cache hit。

最後因为我们的 react 是 SPA,所以只需要 host 一个页面,但是现在如果输入一个不存在的 path,例如 /test,会导致 404 not found 的 error,所以我们可以在 S3 的静态网页托管区块设定一下 redirect 规则。

然後输入

[
    {
        "Condition": {
            "HttpErrorCodeReturnedEquals": "404"
        },
        "Redirect": {
            "HostName": "d1aik19n6llqss.cloudfront.net",
            "ReplaceKeyWith": ""
        }
    }
]

代表如果出现 404 的 Error 的话就 redirect 回首页。有了这个设定以後如果输入不存在的路径都会被自动导回首页罗!

解答时间:访问各种 Cache 的先後顺序

回到一开始请大家思考的问题

- Memory Cache
- Disk Cache
- Service Worker Cache
- CDN Cache

你知道各种 Cache 的优先层级吗?

公布答案!

memory cache -> service worker cache -> disk cache (HTTP Cache | Browser Cache) -> CDN cache

相信如果这三天关於快取的内容都有看完的话,应该不难理解前三个的顺序。至於今天介绍的 CDN 快取,很明显已经离开了浏览器的储存空间并实际发出了网路请求,得去跟邻近的 edge server 要资料了,所以顺位一定是四者的最後一个。

你答对了吗?

延伸阅读

最後想厚脸皮的自荐一下自己的两篇文章让有兴趣的读者可以延伸阅读 ?

Coding Your CDN! 充满惊奇的 Lambda@Edge:CDN 除了快取还能做什麽?最近越来越多 Serverless function 结合 CDN edge server 的服务了,让我们可以在地理位置邻近的 edge server 上跑 serverless 的 function,Lambda@Edge 就是其中一个。原来今天介绍的 CDN 还能做更多事吗!赶快去探索一下吧!

与 Github Actions 的再次相遇!AWS S3 + CloudFront 自动部署 React Web App : 应该说是今天 Demo 的进阶版本。按照我们今天 demo 的流程,每次网站更新都要重新打包再手动上传到 S3 也太麻烦了吧!别怕,CI/CD Pipeline 可以帮我们做到自动化这些步骤!

本日小结

关於 CDN,我只能说它真的是很重要很重要的技术。

今天介绍了 CDN 的概念,还有它的运作流程,也用问答的形式解释一些我自己之前的疑惑。最後附上了一个简单的 demo,主要是因为自己以前听懂 CDN 的概念後仍然不知道到底要怎麽使用它,为了让初学的人少走我走过的歪路,所幸用 AWS CloudFront 这个 CDN 服务来个简易的 demo。

最近一些 CDN 服务商都释出了可以在离使用者较近的 CDN edge server 上跑 serverless function 的服务,例如 AWS 的 Lambda@Edge 与 Cloudflare 的 Cloudflare Worker,建议读者可以去体验看看,未来的发展真的让人十分期待呢!

References & 图片来源

https://reurl.cc/vqz8Vk
https://reurl.cc/Dg2NRe
https://reurl.cc/kZe4Rd
https://www.cloudflare.com/zh-tw/learning/cdn/what-is-a-cdn/
https://www.zhihu.com/question/36514327
https://web.dev/service-worker-caching-and-http-caching/
https://www.akamai.com/zh/our-thinking/cdn/what-is-a-cdn


<<:  Day29 订单 -- 订阅

>>:  Day 23 Object oriented programming

[DAY 19]bot在线状态通知

最近bot的更新量蛮大,有时候会关掉bot方便更新程序码 为了让频道上的人知道目前bot的状态,决定...

Day 22 Odoo 动态domain

昨天讲到可以在XML写入固定的domain, 就是固定的搜寻条件 但是肯定有需求是使用者在A栏位选择...

免费小学堂 | 每日1小时 UiPath 大中华区线上讲堂

RPA人机合作|企业营运未来式|案例分享 日子过得飞快!2022 第一季即将告一段落 若你对於 RP...

端点安全防护(对应:资通安全防护)

适用人员: 技术人员。 适用法规: 资通安全责任等级分级办法 技术面分类提要 网路架构 端点安全防护...

上架流程思考

I. App 上架前准备 定位与区隔 功能与可用性 II. App 上架流程与注意事项 iPhone...