Perl mp2 翻訳 大規模 E コマースサイトの構築 (d224)

セラ (perlackline)

2022年06月15日 20:43

目次 - Perl Index


Theme



Perl について、復習を兼ねて断片的な情報を掲載して行く連載その d224 回。

今回は、mod_perl 「 Documentation / Tutorials / Part I: Application Design / Building a Large-Scale E-commerce site with Apache and mod_perl 」を翻訳して確認します。

正確な内容は 原文 を確認してください。誤解や誤訳がある場合はご指摘ください。



説明 : Description



mod_perl's speed and Perl's flexibility make them very attractive for large-scale sites. Through careful planning from the start, powerful application servers can be created for sites requiring excellent response times for dynamic content, such as eToys.com, all by using mod_perl.

mod_perl のスピードと Perl のフレキシビリティは大規模サイトをとても惹きつけます. スタートからの慎重な計画を通じて, 動的コンテンツのために優れたレスポンスタイムを要求するサイトのためのパワフルなアプリケーションサーバを作成することができます, eToys.com のように, すべてに mod_perl を使うことによって.
This paper was first presented at ApacheCon 2001 in Santa Clara, California, and was later published by O'Reilly & Associates' Perl.com site: http://perl.com/pub/a/2001/10/17/etoys.html

このペーパーはサンタクララでの ApacheCon 2001 で最初に発表され, 後に O'Reilly & Associates の Perl.com サイトで公開されました: http://perl.com/pub/a/2001/10/17/etoys.html


一般的な神話 : Common Myths



When it comes to building a large e-commerce web site, everyone is full of advice. Developers will tell you that only a site built in C++ or Java (depending on which they prefer) can scale up to handle heavy traffic. Application server vendors will insist that you need a packaged all-in-one solution for the software. Hardware vendors will tell you that you need the top-of-the-line mega-machines to run a large site. This is a story about how we built a large e-commerce site using mainly open source software and commodity hardware. We did it, and you can do it too.

大規模な e-コマース web サイトを構築するときには, 誰もがたくさんのアドバイスをします. 開発者はあなたに C++ や Java (彼らがどちらかを好むかによって) だけで構築したサイトはヘビーなトラフィックを処理するためにスケールアップできることを教えてくれます. アプリケーションサーバベンダはソフトウェア用にパッケージ化されたオールインワンソリューションをあなたは必要だと主張します. ハードウェアベンダはあなたが大規模サイトを走らせるためには最高級のメガマシンが必要だとあなたに伝えます. これは私たちが主にオープンソースソフトウェアとコモディティなハードウェアを使ってどのように大規模な e-コマースサイトを構築したかについての物語です. 私たちはそれをしました, そしてあなたもそれをできます.


Perl が救う : Perl Saves



Perl has long been the preferred language for developing CGI scripts. It combines supreme flexibility with rapid development. Programming Perl is still one of O'Reilly's top selling technical books, and community support abounds. Lately though, Perl has come under attack from certain quarters. Detractors claim that it's too slow for serious development work and that code written in Perl is too hard to maintain.

Perl は CGI スクリプトの開発のために長らく好まれた言語でした. それは迅速な開発で最高のフレキシビリティを兼ね備えています. Programming Perl は今でも O'Reilly のトップセールスの技術書のひとつであり, コミュニティサポートが豊富です. しかし最近, Perl は特定の方面から攻撃を受けています. 中傷する人たちはそれはシリアスな開発作業ではとても遅く Perl で書かれたコードは維持がとても難しいと主張します.
The mod_perl Apache module changes the whole performance picture for Perl. Embedding a Perl interpreter inside of Apache provides performance equivalent to Java servlets, and makes it an excellent choice for building large sites. Through the use of Perl's object-oriented features and some basic coding rules, you can build a set of code that is a pleasure to maintain, or at least no worse than other languages.

mod_perl Apache モジュールは Perl のパフォーマンス全体をチェンジします. Apache の内側に組み込まれた Perl インタープリタは Java サーブレットと同等のパフォーマンスを提供し, それは大規模なサイトを構築するための優れた選択にします. Perl のオブジェクト指向機能といくつかの基本的なコーディングルールの利用を通じて, あなたは維持が楽しい, あるいは少なくとも他の言語よりも悪くないコードセットを構築できます.


あなた独自のアプリケーションサーバをはじめる : Roll Your Own Application Server



When you combine Apache, mod_perl, and open source code available from CPAN (the Comprehensive Perl Archive Network), you get a set of features equivalent to a commercial application server:

あなたが Apache, mod_perl, それから CPAN (包括的な Perl アーカイブネットワーク) から利用可能なオープンソースコードを組み合わせると, あなたは商用アプリケーションサーバと同等の機能のセットをゲットできます:

You also get some things you won't get from a commercial product, like a direct line to the core development team through the appropriate mailing list, and the ability to fix problems yourself instead of waiting for a patch. Moreover, every part of the system is under your control, making you limited only by your team's abilities.

