O'Reilly Japan Community Blog

このblogには、オライリーWebサイト協力者からの寄稿記事や、独自のインタビュー、レポート記事などを掲載します。

ここ最近のWebサービスでは、Googleを始めとする他のサービスが提供するAPIを使用して、そのデータを活用するというのが当たり前になってきており、また、そのためのライブラリ等の基盤も整っています。今回はそうしたライブラリの使い方からちょっとだけ先に進んで、外部APIのアクセス数制限を回避するためのキャッシュについて説明します。

はじめに

はじめまして。Retty株式会社の鹿島と申します。今回からこのblogに記事を書かせていただくことになりました。今後、読者の皆さんのご意見なども取り入れつつ、何か役に立つような内容を書いていければと思っていますので、よろしくお願いします。

この記事の内容ですが、我々が開発しているRettyというWebサービスでの実例を通じて、教科書にはあまり載っていないtips、落とし穴等を紹介したいと思います。対象読者として以下のような方を想定しています。

  • Webサービス開発に興味がある人
  • これからはじめようと思っている人(比較的初心者の方)

具体的には以下のような経験があることを前提としています。

  • (言語を問わず)プログラミングの経験
  • Facebook等のWebサービスの使用経験

このサイトに来ている方の大多数は、この前提をクリアしているだろうと思います。

Rettyのサービス概要

Rettyのサービスページ

Rettyのサービスページ

まずは、我々が開発しているRettyというサービスについて少し紹介させて下さい。Rettyは「行ったお店を共有する、記録するソーシャルグルメサイト」です。具体的な機能は以下のようになります。

  • 行ったお店のレビューを投稿する
  • 「友達」や「嗜好の合う人」をフォローして、その人達の投稿をタイムライン(TL)上で閲覧する
  • 行きたい店があった場合には、行きたいリストに追加する
  • スマートフォンで、現在地付近の人気のお店、行きたいリストに追加したお店を検索する

サービスはWeb、iPhone、Androidのマルチプラットフォームで展開していますが、以下のように使い分けている方が多いようです。

  • TLの閲覧やお店の行きたいリストへの追加 → Web
  • 現在地付近のお店検索 → スマートフォン
  • 投稿 → Web、スマートフォン両方

オライリー・ジャパンから先日発表されたプレスリリース「ePUBフォーマットによる電子書籍のラインナップを開始します」にあるとおり、弊社トップスタジオはオライリー・ジャパンとの共同事業として、ePUBフォーマットでの電子書籍の制作を開始しました。 トップスタジオではこのePUBフォーマット電子書籍の出版候補の選定、翻訳、編集、そしてePUB制作までに関わっています。本稿では、このePUBの制作プロセスを支えるシステムにフォーカスを当て、その仕組みについて紹介します。

フリーソフトウェア/オープンソースソフトウェアの集合体としてのシステム

ePUBの作成にはいろいろな手法がありますが、制作を支えるシステムを構築する上で最も重視したのは、できる限り自動化し、手作業による調整を最小限にするということでした。そのため、このシステムでは原稿を常に最新マスターデータとしてそこから一方向にePUBを作成するバッチ型としており、たとえばSigilなどでePUBを後で細かに手直しする、といった手法は採用していません。

また、将来にわたって保守・改良が制作関係者自身の手でできるよう、中核部分をフリーソフトウェア/オープンソースソフトウェアで構成し、原稿の形式もオープンなものであることも当然の前提です。

さらに、訳者や編集者など制作にかかわる人たち(このシステムのユーザ)は、文章についてはプロフェッショナルであるもののソフトウェアについてはそうではありません(逆もまた真なり、ですね)。新しくツールを導入したことでそれに振り回されないように、ユーザ側から見て新しく導入するものを最小限にし、面倒な部分はできるだけシステムの内部に置くとともに、原稿の文法エラーチェックなどを自動化し、原稿更新に合わせて即座にePUBやHTMLのプレビューもできるようにする必要もありました。

こうした背景からできあがったのが、次の図に示すシステムです。

オライリー・ジャパンのePUBを制作しているシステム

オライリー・ジャパンのePUBを制作しているシステム

このシステムで採用している技術やソフトウェアの概要をまとめてみます。

