Skip to content

創作プラットフォームにおけるコンピュータサイエンス vs 俺たち

公開日:

東京都台東区浅草橋ヒューリックホール&カンファレンスで開催された『traPavilion』でスポンサーセッション(10分)として発表しました。

東京都新宿区株式会社キュービックで開催された『第180回 PHP勉強会@東京』でレギュラーセッション(20分)として発表しました。

Download PDF

スライドテキスト

Page 1

創作プラットフォームにおける

コンピュータサイエンス vs 俺たち

Computer Science vs. Us: An Engineering Story from pixiv

pixiv Inc.

USAMI Kenta

2025-10-13 #traPavilion東京科学大traP10周年カンファレンス

Page 2

お前誰よ

  • うさみけんた (@tadsan) / Zonu.EXE / にゃんだーすわん
  • 北海道工業大学(2007〜2012年、現北海道科学大学)
  • ピクシブ株式会社 Platform Div > WebTechnology Team PHPer
  • 2012年末から現職、APIとかCIとかいろいろなところを見つめてきました
  • Emacs PHP Modeを開発しています (2017年-)
  • プログラミング言語にこだわりがある (セキュリティ&プログラミング2010)

Page 3

お前誰よ

  • うさみけんた (@tadsan) / Zonu.EXE / にゃんだーすわん
  • 北海道工業大学(2007〜2012年、現北海道科学大学)
  • ピクシブ株式会社 Platform Div > WebTechnology Team PHPer
  • 2012年末から現職、APIとかCIとかいろいろなところを見つめてきました
  • Emacs PHP Modeを開発しています (2017年-)
  • プログラミング言語にこだわりがある (セキュリティ&プログラミング2010)

Page 4

お前誰よ

  • うさみけんた (@tadsan) / Zonu.EXE / にゃんだーすわん
  • 北海道工業大学(2007〜2012年、現北海道科学大学)
  • ピクシブ株式会社 Platform Div > WebTechnology Team PHPer
  • 2012年末から現職、APIとかCIとかいろいろなところを見つめてきました
  • Emacs PHP Modeを開発しています (2017年-)
  • プログラミング言語にこだわりがある (セキュリティ&プログラミング2010)

Page 5

CSっぽいカリキュラム全然なくて絶望した

お前誰よ

  • うさみけんた (@tadsan) / Zonu.EXE / にゃんだーすわん
  • 北海道工業大学(2007〜2012年、現北海道科学大学)
  • ピクシブ株式会社 Platform Div > WebTechnology Team PHPer
  • 2012年末から現職、APIとかCIとかいろいろなところを見つめてきました
  • Emacs PHP Modeを開発しています (2017年-)
  • プログラミング言語にこだわりがある (セキュリティ&プログラミング2010)

Page 6

普段やってる仕事

Page 7

<?php

Page 8

Page 9

Page 10

Page 11

pixivとDBを直接共有しているのはPHP (モノレポ)

Page 12

それ以外は開発時期や体制に応じていろいろ

Page 13

Page 14

CPUバウンドスループット重要

Page 15

WebSocket

CPUバウンドスループット重要

C10K問題

Page 16

WebSocket

CPUバウンドスループット重要

C10K問題

普通のWebサービスはDBのI/Oで律速するので言語は支配的ではない

Page 17

PHP: Hypertext Preprocessor

  • Web開発にしか使えない、遅い動的言語… と考えられている
  • 型がない、あるいは貧弱な言語… と、認識されている
  • ちょっぴりC言語っぽい標準関数と->
  • そこはかとなくJavaっぽいオブジェクト指向
  • とてもPerlっぽい構文 (特に変数の $ と、文末の ; )

Page 18

こういう言語の型解析とかFWについて発信してます

PHP: Hypertext Preprocessor

  • Web開発にしか使えない、遅い動的言語… と考えられている
  • 型がない、あるいは貧弱な言語… と、認識されている
  • ちょっぴりC言語っぽい標準関数と->
  • そこはかとなくJavaっぽいオブジェクト指向
  • とてもPerlっぽい構文 (特に変数の $ と、文末の ; )

Page 19

PHPは見る人の心を映す

Page 20

現役の学生にはPHPへの感情は特にないかも

Page 21

20年以上Webを支えている言語

Page 22

個人的にはハックしがいのあるおもしろ言語

Page 23

Page 24

Page 25

pixivは2007年から絶え間なく開発が続いている

Page 26

いろんな人たちの問題解決が詰まっている

Page 27

さも自分がやった仕事のように紹介します

Page 28

URLルーティング

vs 俺たち

Page 29

Page 30

Page 31

/data/www/www.pixiv.net (document root)├── index.php├── novel│ └── show.php├── yyy.php└── zzz.php

Page 32

/data/www/www.pixiv.net (document root)├── index.php├── novel│ └── show.php├── yyy.php└── zzz.php

