Yii:ActiveRecordおよびシャーディングデバイス

最近、Habr上のYiiフレームワークに多くの注意が払われました。 彼は主要なプロジェクトの私たちの選択になりました。 そして、ご存じのように、ほとんどの大規模プロジェクトの問題はスケーリングです。 何百もの並列nginxを簡単に配置し、プロセッサ、メモリ、ディスク、さらにはチャネルの負荷のバランスをとることができることも知られています。 しかし、DBMSでは、すべてがはるかに複雑です。



この問題を事前に正しい方法で克服するために、Yiiでシャーディングサポートを実装することが決定されました。 カットの下でのスピーチでは、シャーディングとは何かについて簡単に説明します。

  1. YiiのActiveRecordデバイス
  2. このシャーディングデバイスでの実装
  3. まだARにある問題
UPD:PHPに移植されて以来 シャーディングの拡張機能の存在は、フレームワークを選択するときにスケールを傾けることができます。



シャーディング



シャーディングは、データの垂直スケーリングと呼ばれます。条件によっては、テーブル内の特定の行がデータベースノードの1つに挿入されます。

ソーシャルネットワークの最も一般的なケースでは、ユーザーデータを挿入するノードを選択するアルゴリズムは次のようになります。



server_id := user.id % 2

server_connection = server_id == 0 ? 'dsn1' : 'dsn2'








同じアルゴリズムまたはシステムルックアップテーブルのいずれかでユーザーデータを検索するノードを選択できます。 2番目のオプションでは、少なくとも1人のユーザーを選択したノード全体に自由に転送できます。



「シャードが実行される本質」と見なされるユーザーと一緒に、すべての作業を保存します。 ブログ投稿を配置するサーバーを選択すると、次のようになります。



server_id := post.user.id % 2

server_connection = server_id == 0 ? 'dsn1' : 'dsn2'








スケーリングをほぼ無限にするシャーディングは、多くの問題を引き起こします。 Netlogの説明と、現実世界でのシャーディングの生き方に関するNetlogの記事について読むことができます。 これらは、このパターンのすべての詳細について非常に詳細です。



YiiのActiveRecordデバイス



Yiiのベースと対話する主な機能は、ActiveRecordとActiveFinderの2つのクラスに分かれています。 最初のテーブルは、使用するモデルが属する1つのテーブルのみを操作でき、()またはjoin()に遭遇するとすぐに、すぐにActiveFinderに変更されます。 これは、いくつかのテーブルのみを操作する方法を知っており、常にJOINのクエリを作成します。



AR操作のメインデータベース接続は、Yii構成によって決定されます。 実装では、パブリックgetDbConnection()メソッドがそれを担当します。 この場合、ActiveRecordがこのメソッドを決定し、ActiveFinderがActiveRecordにアクセスします。



シャーディングの実装



以下に説明するすべての完成版はここにあり、「どのようにこれを有効にするか、すべての人に共有するか」という質問で、フレームワークの開発者によって現在検討中です。



フレームワークにシャーディングを実装するために必要なのは、ORMに外界の条件に応じて接続を選択するように教えることだけです。 したがって、ある種のパラメータを取得し、それに応じて適切な接続を選択する機会を彼に与える必要があります。



Yiiインターフェースにはチェーン呼び出しがあります:Foo :: model()-> with( '...')-> find()。 したがって、「外部からの情報」を彼に伝える良い方法は、それを記憶し、それに基づいて決定を下せるようにする別の方法を実装することです。 ()を選択します。



エンドユーザーにとっては、次のようになります。Foo :: model()-> choose($ shard)-> find(); この変数はオブジェクト内に記憶されます。 また、他のモデルには一切影響しません。 同様に、同じモデルの他のインスタンス。 これにより、2つの結果が得られます。



1.カプセル化。 突然何も壊れません。 :)

2.シャードを使用する必要がある各モデルについて、手動で選択をプルする必要があります。 :(



ただし、内部デバイスに戻ります。保存されたキーは、オーバーライドされたgetDbConnection()によって考慮されます。 キーがある場合は、その上で断片選択アルゴリズムを実行する必要があります。 キーがない場合(呼び出しはパラメーターなしで呼び出されたり呼び出されたりしません)-構成からの標準接続を使用します。 接続選択アルゴリズム自体は、特別なDbConnectionManagerクラスに実装されています。 このクラスの実装は、「このキーで使用されるdsnを理解する」という1つの操作を除き、非常に一般的です。 それは、実装に含まれる抽象クラスから継承することによって実装されることが提案されているものです。



合計:($断片)-> getDbConnection($断片)-> DbConnectionManager :: getConnection($断片)-> DbConnectionManager :: _ findConnection($断片)を選択します。



これがチェーンです。 シャーディングの基本的なサポートは次のとおりです。 ちなみに、このような実装の助けを借りて、レプリカや他の多くの便利なものに自動的に切り替えることができます。 この実装のもう1つのプラス:完全な透明性。 choose()が呼び出されるまで、何も変わりません。



さらなる実装は、シャーディングを正確に構築する方法に大きく依存します。 このプロジェクトでは、ShardedActiveRecordを継承する別のクラスを実装しました。これにより、70%の場所で、手動でシャードを指定する必要がなくなりました。 データベースをユーザーごとに分割することを知っているため、保存時にchoose()を自動的に呼び出すことを妨げるものはありません。 または、彼のブログ投稿を保存します。



この場合、理論的には、「構成に関する規約」アプローチに基づいて、拡張機能を開発し、いくつかの基本的な単純なシャーディングをそのまま使用できます。 おそらく次の記事はこれについてです。



結論として、上記の実装が議論されているトピックのYiiフォーラムのアーカイブにあるという事実に再び注目します。 これには、抽象ConnectionManagerとShardedActiveRecordの2つのクラスだけでなく、ユニットテストのセットも含まれます。 そして、これらの単体テストから、そのような実装を使用した場合にオブジェクトの選択がどのようになるかを見るのはかなり良いことです。



まだARの問題



最初の段落のNetlogでのシャーディングの実装に関するリンクに関する記事をまだ読んでいるなら、おそらく、シャーディングに加えて、キャッシングへの興味深いアプローチを説明していることに気づいたでしょう。 モデルのキャッシュ。



デフォルトでは、YiiはJOINを使用するために加重平均ポリシーを使用しようとします。 彼は100件のリクエストですべてを作成するわけではありませんが、すべてを1件にまとめようとはしません。 同時に、メソッド()があります。これにより、1つの必須リクエストを強制的に作成できます。 ただし、最初にすべてのエンティティのIDを選択し、次にそれらのそれぞれを選択する単一のクエリを作成する、反集合()メソッドはありません。



memcachedとsphinxを取り除くと、そのような方法は役に立たないように見えます。 しかし、IDの束を返す何らかの検索クエリがあると想像してください。 そして、model_ $ idによるすべてのエンティティ(一般的にはすべて)はRAMに保存されます。 そしてYiiは、データベースでIDで特定のモデルを検索する前に、キャッシュでそれを見つけようとします。



これらすべてを実装することは、ActiveFinderとBehavioursに出会うまで、それほど複雑ではないようです。 しかし、これは一般に、別の記事の主題でもあります。 一方、フレームワークの作者は、個人的な実装について考えることを約束しました(とにかく、彼は外部ハッカーよりもARを重視しています)これは1.1です;]。



All Articles