プログラムのロジックを考え、実装を行う上で、変数の名前空間やスコープはとても重要です。 これらはロジックを組み立てる上での複雑さに直結し、ソースコードの読みやすさにダイレクトに関係してくるためです。 この記事では、私が Python で開発をする上で気をつけるようにしている名前空間やスコープに関するお話をします。

対象環境

この記事では、 Python 2.7.2 でソースコードを実行して確認しています。

コーディングスタイルについて

名前空間やスコープの前に、まずは基本的なコーディングスタイルについて軽くお話しします。

Python のコーディングスタイルというと、 PEP 8 – Style Guide for Python Code (日本語訳は こちら )が有名です。 これは、 Python でプログラムを書く上で守っておくとよいお作法について書かれており、 Python のコーディングスタイルとしてはデファクトスタンダードといえるでしょう。

この PEP8、例えば以下のようなことが書かれています。

  • インデントは 4 スペースで
  • タブとスペースを混ぜて使わない

といったような Python らしいインデントの話から

  • 演算子の前後にスペースを入れる
  • 代入演算子を縦にそろえるためスペースを入れることはしない
  • モジュール・クラス・変数・関数などの名規則
  • 推奨される例外処理方法

などの書き方に関することまで広範に及びます。

Python で開発をするのであれば一読しておくことをオススメします。 また、このスタイルを守ると多くの Pythonista にとって読みやすいソースコードになるのではないでしょうか。

今回は分散バージョン管理システムgitと共に用いる「ブランチモデル」について紹介していただきます。gitを使ってみて、その高機能さをどう使えば良いか悩まれた方は、ぜひ本稿をご一読ください。gitそのものの使い方については解説していませんので、その際には『 実用git 』などの書籍を参考にしてください。

git-flow は Vincent Driessen 氏によって書かれた A successful Git branching model (O-Show 氏による日本語訳) というブランチモデルを補助するための git 拡張です。 git-flow を利用する前には、まずこの文章を一読することをおすすめします。 その骨子については、 Voluntas 氏のブログ が参考になります。

git を使うメリットの 1 つは、そのブランチモデルです。しかし gitを使っていると、その高い柔軟性から各開発者ごとにブランチが 分散 しがちであったり、最新バージョンが把握しにくいといった不便を感じることがあります。

このツールを導入することで、git の長所を損なわずに、

  • 分散型バージョンコントロールシステムである git に集中型 (Subversion 等) の長所を取り入れることができる
  • チーム内でブランチモデルを共通化できる

などの利点を得ることが可能です。

分散型に対する集中型の長所は、

  • リポジトリが 1 つのため、管理が簡単
  • マスターが 1 つのため、最新バージョンが把握しやすい
  • コミットすべきリポジトリがわかりやすい。

と言われています。これは、リポジトリが 1 箇所にあることの長所であり、短所です。 git-flow では、中央と みなす リポジトリ origin を作成することで、この長所を取り入れています。

centr-decentr.png

Git ブランチモデル( A successful Git branching model より。Creative Commons BY-SA ライセンス)

git-flow のブランチモデルを要約すると、

origin には master, develop という 2 つの メインブランチ を保持します。

  • master: リリースブランチ。プロダクトとしてリリースするためのブランチ。リリースしたらタグ付けする。集中型でいう trunk、tag。
  • develop: 開発ブランチ。コードが安定し、リリース準備ができたら master へマージする。リリース前はこのブランチが最新バージョンとなる。

各開発者は master, develop の他に、フィーチャーブランチ、リリースブランチ、ホットフィックスブランチという サポートブランチ を利用し分散開発します。このブランチは最終的には破棄されます。各ブランチの目的は

  • フィーチャーブランチ: 機能の追加。 develop から分岐し、 develop にマージする。
  • リリースブランチ: プロダクトリリースの準備。 機能の追加やマイナーなバグフィックスとは独立させることで、 リリース時に含めるコードを綺麗な状態に保つ(機能追加中で未使用のコードなどを含まないようにする)ことができる。 develop ブランチにリリース予定の機能やバグフィックスがほぼ反映した状態で develop から分岐する。 リリース準備が整ったら, master にマージし、タグをつける。次に develop にマージする。
  • ホットフィックスブランチ: リリース後のクリティカルなバグフィックスなど、 現在のプロダクトのバージョンに対する変更用。 master から分岐し、 master にマージし、タグをつける。次に develop にマージする。

