Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Big “heart” of mud, 10000 lines VCL generated from .vcl.handlebars

Big “heart” of mud, 10000 lines VCL generated from .vcl.handlebars

日経電子版は創刊から10年以上続く Web サービスです。そんなサービスを開発する中でアプリケーション要件や技術的な情勢の変遷に合わせ技術の刷新, リアーキテクトなども行ってきましたが迂闊に手を出せない部分というのも存在します. その一例としてサービスの心臓部である CDN レイヤーがあげられます. 日経電子版の CDN は電子版のシステム構成上多くの責務を抱えてしまっていますが、それでも泥臭く開発し続けられるよう仕組み化されていました. しかし長年の運用により段々と Big ball of mud と成り果てました. Big ball of mud でありかつサービスの心臓部でもあるいわば Big heart of mud となっていました.

本トークでは電子版の CDN レイヤーの Muddy な開発や Muddy が故の脆さ, そして Muddy な心臓部と向き合い少しでも地盤を固めていくための Muddy な取り組みについて紹介させていただきます.

Shinobu Hayashi

December 12, 2023
Tweet

More Decks by Shinobu Hayashi

Other Decks in Technology

Transcript

  1. 1 Big “heart” of mud, 10000 lines VCL generated from

    .vcl.handlebars 日本経済新聞社 サブスクリプション事業デジタル編成 Shinobu Hayashi/Shinyaigeek 2023年12月12日 #muddy_web
  2. 2 whoami • サブスクリプション事業デジタル編成ユニット Web チーム • Web Developer ◦

    フロントエンド, CDN • Google Professional Cloud Architect • 新卒2年目 • Member of pnpm • OSS、ギター、お酒が好き 林 仁(Shinobu Hayashi) @Shinyaigeek (Twitter/GitHub) #muddy_web
  3. 5 Big “heart” of mud #muddy_web A Big Ball of

    Mud is a haphazardly structured, sprawling, sloppy, duct-tape-and-baling-wire, spaghetti-code jungle. These systems show unmistakable signs of unregulated growth, and repeated, expedient repair. Information is shared promiscuously among distant elements of the system, often to the point where nearly all the important information becomes global or duplicated. The overall structure of the system may never have been well defined. If it was, it may have eroded beyond recognition. Programmers with a shred of architectural sensibility shun these quagmires. Only those who are unconcerned about architecture, and, perhaps, are comfortable with the inertia of the day-to-day chore of patching the holes in these failing dikes, are content to work on such systems. — Brian Foote and Joseph Yoder, Big Ball of Mud. Fourth Conference on Patterns Languages of Programs (PLoP '97/EuroPLoP '97) Monticello, Illinois, September 1997 Big Ball of mud からの造語 “
  4. 6 Big “heart” of mud #muddy_web • 要約すると多様な部品から構成されておりアーキテクチャ が整然としておらずメンテナンス困難な状態 •

    アーキテクチャへの関心の欠如やプロジェクト進行上の要 求による場当たり的な変更などの蓄積により生じる www.nikkei.com における巨大な泥団子でかつサービスの 心臓部である、いわば Big “heart” of mud のご紹介
  5. 9 Agenda #muddy_web • How “Muddy” www.nikkei.com CDN is •

    How “Big” www.nikkei.com CDN is • How to battle Big “heart” of mud
  6. 13 CDN Cache First Strategy #muddy_web • CDN で Cookie

    を元にユーザーのセグメント情報(契約ス テータス, A/B テスト) をデコードしている • Origin Server からのVary Header によりそのセグメント情 報も Cache Key とし CDN で Cacheable に nikkei-foo: 1 vary: nikkei-foo
  7. 14 CDN Cache First Strategy #muddy_web • 一方で CDN で認可のため

    jwt を解く必要が生じる • 解いた結果に応じて適切な セグメントを割り当てる処 理も必要になる if (var.jwtTokenSource == "cookie") { set var.jwtSource = subfield(req.http.Cookie, "auth", ","); } else { set var.jwtSource = subfield(req.url.qs, "auth", "&"); } if (var.jwtSource ~ "^([A-Za-z0-9-_=]+)\.([A-Za-z0-9-_=]+)\.([A-Za-z0-9-_.+/=]*) \z") { set var.jwtHeader = re.group.1; set var.jwtHeaderDecoded = digest.base64url_decode(var.jwtHeader); set var.jwtPayload = re.group.2; set var.jwtPayloadDecoded = digest.base64url_decode(var.jwtPayload); set var.jwtSig = re.group.3; }
  8. 15 CDN as a microservices combiner #muddy_web • 電子版では障害の影響の波及を最小限にすべくページ単 位で

    MicroServices Architecture を採用している • CDN レイヤーでそれらを結合し path ベースでルーティン グしている • 結合層として Backend のエラーハンドリングなども執り行 う
  9. 19 Is VCL a programming language? 🤔 #muddy_web • 認証処理を行うために

    jwt の鍵などが必要に ◦ しかし VCL に secrets 相当の機能はない • Routing などを行う上で for-loop などの機能も欲しくなるが 表現力上の限界がある • local で実行もできないため機械的なテストもできない
  10. 20 Is VCL a programming language? 🤔 #muddy_web ▶ VCL

    の機能, 表現力の不足はテンプレートエンジンを駆使し ての対応を行う • .vcl.handlebars で VCL を記述し handlebars によって for-loop や secret の埋め込みを実現 • 各種メタ設定を DSL 的に JS/TS/JSON で記述する
  11. 21 .vcl.handlebars codesample #muddy_web sub vcl_recv { {{#each routing}} if

    (req.url ~ “{{pattern}}”) { set req.backend = “{{backend}}”; } {{/each}} {{#if isDev}} set req.http.debug-header = “some debug info”; {{/if}} set var.jwtKey = "{{jwt_secret}}"; } } .vcl.handlebars [ { “pattern”: “some nice regexp”, “backend”: “backend name” }, ] DSL JSON
  12. 22 .vcl.handlebars codesample #muddy_web sub vcl_recv { if (req.url ~

    “some nice regexp”) { set req.backend = “{{backend}}”; } if (...) { } set req.http.debug-header = “some debug info”; set var.jwtKey = "some nice jwt string"; } } Built VCL
  13. 26 multiple generations of www.nikkei.com #muddy_web • 日経電子版は歴史の長さ故内部的に複数の 世代を内包している •

    移行時に統合レイヤーである Fastly で吸収す るために DSL の仕様が複雑に • そして古い世代は結局いつまでも残り続け DSL 自体も肥大化...
  14. 27 Central of www.nikkei.com #muddy_web • 電子版 CDN は中央集権レイヤーとしても機能している ◦

    バックエンドのエラーハンドリングなど • その仕組みに乗るために共通規格をバックエンドに求めることになる が, SEO上の要求から異なる電子版以外の製品を同じ www.nikkei.com から配信するための場当たり的な例外対応が内在 することに
  15. 28 VCL limitation #muddy_web • VCL において subroutine を跨いでのステート管理は req.http

    に詰 め込まれた Global 変数でする必要がある • あちこちでその Global 変数が参照/変更されてしまうことに • 何をどう変えると何が変わるのか予測困難に ◦ また変更予測性の低さから整理されていない似たような変数の 乱立にも...
  16. 29 Fastly VCL limitation #muddy_web • Fastly VCL の制約上 local

    で実行できず機械的なテストも敷けない • デプロイして都度人力で確認する, という泥臭いフローでカバー • しかし如何せん責務が大きいため人力で担保する範囲にも限界があ る • 一方サービスの心臓部でもありここが止まると深刻 • 変更に際して心理的負荷が高まることに...
  17. 30 How “Big” www.nikkei.com CDN is #muddy_web • DSL 自身がプロジェクトの要請に応じて複雑かつ肥大に

    • 中央集権的な処理について特定のバックエンドでの個別対応が プロジェクトの要請に応じて差し込まれるように • VCL の特性上 subroutine を横断した処理はグローバル変数と なってしまうことで変更予測が困難に • 運用、責務上変更に際しての心理的負荷が高い状況に
  18. 31 How “Big” www.nikkei.com CDN is #muddy_web _人人人人人人人人人人人人人人人人_ >  10000

    over lines VCL  <  ̄Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^Y^ ̄ (しかもサービスの心臓部であるため迂闊に手を出せない)
  19. 35 Can I use better “heart” ? 🤔 #muddy_web •

    泥製の心臓でなくもっといい心臓に置き換えたい ◦ Fastly Compute や Cloudflare Workersなど • 昨今の Edge Computing サービスでだとプログラミング言語で 処理を記述できるし secret などの機能もある • またローカルで起動できるためテストなども実現できる
  20. 36 Can I use better “heart” ? 🤔 #muddy_web •

    一方サービスの心臓部であるためここの移植はサービス全体で のダウンタイムのリスクが高い ◦ マスメディアである以上ダウンタイムは critical に • また移行元の VCL のテストもないため移行先で同じ挙動を保証 するのが困難 ◦ テストのある基盤に移し替えるためのテストが無い
  21. 37 “Muddy” efforts for the better mud #muddy_web • 各処理のリファクタリングを行い泥の中の石を取り除き良質な泥

    に... • 混沌としていたグローバル変数の命名の整理や規格化 • 各種バックエンド向けの特別対応を規格化 • 不必要な旧世代向けのマイグレーション処理の削除 ▶ 泥臭く泥を濾過していく
  22. 38 “Muddy” efforts for the frame of mud #muddy_web •

    falco v1 から Fastly VCL の emulator が起動できるように ◦ 念願の Fastly VCL のテストがかける! • falco: fastly linter command ◦ 実態としては linter だけでなく内部の parser を利用した emulator, test runner も内包している ▶ 泥臭く泥のフレームを用意する
  23. 39 “Muddy” efforts for the frame of mud #muddy_web •

    処理(=subroutine)ごとにテストを地道に書く • CDN の巨大な責務を把握できるようテスト自体が仕様になるよ うに • この作業の中で仕様の整理や既存の挙動のなかの不穏な点の 発見にも繋がりリファクタリングにも繋がっていく • 今後の展望としては falco の emulator に対して hurl などでテス トする統合テストも...
  24. 40 “Muddy” efforts for the better heart #muddy_web • 泥臭く泥を濾過していく

    • 泥臭く泥のフレームを用意する これらの努力により泥製の心臓を崩れにくく強固なものにしていく。 また良質な泥にしフレームを用意する努力により将来的な Edge Computing 基盤への移行のしやすさも担保する。
  25. 41 Summary #muddy_web • 電子版では CDN が多くの責務を担っている • 長年の運用により Big

    ball of mud と成り果ててしまった • しかし電子版サービスの心臓部でもありおいそれと手を出せない • しかしそんな Big heart of mud であっても小石を取り除いたり 泥のフレームを固める泥臭い努力により向き合っている