またあなたはあなたが商用プロダクトからはゲットできないいくつかのものをゲットします, 適切なメーリングリストを通じたコアの開発チームへのダイレクトライン (# 直通の連絡) や, パッチを待つ代わりにあなたが自身で問題を修正する能力などです. さらに, システムのすべての部分はあなたの制御下で, あなたのチームの能力によってのみあなたは制限されます.


ケーススタディ: eToys.com : Case Study: eToys.com



When we first arrived at eToys in 1999, we found a situation that is probably familiar to many who have joined a growing startup Internet company. The system was based on CGI scripts talking to a MySQL database. Static file serving and dynamic content generation were sharing resources on the same machines. The CGI code was largely written in a Perl4-ish style and not as modular as it could be, which was not surprising since most of it was built as quickly as possible by a very small team.

1999 年私たちが最初に eToys に到着したとき, 私たちは成長するスタートアップのインターネット企業に加わった多くの人たちにはおそらくお馴染みの光景を見ました. そのシステムは MySQL データベースと話しをする CGI スクリプトに基づいていました. 静的ファイルの提供と動的コンテンツの生成は同じマシンのリソースを共有していました. その CGI コードは Perl4 的なスタイルで大部分が書かれていてモジュール式ではありませんでしたが, そのほとんどはとても小さなチームによって可能な限り迅速に構築されたのでそれは驚くことではありませんでした.
Our major task was to figure out how to get this system to scale large enough to handle the expected Christmas traffic. The toy business is all about seasonality, and the difference between the peak selling season and the rest of the year is enormous. The site had barely survived the previous Christmas, and the MySQL database didn't look like it could scale much further.

私たちの主なタスクはどのようにしてこのシステムを予期されたクリスマスのトラフィックを処理するのに十分な大きさにスケールするかを見つけだすことでした. オモチャのビジネスはすべてが季節性で, ピーク売上のシーズンと 1 年の残りの間の違いは甚大です. このサイトは前のクリスマスをぎりぎりで乗り切っていて, その MySQL データベースはそれ以上スケールできるようには見えませんでした.
The call had already been made to switch to Oracle, and a DBA team was in place. We didn't have enough time to do a re-design of the software, so we had to scramble to put in place whatever performance improvements we could finish by Christmas.

Oracle への切り替えはすでに決定されていて, DBA (# DataBase Administrator) チームが配置されていました. 私たちはそのソフトウェアの再設計を行う十分な時間をもっていなかったので, 私たちは私たちがクリスマスに完了したいパフォーマンスの向上を実施するためにスクランブルする必要がありました.


救済のための Apache::PerlRun : Apache::PerlRun to Rescue



Apache::PerlRun is a module that exists to smooth the transition between basic CGI and mod_perl. It emulates a CGI environment, and provides some (but not all) of the performance benefits associated with code written for mod_perl. Using this module and the persistent database connections provided by Apache::DBI, we were able to do a basic port to mod_perl and Oracle in time for Christmas, and combined with some new hardware we were ready to face the Christmas rush.

Apache::PerlRun はベーシックな CGI と mod_perl 間の移行をスムーズにするために存在するモジュールです. それは CGI 環境をエミュレートして, mod_perl 用に書かれたコードに関連するパフォーマンスベネフィットのいくつか (全部ではありません) を提供します. このモジュールと Apache::DBI によって提供される永続的なデータベース接続を使って, 私たちはクリスマスのための mod_perl と Oracle への基本的な移植ができて, 私たちがクリスマスのラッシュに向き合うために準備したいくつかの新しいハードウェアと組み合わせました.
The peak traffic lasted for eight weeks, most of which were spent frantically fixing things or nervously waiting for something else to break. Nevertheless, we made it through. During that time we collected the following statistics:

ピークトラフィックは 8 週間続き, そのほとんどは物事を必死に修正したり他の何かが壊れないか心配して過ごしました. それでも, 私たちはそれをやり通しました. その間私たちは次の統計を収集しました:

According to Media Metrix, we were the third most heavily trafficked e-commerce site, right behind eBay and Amazon.

Media Metrix によれば, 私たちは 3 番目にヘビーなトラフィックの e-コマースサイトでした, eBay と Amazon に続いて.


新しいアーキテクチャを計画する : Planning the New Architecture



It was clear that we would need to do a re-design for 2000. We had reached the limits of the current system and needed to tackle some of the harder problems that we had been holding off on.

私たちは 2000 年のために再設計を行うことが必要なのは明らかでした. 私たちは現在のシステムのリミットにリーチして私たちが保留にしていたよりハードな問題に取り組まなければなりませんでした.
Goals for the new system included moving away from off-line page generation. The old system had been building HTML pages for every product and product category on the site in a batch job and dumping them out as static files. This was very effective when we had a small database of products since the static files gave such good performance, but we had recently added a children's bookstore to the site, which increased the size of our product database by an order of magnitude and made the time required to generate every page prohibitive. We needed a strategy that would only require us to build pages that customers were actually interested in and would still provide solid performance.

新しいシステムのゴールはオフラインページ生成から脱することを含んでいました. 古いシステムはサイト上のすべてのプロダクトとプロダクトカテゴリの HTML ページをバッチジョブと静的ファイルとしてそれらをダンプすることで構築していました. この方法は静的ファイルが良いパフォーマンスを与えるので私たちがプロダクトの小さなデータベースをもっているときにはとても効果的でしたが, 私たちは最近子供用の書店をサイトに追加し, それは私たちのプロダクトデータベースのサイズを桁違いに増加してすべてのページの生成で法外な時間を要することになりました. 私たちは顧客が実際に興味を持って私たちに要求したページだけを構築してかつソリッド (# 頑丈, 硬い, 確かな) なパフォーマンスを提供し続けられる戦略が必要でした.
We also wanted to re-do the database schema for more flexibility, and structure the code in a more modular way that would make it easier for a team to share the development work without stepping on each other. We knew that the new codebase would have to be flexible enough to support a continuously evolving set of features.

また私たちはより多くのフレキシビリティのためのデータベーススキーマの再実行と, 開発作業をチームが互いに踏みつけ合うことなく簡単に共有をできるようにもっとモジュール方式でコードを構造化したいと思っていました. 私たちは新しいコードベースが継続的に進化する機能のセットをサポートするために十分にフレキシブルでなければならないことを知っていました.
Not all of the team had significant experience with object-oriented Perl, so we brought in Randal Schwartz and Damian Conway to do training sessions with us. We created a set of coding standards, drafted a design, and built our system.

チームの全員がオブジェクト指向 Perl での重要な経験をもっているわけではなかったので, 私たちは私たちにトレーニングセッションをするために Randal Schwartz と Damina Conway を招きました. 私たちはコーディング標準のセットを作成し, 設計を草稿して, それから私たちのシステムを構築しました.


クリスマス 2000 を乗り切る : Surviving Christmas 2000



Our capacity planning was for three times the traffic of the previous peak. That's what we tested to, and that's about what we got:

私たちのキャパシティプランは前回のピークトラフィックの 3 倍でした. それは私たちがテストしたもので, それについて私たちはこれをゲットしました:

The software survived, although one of the routers went up in smoke. Once again, we were rated the third most highly trafficked e-commerce site for the season.

そのソフトウェアはサバイブしました, しかしながらルータのひとつが駄目になりました. もう一度繰り返します, 私たちはそのシーズンで 3 番目にトラフィックが高い e コマースサイトと評価されました.


アーキテクチャ : The Architecture



The machine strategy for the system is a fairly common one: low-cost Intel-based servers with a load-balancer in front of them, and big iron for the database.

システムのためのマシン戦略はかなり一般的なものです: 低コストのインテルベースのサーバとそのフロントのロードバランサ, それからデータベースのための高価な高速マシン.

Figure1. Serverlayout

The Architecture
Like many commercial packages, we have separate systems for the front-end web servers (which we call proxy servers) and the application servers that generate the dynamic content. Both the proxy servers and the application servers are load-balanced using dedicated hardware from f5 Networks.

多くの商用パッケージと同様に, 私たちはフロントエンド web サーバ (それを私たちはプロキシサーバと呼びます) と動的コンテンツを生成するアプリケーションサーバのために分割したシステムをもっています. プロキシサーバとアプリケーションサーバは両方とも f5 ネットワークス (# ロードバランサ等を開発・販売する企業) からの専用のハードウェアを使ってロードバランス (# 負荷分散) されます.
We chose to run Linux on our proxy and application servers, a common platform for mod_perl sites. The ease of remote administration under Linux made the clustered approach possible. Linux also provided solid security features and automated build capabilities to help with adding new servers.

私たちは私たちのプロキシとアプリケーションサーバで Linux を実行することを選択しました, mod_perl サイトのための一般的なプラットフォームです. Linux のもとでのリモート管理の容易さはクラスタ化されたアプローチを可能にしました. また Linux はソリッドなセキュリティ機能と新しいサーバの追加を助ける自動化されたビルド能力も提供していました.
The database servers were IBM NUMA-Q machines, which ran on the DYNIX/ptx operating system..

データベースサーバは IBM NUMA-Q マシンで, それは DYNIX/ptx オペレーティングシステム上で走りました..


プロキシサーバ : Proxy Servers



The proxy servers ran a slim build of Apache, without mod_perl. They have several standard Apache modules installed, in addition to our own customized version of mod_session, which assigned session cookies. Because the processes were so small, we could run up to 400 Apache children per machine. These servers handled all image requests themselves, and passed page requests on to the application servers. They communicated with the app servers using standard HTTP requests, and cached the page results when appropriate headers are sent from the app servers. The cached pages were stored on a shared NFS partition of a Network Appliance filer. Serving pages from the cache was nearly as fast as serving static files.

プロキシサーバは Apache のスリムビルドを実行しました, mod_perl はなしです. それらはいくつかスタンダードな Apache モジュールがインストールされていて, 私たちは独自にカスタマイズした mod_session のバージョンを加えました, それはセッションクッキーが割り当てられます. プロセスはとても小さかったので, 私たちはマシンごとに 400 の Apache child たちを走らせることができました. これらのサーバはそれ自身ですべてのイメージリクエストを処理し, ページリクエストはアプリケーションサーバに渡しました. それらはスタンダードの HTTP リクエストを使って app サーバと通信し, 適切なヘッダが app サーバから送信されたときにそのページの結果をキャッシュしました. そのキャッシュされたページは Network Appliance filer (# ネットワーク器機) の共有された NFS (# Network File System) パーティションに格納されました. そのキャッシュからのページサーブは静的ファイルのサーブとほとんど同じ速さでした.
This kind of reverse-proxy setup is a commonly recommended approach when working with mod_perl, since it uses the lightweight proxy processes to send out the content to clients (who may be on slow connections) and frees the resource-intensive mod_perl processes to move on to the next request. For more information on why this configuration is helpful, see the strategy section in the users guide.

この種のリバースプロキシのセットアップは mod_perl で仕事をするときに一般的に推奨されるアプローチです, クライアント (その人は遅い接続かもしれません) へのコンテンツの送信に軽量なプロキシプロセスを使ってリソースインテンシブ (# リソースをたくさん使う) な mod_perl プロセスをフリーにして次のリクエストに移動するからです. なぜこの構成が役立つかの詳細は, ユーザガイドの戦略セクション (# 注: mod_perl 1.0) を参照してください.

Figure2. Proxy Server Setup
Proxy Servers


アプリケーションサーバ : Application Servers



The application servers ran mod_perl, and very little else. They had a local cache for Perl objects, using Berkeley DB. The web applications ran there, and shared resources like HTML templates were mounted over NFS from the NetApp filer. Because they did the heavy lifting in this setup, these machines were somewhat beefy, with dual CPUs and 1GB of RAM each.

Application サーバは mod_perl を実行して, その他はほとんど何もしませんでした. それらは Berkeley DB を使って, Perl オブジェクトのローカルキャッシュを持っていました. web アプリケーションはそこで実行され, HTML テンプレートのような共有リソースは NetApp filer から NFS 経由でマウントされました. このセットアップではヘビーな作業をしたので, それらはそれぞれデュアル CPU と 1GB の RAM で, ややたくましいマシンでした.

Figure3. Application servers layout
Application Servers


検索サーバ : Search servers



There was a third set of machines dedicated to handling searches. Since searching was such a large percentage of overall traffic, it was worthwhile to dedicate resources to it and take the load off the application servers and database.

専用で検索を処理するための 3 番目のマシンのセットがありました. 検索はトラフィック全体でとても大きな割合だったので, それにリソースを割いてアプリケーションサーバとデータベースの負荷を軽減することは価値がありました.
The software on these boxes was a multi-threaded daemon which we developed in-house using C++. The application servers talked to the search servers using a Perl module. The search daemon accepted a set of search conditions and returned a sorted list of object IDs of the products whose data fits those conditions. Then the application servers looked up the data to display these products from the database. The search servers knew nothing about HTML or the web interface.

これらのボックスのソフトウェアはマルチスレッドデーモンでそれは私たちが C++ を使って社内で開発しました. アプリケーションサーバは Perl モジュールを使ってこの検索サーバと話しをしました. 検索デーモンは検索条件のセットを受け付けてそれらの条件にフィットしたデータのプロダクトのオブジェクト ID をソートしたリストで返しました. それからアプリケーションサーバはそれらのプロダクトを表示するためにそのデータをデータベースから探しました. 検索サーバは HTML や web インターフェイスについては何も知りませんでした.
This approach of finding the IDs with the search server and then retrieving the object data may sound like a performance hit, but in practice the object data usually came from the application server's cache rather than the database. This design allowed us to minimize the duplicated data between the database and the search servers, making it easier and faster to refresh the index. It also let us reuse the same Perl code for retrieving product objects from the database, regardless of how they were found.

この検索サーバで ID を見つけてオブジェクトデータを取得するアプローチはパフォーマンスヒット (# 悪影響) するように聞こえるかもしれませんが, 実際にはオブジェクトデータは通常データベースではなくアプリケーションサーバのキャッシュから来ました. この設計は私たちにデータベースと検索サーバの間の重複データの最小化を可能にし, そのインデクスのリフレッシュを簡単かつ高速にしました. それはまた私たちにデータベースからのプロダクトオブジェクトの取得で同じ Perl コードを再利用できるようにしました, どのようにしてそれが見つかったに関係になくです.
The daemon used a standard inverted word list approach to searching. The index was periodically built from the relevant data in Oracle. There are modules on CPAN which implement this approach, including Search::InvertedIndex and DBIx::FullTextSearch. We chose to write our own because of the very tight performance requirements on this part of the system, and because we had an unusually complex set of sorting rules for the returned IDs.

デーモンは検索のために標準の逆単語 (# 倒語, inverted word) リストアプローチを使いました. インデクスは Oracle の関連データから定期的にビルドされました. Search::InvertedIndex と DBIx::FullTextSearch を含む, このアプローチを実装したモジュールが CPAN にあります. システムのこのパートはとてもタイトなパフォーマンス要求でしたし, 私たちはリターンされた ID の異常に複雑な並べ替えルールをもっていたので私たちは私たち独自に書くことを選択しました.

Figure4. Search servers layout

Search Servers


ロードバランシングとフェイルオーバー : Load Balancing and Failover



We took pains to make sure that we would be able to provide load balancing among nodes of the cluster and fault tolerance in case one or more nodes failed. The proxy servers were balanced using a random selection algorithm. A user could end up on a different one on every request. These servers didn't hold any state information, so the goal was just to distribute the load evenly.

私たちは複数のノードがフェイル (# 機能不全) したケースでロードバランシングとフォールトトレランス (# 障害耐性) を私たちが提供可能とすることに苦労しました. プロキシサーバはランダムセレクションアルゴリズムを使ってバランスしました. ユーザはリクエストごとに違うもの (# プロキシサーバ) になったはずです. これらのサーバは状態の情報を保持していなかったのでその目標は負荷を均等に分散するだけでした.
The application servers used ``sticky'' load balancing. That means that once a user went to a particular app server, all of her subsequent requests during that session were also passed to the same app server. The f5 hardware accomplished this using browser cookies. Using sticky load balancing on the app servers allowed us to do some local caching of user data.

アプリケーションサーバは ``スティッキー'' (# 貼りつく) なロードバランシングを使いました. それはユーザが特定のアプリケーションサーバに行くと, そのセッション中の彼女の連続したリクエストも同じ app サーバに渡されることを意味します. f5 ハードウェアはこれをブラウザのクッキーを使って成しました. app サーバでのスティッキーロードバランシングの使用で私たちはユーザデータを一部ローカルキャッシングできるようになりました.
The load balancers ran a periodic service check on every server and removed any servers that failed the check from rotation. When a server failed, all users that were ``stuck''; to that machine were moved to another one.

このロードバランサーは全てのサーバで定期的なサービスチェックを実行してそのチェックがフェイルしたサーバをローテションから削除しました. サーバがフェイルしたとき, そのマシンへの ``スタック'' した全てのユーザ; はその他のマシンに移動されました.
In order to ensure that no data was lost if an app server died, all updates were written to the database. As a result, user data like the contents of a shopping cart was preserved even in cases of catastrophic hardware failure on an app server. This is essential for a large e-commerce site.

app サーバが die してもデータがロストしないことを確実にするために, 全ての更新はデータベースに書込まれました. 結果として, ショッピングカートのコンテンツのようなユーザデータは app サーバの壊滅的なハードウェアフェイルのケースでさえ保護されました. これは大規模な e-コマースサイトでは不可欠です.
The database had a separate failover system, which we will not go into here. It followed standard practices recommended by our vendors.

データベースは別のフェイルオーバー (# 機能不全時に冗長系に切り替える) システムを持っていましたが, 私たちはここでは立ち入りません. 私たちのベンダーによって推奨された標準的なプラクティスに従いました.


コードの構造 : Code Structure



The code was structured around the classic Model-View-Controller pattern, originally from SmallTalk and now often applied to web applications. The MVC pattern is a way of splitting an application's responsibilities into three distinct layers.

コードはクラシックな Model-View-Controller (# モデル-ビュー-コントローラ) パターンで構築されました, 元々は SmallTalk (# オブジェクト指向の言語) からのもので今では web アプリケーションによく適用されます. この MVC パターンはアプリケーションの責任を 3 つの異なるレイヤに分割する方法です.
Classes in the Model layer represented business concepts and data, like products or users. These had an API but no end-user interface. They knew nothing about HTTP or HTML and could be used in non-web applications, like cron jobs. They talked to the database and other data sources, and managed their own persistence.

Model レイヤのクラスはプロダクトやユーザのような, ビジネスコンセプトとデータを表現しました. これらは API を持ちましたがエンドユーザのインターフェイスはありませんでした. それらは HTTP や HTML について何も知らず cron ジョブのような, 非 web アプリケーションで使われました. それらはデータベースや他のデータソースと話しをして, それら独自の永続性を管理しました.
The Controller layer translated web requests into appropriate actions on the Model layer. It handled parsing parameters, checking input, fetching the appropriate Model objects, and calling methods on them. Then it determined the appropriate View to use and send the resulting HTML to the user.

Controller レイヤは web リクエストをモデルレイヤ上での適切なアクションに変換しました. パラメータの解析, 入力のチェック, 適切な Model オブジェクトの取得, およびそれらのメソッドのコールを処理しました. それから使用する適切な View を決定しユーザにその結果の HTML を送信しました.
View objects were really HTML templates. The Controller passed data from the Model objects to them and they generated a web page. These were implemented with the Template Toolkit, a powerful templating system written in Perl. The templates had some basic conditional statements and looping in them, but only enough to express the formatting logic. No application control flow was embedded in the templates.

View オブジェクトは実際は HTML テンプレートでした. Controller が Model オブジェクトからのデータをそれら (# View ) に渡してそれらは web ページを生成しました. これらは Template Toolkit で実装されました, Perl で書かれたパワフルなテンプレートシステムです. そのテンプレートはその中にいくつかのベーシックな条件ステートメントとループをもっているだけでしたが, フォーマットロジックを表現するには十分でした. このテンプレートにはアプリケーション制御フローは組み込まれていませんでした.

Figure5. Code Structure and interaction between the layers

Code Structure


キャッシュ : Caching



The core of the performance strategy is a multi-tier caching system. On the application servers, data objects are cached in shared memory with a backing store on local disk. Applications specify how long a data object can be out of sync with the database, and all future accesses during that time are served from the high-speed cache. This type of cache control is known as "time-to-live." The local cache is implemented using a Berkeley DB database. Objects are serialized with the standard Storable module from CPAN.

パフォーマンス戦略のコアは多層 (# マルチティア) キャッシングシステムです. アプリケーションサーバで, データオブジェクトはローカルディスク上のバッキングストア (# 補助記憶) で共有メモリにキャッシュされます. アプリケーションはデータオブジェクトがデータベースとどのくらいの同期しないかを指定し, その時間中の未来のすべてのアクセスはその高速キャッシュサーブされます. このキャッシュコントロールのタイプは "time-to-live" (# TTL, 生存時間) として知られています. このローカルキャッシュは Berkeley DB データベースを使って実装されました. オブジェクトは CPAN で標準的な Storable モジュールをでシリアライズ (# 直列化) されました.
Data objects are divided into pieces when necessary to provide finer granularity for expiration times. For example, product inventory is updated more frequently than other product data. By splitting the product data up, we can use a short expiration for inventory that keeps it in tighter sync with the database, while still using a longer expiration for the less volatile parts of the product data.

データオブジェクトは有効期限の細かな粒度のために必要に応じて断片に分けられます. 例えば, プロダクトの在庫は他のプロダクトデータよりも頻繁にアップデートされます. プロダクトデータを分割することで, 私たちはデータベースと在庫のよりタイトな同期を維持するために短い有効期限を使えますし, 一方で変化が少ない残りのプロダクトデータには長い有効期限を使ったままにしておけます.
The application servers' object caches share product data between them using the IP Multicast protocol and custom daemons written in C. When a product is placed in the cache on one server, the data is replicated to the cache on all other servers. This technique is very successful because of the high locality of access in product data. During the 2000 Christmas season this cache achieved a 99% hit ratio, thus taking a large amount of work off the database.

アプリケーションサーバたちのオブジェクトキャッシュは IP マルチキャストプロトコルと C で書かれたカスタムデーモンを使ってそれらの間のプロダクトデータを共有します. プロダクトがひとつのサーバ上のキャッシュにおかれたとき, そのデータは他のすべてのサーバ上のキャッシュに複製されます. このテクニックはプロダクトデータへのアクセスで高い局所性があるためとてもうまくいきました。2000 年のクリスマスシーズンの間このキャッシュは 99% のヒット率を達成し, データベースの大部分の仕事を取り除きました.
In addition to caching the data objects, entire pages that are not user-specific, like product detail pages, can be cached. The application takes the shortest expiration time of the data objects used in the pages and specifies that to the proxy servers as a page expiration time, using standard Expires headers. The proxy servers cache the generated page on a shared NFS partition. Pages served from this cache have performance close to that of static pages.

データオブジェクトのキャッシングに加えて, プロダクトの詳細ページのような, ユーザ固有でないページ全体を, キャッシュできました. このアプリケーションはそのページで使われるデータオブジェクトのより短い有効期限を取り標準の Expires ヘッダを使って, ページの有効期限としてプロキシサーバを指定します. そのプロキシサーバは共有された NFS パーティション上でその生成されたページをキャッシュします. このキャッシュからのページサーブ (# 提供) はその静的ページに近いパフォーマンスをもちます.
To allow for emergency fixes, we added a hook to mod_proxy that deletes the cached copy of a specified URL. This was used when a page needed to be changed immediately to fix incorrect information.

緊急のフィックスを可能にするために, 私たちは指定された URL のキャッシュされたコピーを削除するフックを mod_proxy に追加しました. これは正しくない情報をフィックスするためにページをすぐに変更する必要があるときに使われました.
An extra advantage of this mod_proxy cache is the automatic handling of If-Modified-Since requests. We did not need to implement this ourselves since mod_proxy already provides it.

この mod_proxy キャッシュの追加のアドバンテージは If-Modified-Since リクエストの自動的な処理です. mod_proxy はすでにそれを提供しているので私たちはこれを私たち自身で実装する必要はありませんでした.

Figure6. Proxy and Cache Interaction
Caching


セッショントラッキング : Session Tracking



Users are assigned session IDs using HTTP cookies. This is done at the proxy servers by our customized version of mod_session. Doing it at the proxy ensures that users accessing cached pages will still get a session ID assigned. The session ID is simply a key into data stored on the server-side. User sessions are assigned to an application server and continue to use that server unless it becomes unavailable. This is called ``sticky” load balancing. Session data and other data modified by the user -- such as shopping cart contents -- is written to both the object cache and the database. The double write carries a slight performance penalty, but it allows for fast read access on subsequent requests without going back to the database. If a server failure causes a user to be moved to a different application server, the data is simply fetched from the database again.

ユーザは HTTP クッキーを使ってセッション ID が割り当てられました. これは私たちがカスタマイズしたバージョンの mod_session によってプロキシサーバで行われます. プロキシでこれを行ってキャッシュされたページにアクセスするユーザが割り当てられたセッション ID をゲットしたままにします. そのセッション ID はサーバサイドで格納されたデータへの単純なキーです. ユーザセッションはアプリケーションサーバに割り当てられてそのサーバが利用可能できなくならない限りは引き続きそれを使います. これは ``スティッキー'' ロードバランシングと呼ばれます. セッションデータとユーザによって変更された他のデータ - ショッピングカートのコンテンツのような - はオブジェクトキャッシュとデータベースの両方に書込まれます. この二重書込みはわずかなパフォーマンスペナルティをもたらしますが, それは後のリクエストでデータベースに戻ることのない高速な読み込みアクセスを可能にします. 仮にサーバの障害が発生しユーザが異なるアプリケーションサーバに移動する場合、そのデータはシンプルにデータベースから再取得されます.

Figure7. Session tracking and caches
Session Tracking


セキュリティ : Security



A large e-commerce site is a popular target for all types of attacks. When designing such a system, you have to assume that you will be attacked and build with security in mind, at the application level as well as the machine level.

大規模な e コマースサイトはあらゆるタイプのアタック (# 攻撃) のポピュラーなターゲットです. そのようなシステムを設計するとき, あなたはあなたがアタックされることを想定してマシンレベルとアプリケーションレベルで, セキュリティを念頭においた構築をあなたはしなければなりません.
The main rule of thumb is ``don't trust the client!'' User-specific data sent to the client is protected using multiple levels of encryption. SSL keeps sensitive data exchanges private from anyone snooping on network traffic. To prevent ``session hijacking'' (when someone tampers with their session ID in order to gain access to another user's session), we include a Message Authentication Code (MAC) as part of the session cookie. This is generated using the standard Digest::SHA1 module from CPAN, with a seed phrase known only to our servers. By running the ID from the session cookie through this MAC algorithm we can verify that the data being presented was generated by us and not tampered with.

主な経験則は ``そのクライアントを信頼するな !" でクライアントに送信されるユーザ固有のデータは複数レベルの暗号化をつかって保護されます. SSL はネットワークトラフィック上で覗き見する人からセンシティブなデータ交換をプライベートに維持します. ``セッションハイジャック" (別のユーザのセッションへのアクセスをえるために誰かがセッション ID を改竄すること) を防止するために, 私たちはメッセージ認証コード (Message Authentication Code: MAC) をセッションクッキーの一部として含めました. これは CPAN で標準の Digest::SHA1 モジュールを使って, 私たちのサーバだけが知っているシードフレーズで生成されます. この MAC アルゴリズムを介したセッションクッキーからの ID を実行することで私たちはその表示されるデータが私たちによって生成されて改竄されていないことの確認ができます.
In situations where we need to include some state information in an HTML form or URL and don't want it to be obvious to the user, we use the CPAN Crypt:: modules to encrypt and decrypt it. The Crypt::CBC module is a good place to start.

私たちは HTML フォームや URL に何らかの状態情報を含める必要があるがユーザには見せたくないシチュエーションで, 私たちはそれを暗号化と復号化をするために CPAN の Crypt:: モジュールを 使います. Crypt::CBC モジュールはスタートするにはグッドな場所です.
To protect against simple overload attacks, when someone uses a program to send high volumes of requests at our servers hoping to make them unavailable to customers, access to the application servers is controlled by a throttling program. The code is based on some work by Randal Schwartz in his Stonehenge::Throttle module. Accesses for each user are tracked in compact logs written to an NFS partition. The program enforces limits on how many requests a user can make within a certain period of time.

シンプルな過負荷アタックから保護するために, 誰かが私たちのサーバで顧客がそれらを利用できないようにするためにハイボリュームのリクエストを送信するプログラムを使ったとき, アプリケーションサーバへのアクセスはスロットリングプログラムによってコントロールされます. そのコードは Randal Schwartz の Stonehenge::Throttle モジュールでの彼のいくつかの仕事に基づいていました. 各ユーザのアクセスは NFS パーティションに書込まれるコンパクトなログでトラックされます. このプログラムはユーザが一定期間でどれくらいのリクエストできるかの制限を実施します.
For more information on web security concerns including the use of MAC, encryption, and overload prevention, we recommend looking at the books CGI Programming with Perl, 2nd Edition and Writing Apache Modules with Perl and C, both from O'Reilly.

MAC (# メッセージ認証コード) の利用, 暗号化, それから過負荷の防止など web セキュリティの懸念を含む詳細情報について, 私たちは書籍 CGI Programming with Perl 第二版, と Writing Apache Modules with Perl and C を参照することをお勧めします, どちらも O'Reilly です.


例外処理 : Exception Handling



When planning this system, we considered using Java as the implementation language. We decided to go with Perl, but we really missed Java's nice exception handling features. Luckily, Graham Barr's Error module from CPAN supplies similar capabilities in Perl.

このシステムを計画しているときに, 私たちは実装言語として Java を検討しました. 私たちは Perl で行くことに決めましたが, 私たちは Java のナイスな例外処理機能を本当に恋しく思いました. 幸い, CPAN からの Graham Barr の Erro モジュールは Perl で同様の機能を提供しています.
Perl already has support for trapping runtime errors and passing exception objects, but the Error module adds some nice syntactic sugar. The following code sample is typical of how we used the module:

Perl はランタイムのエラーのトラップ (# 補足) と例外オブジェクトの受け渡しをすでにサポートしていましたが, その Erro モジュールはいくつかのナイスな糖衣構文 (# syntactic sugar, 簡易な構文) を追加します. 次のコードサンプルは私たちがそのモジュールを使う典型的なやりかたです:

try {
do_some_stuff();
} catch My::Exception with {
my $E = shift;
handle_exception($E);
};

The module allows you to create your own exception classes and trap for specific types of exceptions.

このモジュールはあなた独自の例外クラスの作成と例外の特定のタイプのトラップをあなたができるようにします.
One nice benefit of this is the way it works with DBI. If you turn on DBI's RaiseError flag and use try blocks in places where you want to trap exceptions, the Error module can turn DBI errors into simple Error objects.

このナイスな利点の 1 つはこれが DBI と連携する方法です. もしあなたが DBI の RaiseError フラグを on にしてあなたが例外をトラップした場所で try ブロックを使うと, この Error モジュールは DBI エラーをシンプルな Error オブジェクトにできます.

try {
$sth->execute();
} catch Error with {
# roll back and recover
$dbh->rollback();
# etc.
};

This code shows a condition where an error would indicate that we should roll back a database transaction. In practice, most DBI errors indicate something unexpected happened with the database and the current action can't continue. Those exceptions are allowed to propagate up to a top-level try{} block that encloses the whole request. When errors are caught there, we log a stacktrace and send a friendly error page back to the user.

このコードはエラーの場所で私たちがデータベーストランザクションをロールバックすべき条件を示します. 実際には, ほとんどの DBI エラーはデータベースで予期しない何かが発生したことを示し現在のアクションを継続することができません. これらの例外はリクエスト全体を囲むトップレベルの try{} ブロックまで伝えることが可能です. そこでエラーがキャッチされると, 私たちはスタックトレースを記録してユーザにフレンドリーなエラーページを送り返します.


テンプレート : Tempates



Both the HTML and the formatting logic for merging application data into it is stored in the templates. They use a CPAN module called Template Toolkit, which provides a simple but powerful syntax for accessing the Perl data structures passed to them by the application. In addition to basics like looping and conditional statements, it provides extensive support for modularization, allowing the use of includes and macros to simplify template maintenance and avoid redundancy.

HTML とそれにアプリケーションデータをマージするフォーマットロジックは両方ともテンプレートに格納されます. それらは Template Toolkit と呼ばれる CPAN モジュールを使います, それはアプリケーションによってそれらに渡された Perl データ構造にアクセスするためのシンプルですがパワフルな構文を提供します. 基本的なループや条件文に加えて, モジュール化のための幅広いサポートを提供し, テンプレートメンテナンスを簡単にするためのインクルードとマクロの利用で冗長性を回避できるようにします.
We found Template Toolkit to be an invaluable tool on this project. Our HTML coders picked it up very quickly and were able to do nearly all of the templating work without help from the Perl coders. We supplied them with documentation of what data would be passed to each template and they did the rest. If you have never experienced the joy of telling a project manager that the HTML team can handle his requested changes without any help from you, you are seriously missing out!

私たちはこのプロジェクトで Template Toolkit が貴重なツールになることを発見しました. 私たちの HTML コーダーたちは迅速にこれをピックアップして Perl コーダーたちからのヘルプなしにほとんどすべてのテンプレート作業を行うことができました. 私たちは彼らに各テンプレートに何のデータが渡されるのドキュメントを提供し残りは彼らが行いました. もしあなたが HTML チームがあなたのヘルプ無しに彼が要求された変更を処理できることをプロジェクトマネージャに伝える喜びを経験したことがないなら, 本当にもったいないですよ !
Template Toolkit compiles templates into Perl bytecode and caches them in memory to improve efficiency. When template files change on disk they are picked up and re-compiled. This is similar to how other mod_perl systems like Mason and Apache::Registry work.

Template Toolkit はテンプレートを Perl バイトコードにコンパイルして効率向上のためにそれらをメモリにキャッシュします. ディスク上でテンプレートファイルを変更したときそれらはピックアップされて再コンパイルされます. これは Mason や Apache::Registry のような他の mod_perl システムの作業に似ています.
By varying the template search path, we made it possible to assign templates to particular sections of the site, allowing a customized look and feel for specific areas. For example, the page header template in the bookstore section of the site can be different from the one in the video game store section. It is even possible to serve the same data with a different appearance in different parts of the site, allowing for co-branding of content.

テンプレートの検索パスを変えることで, 私たちはサイトの詳細なセクションにテンプレートを割り当てることが可能になり, 特定のエリアのルックアンドフィールのカスタマイズができるようになりました. 例えば, このサイトのブックストアセクションでのページヘッダテンプレートはビデオゲームストアセクションでのそれとは異なるかもしれません. それはこのサイトの異なるパートでの異なる外観で同じデータをサーブすることさえ可能で, コンテンツの協調ブランディングが可能になります.
This is a sample of what a basic loop looks like when coded in Template Toolkit:

これは Template Toolkit でコード化したときのような基本的なループのサンプルです:

[% FOREACH item = cart.items %]
name: [% item.name %]
price: [% item.price %]
[% END %]



コントローラの例 : Controller Example



Let's walk through a simple Hello World example that illustrates how the Model-View-Controller pattern is used in our code. We'll start with the controller code.

それでは Model-View-Controller パターンが私たちのコードでどのように使われているのかを示すシンプルな Hello World の例を歩んでみましょう. 私たちは Controller コードでスタートします.

package EFS::Control::Hello;
use strict;
use EFS::Control;
@ESF::Control::Hello::ISA = qw(ESF::Control);
use ESF::Util;
sub handler {
### いくつかのセットアップ作業を行う
### do some setup work
my $class = shift;
my $apr = ESF::Util->get_request();

### Model をインスタンス化
### instantiate the model
my $name = $apr->param('name');

# 私たちは新しい Model::Hello オブジェクトを作成する
# we create a new Model::Hello object.
my $hello = ESF::Model::Hello->new(NAME => $name);

### View を送信
### send out the view
my $view_data{'hello'} = $hello->view();

# process_template() メソッドは
# ESF::Control ベースクラスから継承される
# the process_template() method is inherited
# from the ESF::Control base class
$class->process_template(
TEMPLATE => 'hello.html',
DATA => \%view_data);
}

In addition to the things you see here, there are a few interesting details about the ESF::Control base class. All requests are dispatched to the ESF::Control->run() method first, which wraps them in a try{} block before calling the appropriate handler() method. It also provides the process_template() method, which runs Template Toolkit and then sends out the results with appropriate HTTP headers. If the Controller specifies it, the headers can include Last-Modified and Expires, for control of page caching by the proxy servers.

ここであなたが見るものに加えて, ESF::Control ベースクラスについてのいくつか興味深い詳細があります. すべてのリクエストは最初に ESF::Control->run() メソッドにディスパッチ (# 渡す) され, 適切な handler() メソッドをコールする前に try{} でそれをラップします. それはまた process_template() メソッドも提供し, Template Toolkit を実行してから適切な HTTP ヘッダでその結果を送信します. もしそれを Controller が指定した場合, そのヘッダは Last-Modified と Expire を含めることができます, プロキシサーバによってページキャッシュのコントロールをするためです.
Now let's look at the corresponding Model code.

それでは対応する Model のコードを見てみましょう.

package ESF::Model::Hello;
use strict;
sub new {
my $class = shift;
my %args = @_;
my $self = bless {}, $class;
$self{'name'} = $args{'NAME'} || 'World';
return $self;
}

sub view {
# オブジェクト自体が View で機能する
# the object itself will work for the view
return shift;
}

This is a very simple Model object. Most Model objects would have some database and cache interaction. They would include a load() method which accepts an ID and loads the appropriate object state from the database. Model objects that can be modified by the application would also include a save() method.

これはとてもシンプルなモデルオブジェクトです. 大抵のモデルオブジェクトは何らかのデータベースとキャッシュのインタラクション (# 相互作用) をもっています. それらは ID を受け取りデータベースから適切なオブジェクトの状態をロードする load() メソッドを含みます. アプリケーションによって変更されうる Model オブジェクトは save() メソッドも含むはずです.
Note that because of Perl's flexible OO style, it is not necessary to call new() when loading an object from the database. The load() and new() methods can both be constructors for use in different circumstances, both returning a blessed reference.

Perl のフレキシブルな OO (# Object Oriented, オブジェクト指向) スタイルにより, データベースからオブジェクトをロードするときに必ずしも new() をコールしなくてもよいことに留意してください. load() と new() メソッドはどちらもさまざまな状況で使うためのコンストラクタで, どちらも bless されたリファレンスをリターンします.
The load() method typically handles cache management as well as database access. Here's some pseudo-code showing a typical load() method:

典型的に load() メソッドはデータベースアクセスと同様にキャッシュマネージメントを処理します. こちらは典型的な load() メソッドをお見せするいくつかの疑似コードです:

sub load {
my $class = shift;
my %args = @_;
my $id = $args{'ID'};
my $self;
unless ($self = _fetch_from_cache($id)) {
$self = _fetch_from_databese($id);
$self->_store_in_cache();
}
return $self;
}

The save method would use the same approach in reverse, saving first to the cache and then to the database.

save メソッドは逆順で同じアプローチを使います, 最初にキャッシュそれからデータベースに保存します.
One final thing to notice about our Model class is the view() method. This method exists to give the object an opportunity to shuffle it's data around or create a separate data structure that is easier for use with a template. This can be used to hide a complex implementation from the template coders. For example, remember the partitioning of the product inventory data that we did to allow for separate cache expiration times? The product Model object is really a façade for several underlying implementation objects, but the view() method on that class consolidates the data for use by the templates.

私たちの Model クラスについて注目すべき最後のものは view() メソッドです. このメソッドはオブジェクトのデータ周りをシャッフルしたりテンプレートで簡単に使うための別のデータ構造を作成する機会をそれに与えるためにあります. これは複雑な実装をテンプレートコーダーから隠すために使われます. 例えば, キャッシュの有効期限を別にできるようにするために行ったプロダクト在庫データのパーティション化を覚えていますか ? プロダクトの Model オブジェクトは実際にはいくつかの基盤実装オブジェクトのファサード (# 見せかけ) ですが, そのクラスの view() メソッドはそのテンプレートによって使うためのデータを統合します.
To finish off our Hello World example, we need a template to render the view. This one will do the job:

私たちの例 Hello World を終了するために, 私たちは View をレンダリングするテンプレートが必要です. これはその仕事をするものです:

<html>
<title>Hello, My Oyster</title>
<body>
[% PROCESS header.html %]
Hello [% hello.name %]!
[% PROCESS footer.html %]
</body>
</html>



パフォーマンスチューニング : Performance Tuning



Since Perl code executes so quickly under mod_perl, the performance bottleneck is usually at the database. We applied all the documented tricks for improving DBD::Oracle performance. We used bind variables, prepare_cached(), Apache::DBI, and adjustments to the RowCache buffer size.

Perl コードは mod_perl のもとでとても速く実行されるので, そのパフォーマンスのボトルネックは通常データベースにあります. 私たちは DBD::Oracle のパフォーマンスを向上するためにドキュメント化されたすべてのトリックを適用しました. 私たちはバインド変数, prepare_cached(), Apache::DBI を使い, それから RowCache バッファサイズの調整をしました.
The big win of course is avoiding going to the database in the first place. The caching work we did had a huge impact on performance. Fetching product data from the Berkeley DB cache was about ten times faster than fetching it from the database. Serving a product page from the proxy cache was about ten times faster than generating it on the application server from cached data. Clearly the site would never have survived under heavy load without the caching.

もちろん大きな勝利は最初からデータベースに行くことを回避することです. 私たちが行ったキャッシュの仕事はパフォーマンスで大きなインパクトをもちました. Berkeley DB キャッシュからのプロダクトデータの取得はそれをデータベースから取得するよりも約 10 倍高速でした. プロキシキャッシュからのプロダクトページのサーブはキャッシュされたデータからアプリケーションサーバでそれを生成するよりも約 10 倍高速でした. ヘビーな負荷のもとではそのキャッシングなくしてこのサイトが生存できなかったことは明らかです.
Partitioning the data objects was also a big win. We identified several different subsets of product data that could be loaded and cached independently. When an application needed product data, it could specify which subset was required and skip loading the unnecessary data from the database.

データオブジェクトのパーティション化もまた大きな勝利でした. 私たちは独立したロードやキャッシュができるいくつか異なるプロダクトのサブセットを特定しました. アプリケーションがプロダクトデータを必要としたとき, それはどのサブセットが必要かを指定してデータベースからの不必要なローディングをスキップできました.
Another standard performance technique we followed was avoiding unnecessary object creation. The Template object is created the first time it's used and then cached for the life of the Apache process. Socket connections to search servers are cached in a way similar to what Apache::DBI does for database connections. Resources that are used frequently within the scope of a request, such as database handles and session objects, were cached in mod_perl's $r->pnotes() until the end of the request.

私たちが従ったもうひとつの標準的なパフォーマンステクニックは不必要なオブジェクト生成を回避することでした. Template オブジェクトはそれが使われた最初で作成されて Apache プロセスのライフのためにキャッシュされます. 検索サーバへのソケットコネクションはデータベースコネクションのために Apache::DBI が行うのと似た方法でキャッシュされます. データベースハンドルやセッションオブジェクトのような, リクエストのスコープで頻繁に利用されるリソースは, そのリクエストが終わるまで mod_perl の $r->pnotes() でキャッシュされました.


罠: ネストされた例外 : Trap: Nested Exceptions



When trying out a new technology like the Error module, there are bound to be some things to watch out for. We found a certain code structure that causes a memory leak every time it is executed. It involves nested try{} blocks, and looks like this:

Error モジュールのような新しいテクノロジーをトライするとき, 注意しなければならないことがいくつかあります. 私たちはそれが実行されるたびにメモリリークを発生する特定のコードの構造をみつけました. それはネストされた try{} ブロックに関与していて, このようなものです:

my $foo;
try {
# some stuff...
try {
$foo++;
# more stuff...
} catch Error with {
# handle error
};
} catch Error with {
# handle other error
};

It's not Graham Barr's fault that this leaks; it is simply a by-product of the fact that the try and catch keywords are implemented using anonymous subroutines. This code is equivalent to the following:

このリークは Graham Barr の過ちではありません; それは try と catch キーワードが無名サブルーチンで実装されているという単純な事実の副産物です. このコードは次と等価です:

my $foo;
$subref1 = sub {
$subref2 = sub {
$foo++;
};
};

This nested subroutine creates a closure for $foo and will make a new copy of the variable every time it is executed. The situation is easy to avoid once you know to watch out for it.

このネストされたサブルーチンは $foo のためのクロージャを作成しそれが実行されるたびにその変数の新しいコピーを作ります. この状況はあなたがそれを注意することをわかれば簡単に回避できます.


バークレー DB : Berkeley DB



One of the big wins in our architecture was the use of Berkeley DB. Since most people are not familiar with it's more advanced features, we'll give a brief overview here.

私たちのアーキテクチャでの大きな勝利のひとつは Berkeley DB の使用でした. ほとんどの人はそのより高度な機能に親しんではいないので, 私たちはここで簡単な概要を提供します.
The DB_File module is part of the standard Perl distribution. However, it only supports the interface of Berkeley DB version 1.85, and doesn't include the interesting features of later releases. To get those, you'll need the BerkeleyDB.pm module, available from CPAN. This module can be tricky to build, but comprehensive instructions are included.

DB_File モジュールは標準的な Perl ディストリビューションの一部です. しかしながら, それは Berkeley DB バージョン 1.85 のインターフェイスのみをサポートしていて以降のリリースの興味深い機能は含んでいません. それらをゲットするために, あなたは CPAN から利用可能な, BerkeleyDB.pm モジュールが必要になるでしょう. このモジュールはビルドがトリッキーになるかもしれませんが, 広範囲な説明が含まれています.
Newer versions of Berkeley DB offer many features that help performance in a mod_perl environment. To begin with, database files can be opened once at the start of the program and kept open, rather than opened and closed on every request. Berkeley DB will use a shared memory buffer to improve data access speed for all processes using the database. Concurrent access is directly supported with locking handled for you by the database. This is a huge win over DB_File, which requires you to do your own locking. Locks can be at a database level, or at a memory page level to allow multiple simultaneous writers. Transactions with rollback capability are also supported.

Berkeley DB の最新バージョンは mod_perl 環境でのパフォーマンスをヘルプする多くの機能を提供します. まずはじめに, データベースファイルをリクエストごとにオープンとクローズをするのではなく, プログラムのスタートで 1 度オープンしてオープンを維持します. Berkeley DB はデータベースを使用するすべてのプロセスのデータアクセスを向上するために共有メモリバッファを使います. 同時アクセスはデータベースによってあなたのために処理されるロッキングで直接サポートされます. これはあなた独自のロッキングをあなたが行うことを要求する, DB_File への大きな勝利です. ロックは複数の同時書き込みを可能にするためにデータベースレベル, あるいはメモリページレベルでできます. ロールバック能力をもつトランザクションもまたサポートされています.
This all sounds too good to be true, but there are some downsides. The documentation is somewhat sparse, and you will probably need to refer to the C API if you need to understand how to do anything complicated.

これはほんとうにすべてが素晴らしいように思えますが, いくつか良くない面があります. そのドキュメントはややまばらで, もしあなたが複雑な何かのやり方を理解する必要があるならあなたはおそらく C API を参照する必要があります.
A more serious problem is database corruption. When an Apache process using Berkeley DB dies from a hard kill or a segfault, it can corrupt the database. A corrupted database will sometimes cause subsequent opening attempts to hang. According to the people we talked to at Sleepycat Software (which provides commercial support for Berkeley DB), this can happen even with the transactional mode of operation. They are working on a way to fix the problem. In our case, none of the data stored in the cache was essential for operation so we were able to simply clear it out when restarting an application server.

より深刻な問題はデータベースの破損です. Berkeley DB を使用する Apache プロセスがハード kill (# 物理的な停止) や segfault (# セグメンテーションフォルト) で die すると, データベースを破損するかもしれません. 破損したデータベースは続けてオープンしようするとハング (# ハングアップ) を発生させることがあります. 私たちが話をした Sleepycat Software (Berkeley DB の商用サポートを提供している) の人によれば, これはトランザクションモードの操作でさえ発生しうるようです. 彼らはこの問題をフィックスする方法に取り組んでいます. 私たちのケースで, キャッシュに格納されたデータでオペレーションに不可欠なものはなかったので私たちはアプリケーションサーバをリスタートするときにそれをシンプルにクリアすることができました.
Another thing to watch out for is deadlocks. If you use the page-level locking option, you have to handle deadlocks. There is a daemon included in the distribution that will watch for deadlocks and fix them, or you can handle them yourself using the C API.

注意すべきもうひとつのことはデッドロックです. もしあなたがページレベルのロックオプションを使うなら, あなたはデッドロックを処理しなければなりません. ディストリビューションに含まれるデッドロックを監視してそれらをフィックスする daemon がありますし, あなたは C API を使ってあなた自身でそれらを処理することもできます.
After trying a few different things, we recommend that you use database-level locking. It's much simpler, and cured our problems. We didn't see any significant performance hit from switching to this mode of locking. The one thing you need to watch out for when using exclusive database level write locks are long operations with cursors that tie up the database. We split up some of our operations into multiple writes in order to avoid this problem.

いくつか異なることをトライした後, 私たちはあなたがデータベースレベルのロッキングを使うことをお勧めします. それはとてもシンプルで, 私たちの問題を治療しました. このモードのロッキングに切り替えても私たちは大きなパフォーマンスヒット (# パフォーマンスの低下) を見ることはありませんでした. 排他的なデータベースレベルの書込みロックを利用するときにあなたが注意する必要があることのひとつはデータベースを拘束するカーソル (# DB の処理方法) での長いオペレーションです. 私たちはこの問題を回避するために私たちのオペレーションのいくつかを複数の書込みに分割しました.
If you have a good C coder on your team, you may want to try the alternate approach that we finally ended up with. You can write your own daemon around Berkeley DB and use it in a client/server style over Unix sockets. This allows you to catch signals and ensure a safe shutdown. You can also write your own deadlock handling code this way.

もしあなたがあなたのチームにグッドな C コーダーをもっているなら, あなたは私たちが最後におこなった別のアプローチをトライしても良いかもしれません. あなたは Berkeley DB 周りのあなた独自の daemon を書いてそれを Unix socket を通じてクライアント/サーバスタイルで使うことができます. これはシグナルのキャッチと安全なシャットダウンをあなたができるようにします. またあなたはこの方法であなた独自のデッドロックの処理を書くこともできます.


価値あるツール : Valuable Tools



If you plan to do any serious Perl development, you should really take the time to become familiar with some of the available development tools. The debugger in particular is a lifesaver, and it works with mod_perl. There is a profiler called Devel::DProf, which also works with mod_perl. It's definitely the place to start when performance tuning your application.

もしあなたが何らかシリアスな Perl 開発を行う計画をしているなら, あなたはリアルに時間をとって利用可能なツールのいくつかに慣れておくべきです. 特にデバッガはライフセーバーで, それは mod_perl で動作します. Devel::DProf と呼ばれるプロファイラがあり, mod_perl でも動作します. それはあなたのアプリケーションのパフォーマンスチューニングのときにスタートするための確実な場所です.
We found the ability to run our complete system on individual's workstations to be extremely useful. Everyone could develop on his own machine, and coordinate changes using CVS source control.

私たちは個別のワークステーションで私たちのすべてのシステムを実行する能力がとても有用になることを見つけました. 誰もが彼自身のマシン上で開発ができて, CVS (# Concurrent Version System, バージョン管理システム) ソースコントロールを使って変更をコーディネートできます.
For object modeling and design, we used the open source Dia program and Rational Rose. Both support working with UML and are great for generating pretty class diagrams for your cubicle walls.

オブジェクトのモデリングとデザインのために, 私たちはオープンソースの Dia と Rational Rose を使いました. どちらも UML での動作をサポートしていてあなたのキュービクルウォール (# ≒ 間仕切りした図 ?) のためのきれいなクラスダイアグラムを生成するのにグレートです.


自宅でトライする : Do Try This at Home



Since we started this project, a number of development frameworks that offer support for this kind of architecture have appeared. We didn't use one of these, but they have a similar design to what we did and may prove useful to you if you want to take an MVC approach with your system.

私たちがこのプロジェクトをスタートして以来, この種のアーキテクチャのサポートを提供する多くの開発フレームワークが現れました. 私たちはそれらをどれも使いませんでしたが, それらは私たちが行ったものと似た設計をもっていてあなたがあなたのシステムで MVC (# Model View Controller) アプローチをとりたい場合に役立つかもしれません.
Some of the most interesting tools for MVC web development in Perl include Apache::PageKit, OpenInteract2, CGI::Application, Maypole, and Catalyst. There isn't room here to get deeply into the differences between these tools, but watch for an article comparing these frameworks in the future.

Perl での MVC web 開発のためのいくつかもっとも興味深いツールは Apache::Pagekit, OpenInteract2, CGI::Apllication, Myapole, それから Catalyst を含みます. ここではこれらのツール間の違いに深入りすることはできませんが, 将来的にこれらのフレームワークを比較する記事を期待しています.
If you want a ready-to-use cache module, there are several on CPAN now. The most popular is the Cache::Cache framework, which can use files or shared memory for storage. Since the original writing of this article, newer and faster options have appeared, particularly Cache::FastMmap and Cache::Memcached.

もしあなたがすぐに使えるキャッシュモジュールを欲しいなら, すでに CPAN 上にいくつかがあります. もっともポピュラーなものは Cache::Cache フレームワークで, それはストレージのためにファイルか共有メモリを使うことができます. この記事を最初に書いて以降, より新しく高速なオプションが現れました, 特に Cache::FastMmap と Cache::Memcached です.
The Java world has many options as well. The Struts framework, part of the Jakarta project, is a good open source choice. There are also commercial products from several vendors that follow this sort of design. Top contenders include ATG Dynamo, BEA WebLogic, and IBM WebSphere.

Java の世界も多くのオプションをもっています. Jakarta プロジェクトの一部の, Struts フレームワークは, グッドなオープンソースの選択肢です. この種の設計に従ういくつかのベンダからの商用プロダクトもあります. トップコンテンダーは ATD Dynamo, BEA WebLogic, それから IBM WebSphere です.


オープンソースのサクセスストーリー : An Open Source Success Story



By building on the open source software and community, we were able to create a top-tier web site with a minimum of cost and effort. The system we ended up with is scalable to huge amounts of traffic. It runs on mostly commodity hardware making it easy to grow when the need arises. Perhaps best of all, it provided tremendous learning opportunities for our developers, and made us a part of the larger development community.

オープンソースソフトウェアとコミュニティを基礎にすることで, 私たちは最小のコストと努力でトップティアの web サイトを作成することができました. 私たちが仕上げたシステムは膨大なトラフィックに対してスケーラブルです. その大部分がコモディティ (# 通常の商品) のハードウェア上で走っていることは必要なときにそれを拡張できるようにします. 何よりも良いことはおそらく, それが私たちの開発者にとてつもない学習の機会を提供し, 私たちをより大きな開発者コミュニティの一部にしたことです.
We've contributed patches from our work back to various open source projects, and provided help on mailing lists. We'd like to take this opportunity to officially thank the open source developers who contributed to projects mentioned here. Without them, this would not have been possible. We also have to thank the hardworking web developers at eToys. The store may be closed, but the talent that built it lives on.

私たちは私たちの仕事からのパッチをさまざまなオープンソースプロジェクトにコントリビュートし, メーリングリストにヘルプを提供しました. この機会に私たちはここで言及されているプロジェクトにコントリビュートしてくれたオープンソースの開発者たちに公式に感謝したいと思います. それらがなければ, これは不可能だったでしょう. また私たちは勤勉な eToys の web 開発者たちにも感謝しなければなりません. 店は閉鎖された (# 2001 年 etoys.com 破産) かもしれませんが, それを構築したタレントは生き続けます.


メンテナ : Maintainers



The maintainer is the person(s) you should contact with updates, corrections and patches.

Per Einar Ellefsen <per.einar (at) skynet.be>


作者 : Authors



Only the major authors are listed above. For contributors see the Changes file.


NEXT



次回は、「 Documentation / Tutorials / Part II: Templating / Choosing a Templating System 」を「 mod_perl 」公式サイト (https://perl.apache.org/index.html) より確認する予定です。


参考情報は書籍「 続・初めての Perl 改訂版 」, 「 Effective Perl 第 2 版 」を中心に perldoc, Wikipedia および各 Web サイト。それと詳しい先輩。

目次 - Perl Index





















関連記事