となります。このサポートブランチにより、マージ、コミットすべきブランチを明確化することができます。

今回は、前回取り上げたsquashfs,aufs,cloop,dm-snapshotの各機能を用いた、LiveCDに必要な機能を実現するための組合せを考えてみます。 なお、本記事はhttp://sourceforge.net/mailarchive/forum.php?thread_name=20986.1293537718%40jrobl&forum_name=aufs-usersを元にしています。

方式ごとの性能比較

ここまで、squashfs,aufs,cloop,dm-snapshotの各機能を簡単に紹介しました。次にLiveCDに必要な機能を実現するための組合せを考えてみます。組合せ要素には圧縮された読み取り専用下位レイヤ、書き込み可能上位レイヤ、両レイヤの結合方法の三種類がありますが、前述のようにdm-snapshotの場合にはファイルシステム種類に条件が加わるため、次のようになります(表1)。

http://www.oreilly.co.jp/community/blog/images/union/pg_high_logo.png

Linuxをハードディスクへインストールせずに使用するLiveCD/DVDも広く利用されるようになり、多くのディストリビューションが従来のインストール媒体/方法に加え、LiveCDをリリースしています。ほとんどのLiveCDではsquashfs、tmpfs、更にAUFSを用い、ハードディスクへインストールしない形態を実現していますが、本記事ではその他の方法も取り上げ、考察します。 なお、本記事はhttp://sourceforge.net/mailarchive/forum.php?thread_name=20986.1293537718%40jrobl&forum_name=aufs-usersを元にしています。

古代の構成

一般的にLinux LiveCDではシステムをインストールした状態のファイルシステムを圧縮し、読み取り専用ファイルシステムイメージとして収納してあります。この際に用いられるのがsquashfsなどのファイルシステムですが、ここからそのままシステムを起動しても読み取り専用ですから、使用できない部分が生まれます。

圧縮の反対動作を指す言葉は伸長とも表現されますが、本記事では展開と表現します。

例えば、システムを起動すれば各種ログファイルや/var/wtmpファイルに対する書き込みが発生しますし、ファイルシステムをマウントすれば/etc/mtabというファイルも更新されます。デーモンが起動されればサービスに必要な各種ファイルなども作成されます。それぞれを一つづつ調査し、書き込みが発生しないように対処して行くことも不可能ではないかもしれませんが、もちろん手間がかかります。そもそもLinux(UNIX)システムは書き込み可能ファイルシステム上で動作することを前提としているのですから、この努力は有意義とは言えないでしょう。

かつてはシャドウディレクトリ方式で対応しようという時代もありました。シャドウディレクトリとはやや古い呼び方かもしれませんが、X.Org/XFree86以前のX11 Window Systemのビルドなどにも用いられていた(と思うけど、記憶に自信がなくなってきた )形態です。例えば、ソースファイルが置かれたsrc/下でそのままビルドすると、他のアーキテクチャ用にビルドする際には全オブジェクトファイルを削除しなければなりません。そうすると、先のアーキテクチャ用のリビルド時にはまた初めからすべてをコンパイルしなければならず、この手間暇を節約するための方策として、obj/を別に用意し、全てのソースファイルのシンボリックリンクをobj/下に作成する方法が採られました。この形態がシャドウディレクトリで、ビルドされるオブジェクトファイルはobj/下に作成され、ソースファイルを書く場合にもディレクトリの差異を気にする必要もありません。lndir(1)を用いると、子ディレクトリ、孫ディレクトリも含んだシャドウディレクトリを作成できます。

大量のリクエストを捌くWebサイトを構築するには、さまざまなノウハウがあります。例えばオライリーの書籍『ハイパフォーマンスWebサイト』では、クライアントに配信するコンテンツを最適化することでパフォーマンスの向上を図っています。今回は、Pythonを使って月間10億を超える(!)リクエストを捌いている、株式会社クロスリスティングの方に、そのノウハウの一部を寄稿していただきました。
また、本記事の内容はPython Hack-a-thon 2010.07でのプレゼンテーションを元にしています

自己紹介

現在、私はクロスリスティングという会社で、広告配信システムとか、その周辺の新規商品関連の研究開発をやっています。メインのプログラミング言語はPythonです。自社でのシステム開発は基本的に全てPythonを使っています。自分は研究開発的なポジションですが、技術チームが開発しているプロダクションシステムもほぼ100% Pythonで開発されています。