Page 33

/data/www/www.pixiv.net (document root)├── index.php├── novel│ └── show.php├── yyy.php└── zzz.php

Page 34

/data/www/www.pixiv.net (document root)├── index.php├── novel│ └── show.php├── yyy.php└── zzz.php

Page 35

/data/www/www.pixiv.net (document root)├── index.php├── novel│ └── show.php├── yyy.php└── zzz.php

Page 36

/data/www/www.pixiv.net (document root)├── index.php├── novel│ └── show.php├── yyy.php└── zzz.php

Page 37

/data/www/www.pixiv.net (document root)├── index.php├── novel│ └── show.php├── yyy.php└── zzz.php

Page 38

/data/www/www.pixiv.net (document root)├── index.php├── novel│ └── show.php├── yyy.php└── zzz.php

Page 39

/data/www/www.pixiv.net (document root)├── index.php├── novel│ └── show.php├── yyy.php└── zzz.php

Page 40

/data/www/www.pixiv.net (document root)├── index.php├── novel│ └── show.php├── yyy.php└── zzz.php

Page 41

ファイルをサーバにコピーすればデプロイ完了する

Page 42

Railsとか使えば綺麗なURLになるよね

Page 43

NovelController#show

# routes.rb get '/', to: 'index'get '/n/:id', to: 'novel#show'get '/u/:id', to: 'user#show'get '/yyy', to: 'yyy'get '/zzz', to: 'zzz'

Page 44

NovelController#show

# routes.rb get '/', to: 'index'get '/n/:id', to: 'novel#show'get '/u/:id', to: 'user#show'get '/yyy', to: 'yyy'get '/zzz', to: 'zzz'

Page 45

NovelController#show

# routes.rb get '/', to: 'index'get '/n/:id', to: 'novel#show'get '/u/:id', to: 'user#show'get '/yyy', to: 'yyy'get '/zzz', to: 'zzz'

Page 46

NovelController#show

# routes.rb get '/', to: 'index'get '/n/:id', to: 'novel#show'get '/u/:id', to: 'user#show'get '/yyy', to: 'yyy'get '/zzz', to: 'zzz'

Page 47

NovelController#show

# routes.rb get '/', to: 'index'get '/n/:id', to: 'novel#show'get '/u/:id', to: 'user#show'get '/yyy', to: 'yyy'get '/zzz', to: 'zzz'

Page 48

NovelController#show

# routes.rb get '/', to: 'index'get '/n/:id', to: 'novel#show'get '/u/:id', to: 'user#show'get '/yyy', to: 'yyy'get '/zzz', to: 'zzz'

Page 49

NovelController#show

# routes.rb get '/', to: 'index'get '/n/:id', to: 'novel#show'get '/u/:id', to: 'user#show'get '/yyy', to: 'yyy'get '/zzz', to: 'zzz'

Page 50

pixivはフレームワークに乗ってない

Page 51

時は流れて…

Page 52

pixiv本体にもURL正規化の流れ

Page 53

# routes.rb get '/', to: 'index'get '/n/:id', to: 'novel#show'get '/u/:id', to: 'user#show'get '/yyy', to: 'yyy'get '/zzz', to: 'zzz'

Page 54

# routes.rb get '/', to: 'index'get '/n/:id', to: 'novel#show'get '/u/:id', to: 'user#show'get '/yyy', to: 'yyy'get '/zzz', to: 'zzz'

Page 55

# routes.rb get '/', to: 'index'get '/n/:id', to: 'novel#show'get '/u/:id', to: 'user#show'get '/yyy', to: 'yyy'get '/zzz', to: 'zzz'

定数URLはハッシュテーブルでO(n)で取得

Page 56

# routes.rb get '/', to: 'index'get '/n/:id', to: 'novel#show'get '/u/:id', to: 'user#show'get '/yyy', to: 'yyy'get '/zzz', to: 'zzz'

定数URLはハッシュテーブルでO(n)で取得

Page 57

URLにIDが組み込まれている場合は…?

# routes.rb

get '/', to: 'index'

get '/n/:id', to: 'novel#show'

get '/u/:id', to: 'user#show'

get '/yyy', to: 'yyy'

get '/zzz', to: 'zzz'

定数URLはハッシュテーブルでO(n)で取得

Page 58

ボトルネックじゃなけりゃ雑に処理すればいいじゃん(大富豪の発想)

Page 59

Page 60

URLルーター作った!

(ここまでは自分の仕事)

Page 61

pixiv本体にもURL正規化の流れ

Page 62

Page 63

たったの100個でこの有様これだから線形時間はだめ

Page 64

どうにかしよう

(と競プロ得意な同僚が言った)

Page 65

URLルーティングには実装の定石がある

Page 66

