$30 off During Our Annual Pro Sale. View Details »

CDNフル活用でつくる、高速Webアプリ / Using CDN To Improve Web Performance

CDNフル活用でつくる、高速Webアプリ / Using CDN To Improve Web Performance

Kazunari Hara

October 23, 2019
Tweet

More Decks by Kazunari Hara

Other Decks in Technology

Transcript

  1. CDNフル活用でつくる
    高速Webアプリ
    ~ こえのブログ実装例 ~
    Oct. 23 2019, Yamagoya 2019
    Kazunari Hara, CyberAgent
    Using CDN To Improve Web Performance

    View Slide

  2. CyberAgent Web Team is now on
    Performance Accessibility Security

    View Slide

  3. CyberAgent Web Team is now on
    WebパフォーマンスとプロダクトKPIの相関を可視化
    する話 https://developers.cyberagent.co.jp/blog/archives/9540/
    アクセシビリティへの取り組み
    https://www.cyberagent.co.jp/way/csr/accessibility/
    アメブロ2017 – 大規模サービスhttps化
    https://developers.cyberagent.co.jp/blog/archives/7743/

    View Slide

  4. CyberAgent Web Team is now

    View Slide

  5. View Slide

  6. Posting a blog entry just by speaking

    View Slide

  7. こんにちは 今日はFastly
    山小屋にきました
    Cloud
    Speech-to-Text

    View Slide

  8. こえのブログ
    is

    View Slide

  9. https://twitter.com/sisidovski/status/1158980641955823616
    Lighthouse
    score with
    firework

    View Slide

  10. Performance:
    - Fast
    - Consistant

    View Slide

  11. “Spike” -
    a sharp increase
    in the
    magnitude or
    concentration of
    visitors
    Spike reasons:
    - Breaking news
    - Launch days
    - Disasters
    - Bots
    - System issues

    View Slide

  12. When your site is slow...

    View Slide

  13. When your site is down...

    View Slide

  14. Cache helps
    performance
    improvement by
    reusing
    resources and
    removing
    unnecessary
    calculation on
    servers
    Origin
    CDN

    View Slide

  15. こえのブログ
    is made with
    Fastly and
    GCP to
    maintain
    backends
    more easily

    View Slide

  16. Cache Stats of こえのブログ

    View Slide

  17. 98%
    cache hit ratio on
    CDN

    View Slide

  18. 98% cache hit
    ratio on CDN
    if you have
    cats

    View Slide

  19. 98% cache hit
    ratio on CDN
    if you have
    cats

    View Slide

  20. 99%
    cache coverage
    on CDN

    View Slide

  21. 99% cache
    coverage on
    CDN if you
    have cats

    View Slide

  22. 99% cache
    coverage on
    CDN if you
    have cats

    View Slide

  23. 98%
    cache coverage
    in browser on
    repeat view

    View Slide

  24. Fast and
    consistent
    even during
    spike as CDN
    returns cache
    CDN Origin
    Client
    98%

    View Slide

  25. Less network
    access on
    repeat view CDN Origin
    Client
    98%

    View Slide

  26. Cache Strategy

    View Slide

  27. Cache strategy
    - Keep resources static
    - Define consistent URLs
    - Set long cache time (TTL)
    - Divide endpoint if the resource
    changes frequently
    - Tagging cacheable resources and
    purging if necessary

    View Slide

  28. Static:
    - Same for everyone
    - Cacheable
    Dynamic:
    - Variable by user/session
    - Hard to cache efficiently
    Keep as many
    resources
    static as
    possible

    View Slide

  29. Keep as many
    resources
    static as
    possible
    Web App Assets:
    Entry Assets:
    {

    “id”: “12345”, 

    “title”: “voice” 

    }


    View Slide

  30. Most
    resources of
    こえのブログ
    are static since
    the app was
    made by a
    Client Side
    Rendering
    (CSR) App
    {

    “id”: “12345”, 

    “title”: “voice” 

    }


    Fetch data from JS
    when necessary

    View Slide

  31. User data is
    rendered
    asynchronousl
    y
    Displayed later
    than ranking

    View Slide

  32. Define
    consistent
    URLs using
    HTTP methods
    GET
    - Retrieve resource
    information only
    - Do not change the state
    of the resource
    - Return the same result
    every time

    View Slide

  33. Define
    consistent
    URLs using
    HTTP methods
    POST/PUT/DELETE
    - create/update/delete
    resources
    - Not cacheable

    View Slide

  34. Define
    resources as
    cacheable or
    not
    Cacheable:
    - Most GET endpoints
    Not cacheable:
    - Few GET endpoints with
    session
    - Few POST/PUT/DELETE
    endpoints

    View Slide

  35. URL example
    GET /
    GET /editor
    GET /src/**/*.js
    GET /images/**/*.{png|jpeg|svg}
    GET /assets/audios/${userId}/${entryId}/
    GET /assets/images/${userId}/${entryId}/
    GET /api/entry/${userId}/${entryId}/
    POST /api/entry/${userId}/
    PUT /api/entry/${userId}/${entryId}/
    DELETE /api/entry/${userId}/${entryId}/
    GET /api/auth/${userId}/status/
    Cacheable

    View Slide

  36. 93%
    of endpoints are
    cacheable

    View Slide

  37. Set cache TTL
    as long as
    possible
    Response header for
    CDN:
    “Surrogate-Control: max-age=”
    - Default: 2592000 (30 days)
    - Fallback: 86400 (1 day)

    View Slide

  38. Set cache TTL
    as long as
    possible
    Response header for
    browsers:
    “Cache-Control: max-age=”
    - Default: ※
    120 (2 minutes)
    - Fallback: 86400 (1 day)
    ※ Enabled longer cache with service worker

    View Slide

  39. Divide
    endpoint if the
    resource
    changes
    frequently
    Entry
    {
    “id”: “12345”,
    “title”: “voice”,
    “view-count”:
    2946
    }
    Meta data is
    immutable
    View count
    changes
    frequently

    View Slide

  40. Divide
    endpoint if the
    resource
    changes
    frequently
    Response header for
    stale content:
    “Stale-While-Revalidate:”
    CDN Origin
    Update data in background

    View Slide

  41. Tagging
    cacheable
    resources with
    surrogate key
    “webapp” “blogger/
    ameba”
    “entry/12345 blogger/ameba”

    View Slide

  42. Purge the tag
    when
    resources have
    been updated
    New version release
    curl -XPOST -H “Fastly-Key:${KEY}” \n
    -H “Accept:application/json” \n
    “https://api.fastly.com/service/${SERVICE}/pu
    rge/webapp”

    View Slide

  43. Purge the tag
    when
    resources have
    been updated
    Data updated
    curl -XPOST -H “Fastly-Key:${KEY}” \n
    -H “Accept:application/json” \n
    -H “Surrogate-Key:blogger/ameba
    entry/12345” \n
    “https://api.fastly.com/service/...”
    Cloud
    Filestore

    View Slide

  44. These key
    ideas are also
    useful even
    when your
    app uses
    server side
    rendering
    (SSR)
    To be continued in the
    fastly meetup #3

    View Slide

  45. Backends

    View Slide

  46. Cloud
    Filestore
    Cloud
    Storage
    Cloud
    Functions
    Stable Serverless with Fastly and
    GCP
    - High CDN cache coverage
    - Event-driven execution
    - Auto scalling
    - Deployability

    View Slide

  47. Cloud Storage
    Static files in Cloud
    Storage
    - Scalable
    - As an origin server
    - HMAC Authentication
    https://docs.fastly.com/en/guides/google-cloud-storage

    View Slide

  48. Cloud Storage
    Cloud Filestore
    Event-driven functions
    Cloud Functions
    Some actions
    Event
    Cloud Storage

    View Slide

  49. onDatabaseUpdate
    Cloud Filestore Cloud Functions
    Update
    entryId: 12345
    Purge
    Surrogate-Key: entry/12345

    View Slide

  50. onDatabaseDelete
    Cloud Filestore Cloud Functions
    Delete
    entryId: 12345
    Purge
    Surrogate-Key: entry/12345
    Cloud Storage
    Delete audio

    View Slide

  51. “deployability”
    is an important
    metric for app
    quality
    Over 1,000
    web app releasesin 10 month
    Over 200
    VCL deploymentsin 10 month

    View Slide

  52. https://speakerdeck.com/herablog/web-app-checklist-2019-at-inside-frontend?slide=134

    View Slide

  53. Browser Cache

    View Slide

  54. Browser cache
    strategy
    No Service Worker:
    - Cache-Control header
    Service Worker:
    - Precaching
    - Runtime caching
    Service Worker is available in most modern browsers today

    View Slide

  55. Web app
    assets are
    cached with
    service worker
    at first visit
    and are never
    re-fetched
    until updated
    // service-worker.js
    workbox.precaching.precacheAndRoute([
    {
    url: "images/title_service_header.svg",
    revision: "6a048b548112674c9e65ed"
    },
    {
    url: "index.html",
    revision: "6805b47012688211c81521"
    },
    {
    url: "src/components/voice-app.js",
    revision: "fdf10df6f530cbce55c8f5"
    },
    ...
    ]);

    View Slide

  56. Other
    resources are
    cached as
    runtime cache
    and can be
    used when
    offline
    CDN

    View Slide

  57. VCL Recipes

    View Slide

  58. Cache key to
    normalize
    method=${req.request};
    origin=${req.http.host};
    url=${req.url};
    vary=${req.http.Accept-Encoding};
    URL and vary can be
    variable

    View Slide

  59. Query
    normalization
    import querystring;
    sub vcl_recv {
    set req.url = querystring.sort(req.url);
    set req.url = querystring.regfilter_except(
    req.url,
    "^(language|format|offset|limit)$"
    );
    }
    https://docs.fastly.com/vcl/query-string-manipulation/

    View Slide

  60. Vary
    normalization
    sub vcl_recv {
    if (req.http.User-Agent !~ "Edge" &&
    req.http.User-Agent ~ "Chrome/([^.]*)") {
    set req.http.X-UA = "esm";
    } else {
    set req.http.X-UA = "es5";
    }
    }
    sub vcl_fetch {
    set beresp.http.Vary =
    "Accept-Encoding, X-UA";
    }
    https://docs.fastly.com/vcl/query-string-manipulation/

    View Slide

  61. Basic Auth
    table customer_keys {
    "Basic a2FrZXJ1OmthZXJ1": "kakeru",
    "Basic a2FlcnU6a2FrZXJ1": "kaeru"
    }
    sub vcl_recv {
    if (!table.lookup(
    customer_keys,
    req.http.Authorization
    )) {
    error 401 "Restricted";
    }
    }
    https://docs.fastly.com/en/guides/basic-authentication

    View Slide

  62. Basic Auth
    sub vcl_error {
    if (obj.status == 401) {
    set obj.http.Content-Type = "text/html;
    charset=utf-8";
    set obj.http.WWW-Authenticate = "Basic
    realm=Secured";
    synthetic {"return (deliver);
    }
    }
    https://docs.fastly.com/en/guides/basic-authentication

    View Slide

  63. Access control
    acl office_ip_ranges {
    "192.0.2.0"/24;
    "198.51.100.4";
    }
    sub vcl_recv {
    if (!(client.ip ~ office_ip_ranges)) {
    error 403 "Forbidden";
    }
    }
    https://docs.fastly.com/en/guides/about-acls

    View Slide

  64. Routing to
    different
    origins
    sub assets_origin {
    set req.backend = F_assets_origin;
    set req.http.host = "${api-assets-domain}";
    }
    sub api_origin {
    set req.backend = F_api_origin;
    set req.http.host = "${api-org-domain}";
    }
    sub vcl_recv {
    if (req.url.path ~ "^/assets/") {
    call assets_origin;
    } else if (req.url.path ~ "^/api/") {
    call api_origin;
    }...
    }

    View Slide

  65. Adding
    surrogate key
    sub vcl_fetch {
    declare local var.SurrogateKey STRING;
    set var.SurrogateKey = "assets";
    if (req.http.x-url ~
    "/audios/standard/([a-z0-9-]{3,24})/([a-zA-Z0-9]+)") {
    set var.SurrogateKey =
    var.SurrogateKey + " blogger/" + re.group.1 + " entry/"
    + re.group.2;
    }
    set beresp.http.Surrogate-Key = var.SurrogateKey;
    }
    Extracting keys
    from URL path

    View Slide

  66. Modifying
    response
    headers
    sub vcl_deliver {
    unset resp.http.via;
    unset resp.http.server;
    add resp.http.Server-Timing =
    fastly_info.state {", fastly;desc="Edge time";dur="}
    time.elapsed.msec;
    set resp.http.Referrer-Policy = "origin-when-cross-origin";
    set resp.http.Strict-Transport-Security = "max-age=31536000";
    set resp.http.X-Content-Type-Options = "nosniff";
    add resp.http.Content-Security-Policy = "default-src 'self';...”
    add resp.http.Content-Security-Policy =
    "upgrade-insecure-requests";
    }
    Removing unnecessary
    headrers
    Adding useful headers

    View Slide

  67. (CDN) makes your app
    stable, predictable,
    efficient, deployable and
    enjoyable

    View Slide

  68. (CDN) makes your app

    View Slide

  69. @herablog
    Related documents:
    - アメブロ2019: こえのブログでのPWA
    https://developers.cyberagent.co.jp/blog/archives/20506/
    - Web App Checklist 〜高品質のWebアプリケーションをつくる
    ために〜
    https://speakerdeck.com/herablog/web-app-checklist-2019-at-inside-frontend
    - こえのブログでのPWA ~ PWA編 ~
    https://speakerdeck.com/herablog/pwa-night-vol-dot-4
    - こえのブログでのPWA ~ 開発現場編 ~
    https://speakerdeck.com/herablog/koe-no-blog-pwa
    - 最新CDN入門 WEB+DB PRESS Vol.109
    https://gihyo.jp/magazine/wdpress/archive/2019/vol109

    View Slide