Fav2mark アプリ開発メモ
Upcoming SlideShare
Loading in...5
×
 

Fav2mark アプリ開発メモ

on

  • 1,703 views

 

Statistics

Views

Total Views
1,703
Views on SlideShare
955
Embed Views
748

Actions

Likes
1
Downloads
1
Comments
0

7 Embeds 748

http://causeless.seesaa.net 515
http://causeless.hatenablog.jp 208
http://s.deeeki.com 13
http://blog.seesaa.jp 8
http://newsblur.com 2
http://rssc.dokoda.jp 1
http://feedly.com 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Fav2mark アプリ開発メモ Fav2mark アプリ開発メモ Presentation Transcript

  • Pythonでアプリ開発メモ
  • whoami  ko-zu ◦ Python だいたい ◦ Javascript (web/userscripts) ときどき ◦ C, Java (Android) まれに ◦ twitter @cause_less ◦ http://causeless.hatenablog.jp/ ◦ http://causeless.seesaa.net/
  • 開発史  前提  ビジネスロジック ◦ OAuth ◦ データストア  並列化 ◦ 非同期フレームワーク ◦ gevent  管理 ◦ タスク管理 ◦ プロセス管理 ◦ サーバー管理
  • 動機  締め切り間際のコンテスト発見 ◦ このこん http://www.conoha.jp/conocon 6日前  自分が使うもの作ろう ◦ Twitter-はてブ連携の不満部分を実装 ◦ アグリゲーションっぽいことしたい  多少触ったことがあるツールで ◦ 最低限セキュアに書けるライブラリで組む
  • fav2mark https://fav2mark.usb0.net/ favorite: Twitterのお気に入りツイート  bookmark: はてブのブックマーク  fav → mark ◦ URLを共有できると(自分が)便利! なんのひねりもない…… 1ユーザならcronでも出来る。 貧弱なVPS(openvz)でどこまで捌けるだろうか?
  • 環境  Python2.6+ ◦ Flask, Requests, OAuthlib, Celery, gevent …  Redis ◦ redis-py  MongoDB ◦ MongoEngine (Google AppEngine風 Mapper)  当然全てOSS ◦ MongoDBはAGPL ◦ ライブラリはAPL/BSD/MIT/Python
  • 一日目  前提  ビジネスロジック ◦ OAuth → Requests + OAuthLib ◦ データストア → Redis + MongoEngine  並列化 ◦ 非同期フレームワーク ◦ gevent  管理 ◦ タスク管理 ◦ プロセス管理 ◦ サーバー管理
  • 基本設計  1ページアプリ ◦ ◦ ◦ ◦  OAuthでTwitterアクセス権限をもらう OAuthではてブ書込権限をもらう ちょっとした同期設定 Flaskフレームワークで構築 バックグラウンドタスク ◦ Twitter APIからFavoritesを取得 ◦ URLを抽出してはてブ Atom APIにPost
  • OAuth?  エンドユーザーからWebサービスの アクセス権(認可)を貰う仕組み ◦ パスワードは渡さない(≠合鍵) ◦ ユーザーは何時でも個別に無効化出来る  ユーザー認証にも使えなくはない ◦ sign in with twitter ◦ でもopenid (=IDを証明) とは別物!
  • OAuth  OAuthライブラリ多すぎ ◦ python-oauth (EOL?) ◦ python-oauth2 ◦ python-oauthlib ◦ OAuth認可フローはWebと密結合 =フレームワークとのバインディング多数  非標準パラメータ対応のばらつき ◦ はてなAPIのscopeなど
  • OAuth 危なっかしいライブラリが……  アクセストークン管理 ◦ flask-oauthはaccess tokenをsigned cookieに保存し ているような?  HTTPS証明書検証  セキュリティ上の前提がドキュメントにない ◦ 信頼チェーンとCN/SANsチェックしている? なるべく単機能で疎結合なものがほしい
  • requests-oauthlib pip install requests-oauthlib  Webフレームワーク非依存  ドキュメントが比較的まとも  HTTPカスタム認証プラグインとして実装 >>> oauth = OAuth1(client_key, client_secret=client_secret, resource_owner_key=resource_owner_key, resource_owner_secret=resource_owner_secret, verifier=verifier) >>> r = requests.post(url=access_token_url, auth=oauth)
  • Requests pip install requests  多機能HTTPクライアント実装 ◦ コネクションプール ◦ HTTPS証明書検証(Mozilla準拠CA内蔵) ◦ doc/en と doc/jp (古いけど) ◦ ヘッダ処理・リダイレクト処理  短縮URL展開も手軽に >>> res = requests.get(“http://bit.ly/1eb9WfE”) >>> print res.url u'http://fav2mark.usb0.net/'
  • Redis  オンメモリKey-Value+ Storage  memcachedの置き換えが楽 ◦ セッション・キャッシュ・ロック等に利用 ◦ key長の制限無し ◦ redis-py実装のredis API対応が素直  python-memcachedとは何だったのか……  再起動してもデータが(大抵)消えない  シングルスレッド =トランザクションが低コスト
  • MongoEngine  ObjectDictMapper? ◦ Django/AppEngineライクなモデル記述  まだ開発途上 (doc) ◦ ネスト要素の取扱が重い ◦ シリアライズ重い ◦ 致命的なバグ・未実装が……  #537 にハマったり  素のpymongoで十分だった気もする
  • ロジック実装レシピ  requests-oauthlib ◦ 認証周りはシンプルなものを ◦ セキュリティ甘いライブラリ多い  httpはpython-requestsで  ACI(D)はRedisで ◦ redis-clusterが出たら全部Redisにするかも  MongoDBでスキーマレス ◦ Python上のObjectMappingが課題
  • 二日目  前提  ビジネスロジック ◦ OAuth ◦ データストア  並列化 ◦ 非同期フレームワーク ◦ gevent  管理 ◦ タスク管理 ◦ プロセス管理 ◦ サーバー管理
  • フロー Twitterから favorites取得  共有済みかDBでチェック  短縮URLを展開  個別にブックマークを生成  ◦ 全てI/O待ちで時間が掛かる…… ◦ 並列化するしかない
  • 並列化   WebAPI経由のサービス DBクエリ ◦ …CPUはほとんどiowaitしている  プロセス・スレッドを増やす? ◦ メモリ不足 ◦ openvz VPSのプロセス数制限 ◦ CPythonのLock問題 →非同期APIを使う
  • 非同期化手法 例)Twisted(Asyncフレームワーク doc) フローを(人力で) 「短くてブロックしないコルーチン」 に分割   コールバックで遅延評価 コンテキストはクロージャか引数で維持  コンテキストがわかりづらい  分岐の記述が煩雑  他のライブラリをどう組み込む?
  • gevent pip install gevent 非同期処理「自動化」ライブラリ (doc/jp)  libev+マイクロスレッド(greenlet)  よく使うAPIのAsync版を提供 ◦ 単一スレッドでイベント待ち ◦ 一応Windowsでも動く ◦ socket I/O ◦ file I/O ◦ process/signal
  • gevent.monkey.patch_all()  非同期化作業は面倒 ◦ ブロックする処理は決まったAPI ◦ 他の処理はほとんど一瞬 ……なら手作業で遅延評価に書き直す意味は?  同期APIを非同期APIに「パッチ」 ◦ ブロックする代わりに他のタスクに コンテキストスイッチ ◦ 協調的マルチタスクをほぼ自動化
  • gevent 協調的マルチタスク  同期的プログラミングがそのまま使える ◦ タスク(Greenlet)は普通のPython関数 ◦ 外部ライブラリもほぼ無変更で並列化  greenlet数で並列度は制御可能 ◦ 純イベント駆動と違い未発火イベントの リークやソケット溢れを気にする必要なし  割り込みされない ◦ 重い処理はsleep(0)して分割
  • 並列化レシピ  from gevent import monkey monkey.patch_all()  greenlet間の排他制御はthreadと同様  あとはタスク管理に任せる
  • 三日目  前提  ビジネスロジック ◦ OAuth ◦ データストア  並列化 ◦ 非同期フレームワーク ◦ gevent  管理 ◦ タスク管理 → Celery ◦ プロセス管理 → uWSGI ◦ サーバー管理 → Ansible
  • Celery pip install celery  タスクキュー・メッセージ管理 ◦ 各種バックエンド対応 amqp/redis/RDB  ワーカープロセス管理 (celeryd) ◦ タスクをモジュールとしてロード・実行 ◦ greenletタスクに対応  cronライクジョブ実行 (celerybeat)
  • Celery  マルチアプリ対応が貧弱 ◦ タスクをモジュール化して同じワーカー プロセスに読ませる……面倒  ログ管理が貧弱 ◦ 安全にlogrotate出来ない ◦ loggingモジュール依存でutf-8が通らない
  • uWSGI pip install uwsgi  アプリケーション・サーバー ◦ php-fpmみたいなもの ◦ configファイルからWebアプリを起動 ◦ Webアプリ以外の外部deamonも対応  豊富(過ぎる?)アプリ管理機能 ◦ プロセス数管理(thread/greenletも対応) ◦ アプリリロード、ウォームアップ etc
  • uWSGI  全部uwsgiでプロセス管理 ◦ Flask  アプリのホストとリロード ◦ Celery Worker  タスクモジュールのリロード ◦ redis/mongodb  専用インスタンス ◦ 設定の一元化・アプリ別設定の簡素化
  • uWSGI  uwsgi本体はC ◦ ビルド・依存解決が面倒  pip (pythonのパッケージマネージャ)は ビルド時に依存Cパッケージ教えてくれない  Pythonバージョン依存 ◦ 別VerのPythonでvirtualenv化できない ◦ uwsgiを複数走らせる or libpython.so を動的リンクするようビルド
  • 環境管理  自前でプロセスの面倒を見る部分 ◦ uwsgi ◦ nginx  依存関係 ◦ パッケージ管理 ◦ C/Pythonライブラリのビルド ◦ 設定ファイルの統合 etc …少なくなったけど手作業管理するのは厳しい
  • Ansible pip install ansible  リモートサーバー管理ツール ◦ Chef/Vagrantと違ってデプロイ済みサーバー 管理・維持の簡略化に特化  低レベルのシスオペ向け ◦ sshでコマンドを叩く+α ◦ テスト機構は未実装  別のVPSやVagrantでテストラン  冪等性からの逸脱に寛容 ◦ Changeイベントハンドラがある ◦ 冪等性を担保しないshell command
  • Ansible  Inventory ◦ サーバーの静的リスト  AWS等の自動追加もできなくないけど…… ◦ 各サーバーの振る舞い(role)を一元管理  Playbook ◦ リモートに流し込むコマンド(task)のリスト  複雑な条件分岐は書きにくい $ ansible –i inventory.ini all –m yum –a name=nginx $ ansible-playbook –i inventory.ini myconfig.yml
  • Ansible  単純な設定同期・管理は非常に楽 ◦ sshでログイン出来る環境とpython2.5+があれば 始められる  ルール変更や失敗時の追跡が難しい ◦ playbook編集時は差分をチェックして 変更前後の挙動を把握していないとハマる  ドキュメントが分散 ◦ 開発中でAPIがよく変わる ◦ 暗黙の変数やパス展開が多く分かりにくい ◦ テンプレート展開を入れ子に適用していて エスケープに困る
  • サーバーデプロイ  今のところ手動(VPS)  Ansible+ローカルyum repo ◦ 何故かubuntuでrpm弄ってる……  セットアップ時間の大部分が SSH設定+システムのアップデート  OSテンプレート更新進捗どうですか?@VPSの中の人
  • 動いた!  約3日 ◦ OAuth対応が一番かかった気がする ◦ cat *.py | wc –l 2000くらい  エラー処理・一貫性維持は簡略化 ◦ Twitter APIが明確なので依存 ◦ 稀に多重POSTしてもAPI的に許容範囲  性能は未検証 ◦ APIのテストはダミー相手 ◦ 100並列 1000qps 程度を想定
  • ボトルネック?  MongoDB Read ◦ MongoDBレプリケーションで自動化  MongoDB write ◦ 同期済みTweetIDのwriteが増える  Redisに置き換え? or MongoDBシャーディングで対応? (ToDo)  Redis ◦ KVSとして使う限り考慮する必要無さそう  Web側はビジター増えないアプリ  バックエンドはユーザーIDでシャーディング可能
  • ボトルネック  CeleryのCPU負荷 ◦ Redis側は余裕なので分散 ◦ (デ)シリアライズが重い模様  フル機能が不要であればRedisのリストで もっと軽量に書けそう  ソケット数・バッファメモリ ◦ カーネル共有(openvz)だと厳しい ◦ KVMか専用サーバーへ  CPUが律速 ◦ レイテンシは並列化で対応してCPUが安い所へ
  • セキュリティ  SSL ◦ Forward Secrecy取得  エンコード・正規化(XSS) ◦ 全てテンプレートエンジン利用  セキュアセッション ◦ Redisで実装  fixation対策他 CSRF ◦ flask_wtf.csrf ベース  セキュリティヘッダ ◦ X-Frame-Options 他  追加対策(ToDo) ◦ サイト識別性向上 ◦ DoS耐性向上
  • 機能追加 ToDo  もう少しまともなURLフィルタリング ◦ 現状twitter側のsensitive/withheld依存 最新の同期ツイート表示  共有ツイート数カウンタ  ◦ トップにもう少しコンテンツほしい 自動デプロイ  性能テスト・モニタ自動化 
  • まとめ Requests-OAuthlib便利 geventで簡単並列化 Ansibleでサーバー管理 全部(?) Pythonで! (uwsgi pipで入るし……)
  • 参考・素材・ライブラリ  OAuth ◦ ◦  http://oauth.net/ http://wiki.oauth.net/w/page/12238520/Logo ( CC-BY-SA3.0, Chris Messina) Twitter API ◦ ◦  https://dev.twitter.com/ https://dev.twitter.com/terms/api-terms はてな API ◦ ◦  Requests (APL) ◦  http://developer.hatena.ne.jp/ja/license http://developer.hatena.ne.jp/ja/documents/auth/apis/oauth http://docs.python-requests.org/en/latest/ Requests-oauthlib (MIT) ◦ ◦  https://github.com/requests/requests-oauthlib http://requests-oauthlib.readthedocs.org/en/latest/oauth1_workflow.html MongoDB (AGPL) ◦ ◦  http://www.mongodb.org/ MongoEngine (MIT) http://mongoengine.org/ Redis (BSD) ◦ http://redis.io/ ◦ ◦ https://github.com/antirez/redis-io Redis-py (MIT) https://github.com/andymccurdy/redis-py
  • 参考・素材・ライブラリ  Flask (BSD) ◦ http://flask.pocoo.org/ ◦ http://flask.pocoo.org/snippets/75/ ◦ flask-wtf https://flask-wtf.readthedocs.org/en/latest/  Gevent (MIT) ◦ http://www.gevent.org/ ◦ http://methane.github.io/gevent-tutorial-ja/  Celery (BSD) ◦ http://www.celeryproject.org/ ◦ http://docs.celeryproject.org/en/latest/userguide/workers.html  uWSGI (GPLv2) ◦ https://github.com/unbit/uwsgi ◦ http://uwsgi-docs.readthedocs.org/en/latest/ ◦ http://uwsgi-docs.readthedocs.org/en/latest/AttachingDaemons.html  Ansible (GPLv3) ◦ http://www.ansibleworks.com/ ◦ https://github.com/ansible/ansible