正規表現ベース実装

  • 全部のルーティング対象のパスを結合したパターンを構築して、リクエストされたパスをマッチさせる
  • めちゃくちゃ力技っぽく見えるが… アイディアはシンプル
  • ところで… 現代の実用的な正規表現エンジンはJITコンパイルされ、速い

Page 67

基数木(パトリシアトライ)

  • パスを “/" で区切りってネストした連想配列を構築する

Page 68

基数木(パトリシアトライ)

  • パスを “/" で区切りってネストした連想配列を構築する

get '/', to: 'index'get '/xxx', to: 'xxx#index'get '/xxx/:id', to: 'xxx#shoq'get '/xxx/yyy', to: 'yyy'get '/xxx/zzz’, to: 'zzz'

Page 69

基数木(パトリシアトライ)

  • パスを “/" で区切りってネストした連想配列を構築する

get '/', to: 'index'get '/xxx', to: 'xxx#index'get '/xxx/:id', to: 'xxx#shoq'get '/xxx/yyy', to: 'yyy'get '/xxx/zzz’, to: 'zzz'

{"", : {"#result": "index"}"xxx", : {"": {"#result": "xxx#index"},":id": {"#result": "xxx#show"},"yyy": {"#result": "yyy"},"zzz": {"#result": "zzz"},...

Page 70

では作ろう

(さも自分がやったかのように)

Page 71

では作ろう

(さも自分がやったかのように)

Page 72

正規表現vsパトリシアトライ

Page 73

Page 74

選ばれたのはパトリシアトライでした

Page 75

パトリシアトライを実装しよう

  • 正規表現に比べアルゴリズムが素朴で、実装もめちゃくちゃ簡単
  • パスのリストから “/” でネストした多次元の連想配列に変換するだけ
  • 可変パラメータは数値と文字列のみ対応 (複雑なパターンも対応は可能)
  • 構築コストはルーティング数によって線形増加するが、十分許容できる
  • キャッシュも可能だが、いまのところはボトルネックになっていない
  • マッチしない場合も処理時間のペナルティがない

Page 76

ルーティングはできた

Page 77

めでたしめでたし

🎉

Page 78

あとは既存コードをURLルーターに載せればいいだけ

Page 79

/data/www/www.pixiv.net (document root)├── index.php├── novel│ └── show.php├── yyy.php└── zzz.php

Page 80

/data/www/www.pixiv.net (document root)├── index.php├── novel│ └── show.php├── yyy.php└── zzz.php

Page 81

/data/www/www.pixiv.net (document root)├── index.php├── novel│ └── show.php├── yyy.php└── zzz.php

Page 82

/data/www/www.pixiv.net (document root)├── index.php├── novel│ └── show.php├── yyy.php└── zzz.php

Page 83

現実にはファイルが何百個もある!!!

Page 84

/data/www/www.pixiv.net├── index.php├── novel│ └── show.php├── yyy.php└── zzz.php(実際にはファイルが数百個)

Page 85

/data/www/www.pixiv.net├── index.php├── novel│ └── show.php├── yyy.php└── zzz.php(実際にはファイルが数百個)

Page 86

/data/www/www.pixiv.net├── index.php├── novel│ └── show.php├── yyy.php└── zzz.php(実際にはファイルが数百個)

Page 87

www.pixiv.net/inc/├── IndexController.php├── Novel│ └── ShowController.php├── YyyController.php└── ZzzController.php

/data/www/www.pixiv.net├── index.php├── novel│ └── show.php├── yyy.php└── zzz.php(実際にはファイルが数百個)

Page 88

手で移植するのはナンセンス

Page 89

PHPカンファレンス2017

Page 90

Page 91

Page 92

Page 93

Page 94

Page 95

Page 96

Page 97

今も同じコードが元気に走り続けてます

🏃

Page 98

枯れた機能なので

積極的に弄る動機がない

(PHPのBC breakを踏まない限り)

Page 99

Notes on Programming in C

ルール2: 計測すべし。計測するまでは速度のための調整をしてはならない。コードの一部が残りを圧倒しないのであれば、なおさらである。

̶ Rob Pike

https://www.lysator.liu.se/c/pikestyle.html

訳語はUNIX哲学 - Wikipediaより引用(2025年10日2日12:33:03版)

Page 100

裏返せば、計測してみてスループット悪化の主要因と判断されない限り安全性と開発者体験を優先

Page 101

PHPには型宣言の機能がある

Page 102

処理系が実行時に自動型チェックを実施

Page 103

実行時?遅いのでは?

🤔

Page 104

かつてはそうだった

Page 105

言語のホットスポットは処理系で改善されると嬉しい

Page 106

現代はJITが改善され型宣言した方が最適化の恩恵を受ける

Page 107

当てずっぽうで「速い」ものを選んでも問題解決にならない

Page 108

これからの時代こそ自我をもって問題解決しよう