「Pythonはバイトコードインタプリタのランタイムで動作するので、(JITを含めて)ネイティブコードにコンパイルする言語に比べて、実効速度の点で不利でありハイトラフィックなWebサービスの実装言語として向かないのではないか」という話を良く聞きます。今回は、Pythonで構築されているWeb広告配信サーバと、その周辺ツールについて、すこし紹介できればと思っています。

2008年にリリースされたPython 3。さまざまな機能が追加、更新されている中に私たち日本人にとっては嬉しい機能が追加されています。今回はその機能を提案・設計したご本人に解説をご寄稿いただきました。
また、本記事の内容はPython Hack-a-thon 2010.07でのプレゼンテーションを元にしています

Python 2.x までのオブジェクト文字列表現

Pythonを使ってプログラムを開発していると、デバッグ中などにこんな感じの文字列をよく目にします。

>>> "abc\tdef"
'abc\tdef'
>>> datetime.datetime.now()
datetime.datetime(2010, 7, 9, 13, 37, 49, 107000)

"abc\tdef"datetime.datetime.now()という式を評価した結果が、'abc\tdef'datetime.datetime(2010, 7, 9, 13, 37, 49, 107000)のように表示されています。このような、Pythonの値をデバッグ用に読みやすく整形した文字列を「オブジェクトの文字列表現」と言います。

renamed_ebook.jpg

O'Reilly Japan Ebook Store」サイトのオープンからもうすぐ2年経過します。販売タイトルも、当初はわずか20タイトルほどだったのですが、現在では160タイトルほどになり、カタログに掲載されている書籍の半分弱くらいになっています。

ところでこのEbook、ご購入後にサイトからダウンロードしていただくと、ファイル名が「<16進数の羅列>-<書籍のISBN>.pdf」という形式になっています。もちろん変更はできるのですが、そのまま電子書籍リーダーなどに読み込むと、画面が英数字の羅列だらけになってしまいます。

かく言う私たちも、イベント出展にサンプルのEbookを持って行くことがあるのですが、イベント会場でISBNだけがズラ―っと並んだ画面をお見せするのをとても心苦しく思っていました。

以前は手作業でファイル名を変更していたのですが、100タイトルを超えた辺りで心が折れました。Amazon APIを使って書名を取得すればいいことは分かっていたのですが、発行元がそれをしてしまったら負けな気がします。

そこでWebサイトの書誌情報を以下のようなURLで取得できるように、テンプレートを1つ追加しました。ファイル名をご覧いただくと分かるように、簡単な書誌情報をJSON形式でご提供しています。

http://www.oreilly.co.jp/books/9784873114569/biblio.json

http://www.oreilly.co.jp/community/blog/images/union/pg_high_logo.png

前回はPOSIX AIOとLinuxカーネルのAIOサポートについて解説しました。今回は、このAIOの使い勝手を良くするため、POSIX AIOインタフェース準拠のライブラリを作成しています。

LinuxネイティブAIOライブラリliblaioの試作

Linux AIOを使用する場合、現在では前述のlibaioの利用が第一候補になりますが、やや使い勝手が悪いため、本記事でPOSIX AIOインタフェース準拠のライブラリを試作してみます。Linux AIOではO_DIRECTが前提となるため、この点もやや使い勝手が悪いのですが、SSDなどメモリベースのファイルシステムもありますし、動作は非同期になりませんがio_submit(2)O_DIRECTがなくとも使用可能ですから、まぁ試しにやってみましょう。

ライブラリ設計要点を挙げます。

Linux AIOにPOSIX AIOインタフェースをかぶせる

簡単に対応をとってみると表3の様になります。

表3 Linux AIOシステムコールとPOSIX AIOインタフェースの対応

POSIX AIOインタフェース Linux AIOシステムコール
aio_read io_submit
aio_write
aio_fsync
lio_listio
aio_suspend io_getevents
aio_return
aio_error
aio_cancel io_cancel

io_setup(2)などの前処理はライブラリ内で自動的に行いますが、プログラマが同時AIO数を拡張するなどの場合も考えられます。このため、Glibc拡張であるaio_init(3)を流用/対応すると同時に、laio_fin()も新設しio_destroy(2)に対応します。

アーカイブ