前の記事で、Cassandraがデータを保存する方法を明快に説明しました。 少なくとも目を走らせることを強くお勧めします。 この記事では、
次の記事で使用する単純なデータベースを作成します。これは、データの選択/取得に完全に専念します。
挑戦する
広告をスピンする広告ネットワークがあるとします。 人々はバナーをクリックし、広告顧客は支払い、私たち(ネットワーク)、再販業者(販売業者)、および広告ホスティングホスティング会社はこれに収入を得ます。 広告スロットの再販業者は20%働いています。 この割合はさまざまな要因によって増加しますが、最も重要なことは、一定ではなく、たとえば1か月前のクリックに新しい割合を適用できることです。
必要なのは、各リセラーの収入を任意の期間ですばやくカウントできること、クリックのスケジュールをリアルタイムで維持することです。
免責事項
- この記事は、広告ネットワークのタスクをモデリングするための唯一の正しいガイドではありません。
- 各ケースには、固有のシミュレーションが必要です。 特効薬は存在しません。
教育プログラム
- Cassandra(以降、 C * )は、分散NoSQLデータベースです。
- cqlsh -C * CQLのコマンドライン。
- CQLは、SQLに似たクエリ言語です。 C assandra Q uery L anguageの略語。
- キースペースは、リレーショナルDBMS のデータベースに類似しています 。
- 基本的なストレージユニットは文字列です。 行は20億列に動的に拡張できます。 これは重要です。
- 主キー -文字列の一意の識別子。 各行にある必要があります。 文字列が保存されているノードの検索、および文字列自体の内部の検索に使用されます。
- 配布キーは、マスターキーの最初の部分です。
- クラスターキーは、マスターキーの2番目の部分です。
- ノード(ノード) -CassandraのJavaプロセス。 すべてのノードは同等です。 マスタースレーブの依存関係はありません。
- クラスター -全体として互いに連携する複数のノード。
- 記録中に、記録されたセルの現在の値を読み取る方法はありません(これはほとんど正しいです)。
6つのノードがあると仮定しましょう。
cqlsh
cqlsh
実行します。
Connected to Test Cluster at localhost:9160. [cqlsh 4.1.0 | Cassandra 2.0.2 | CQL spec 3.1.1 | Thrift protocol 19.38.0] cqlsh>
キースペースを作成する
キースペース(データベース)を作成します。
CREATE KEYSPACE ad_network WITH replication = { 'class': 'SimpleStrategy', 'replication_factor': '3' }; USE ad_network;
replication_factor
は、文字列を保存するノードの数です。
モデルを作成する
リセラー表
リセラーテーブルを作成し、データを入力します。 表には、再販業者の金利の変化の履歴が保存されます。
CREATE TABLE reseller ( id text, effective_since text,
3行作成したようです。 しかし、
前の記事を読んだ人は
、 'supaboobs'
配布キーと3つの
クラスターキー '2011-02-13'
、
'2012-01-22'
、
'2013-11-30'
1行作成したことを知ってい
ます 。 この行と後続のすべての行は、6つのノードのうち3つに保存されます。
内容を見てみましょう:
cqlsh:ad_network> SELECT * FROM reseller WHERE id='supaboobs'; id | effective_since | reward_percent -----------+-----------------+---------------- supaboobs | 2013-11-30 | 0.3 supaboobs | 2012-01-22 | 0.25 supaboobs | 2011-02-13 | 0.2
将来、現在の金利が必要になったときに、次のことを行います。
cqlsh:ad_network> SELECT * FROM reseller WHERE id = 'supaboobs' LIMIT 1; id | effective_since | reward_percent -----------+-----------------+---------------- supaboobs | 2013-11-30 | 0.3
Ad_clickテーブル
これで、バナーのクリックを保存します。
列:販売代理店ID、日(検索を高速化するため)、日付+クリック時間、バナーID、クリックの総費用。
CREATE TABLE ad_click ( reseller_id text, day text,
データを追加します。
INSERT INTO ad_click (reseller_id, day, time, ad_id, amount) VALUES ('supaboobs', '2013-11-28', '2013-11-28 02:16:52', '890_567_234', 0.005); INSERT INTO ad_click (reseller_id, day, time, ad_id, amount) VALUES ('supaboobs', '2013-11-28', '2013-11-28 07:17:35', '890_567_234', 0.005); INSERT INTO ad_click (reseller_id, day, time, ad_id, amount) VALUES ('supaboobs', '2013-11-29', '2013-11-29 17:18:51', '890_567_211', 0.0075); INSERT INTO ad_click (reseller_id, day, time, ad_id, amount) VALUES ('supaboobs', '2013-11-29', '2013-11-29 22:20:37', '890_567_211', 0.0075); INSERT INTO ad_click (reseller_id, day, time, ad_id, amount) VALUES ('supaboobs', '2013-11-30', '2013-11-30 11:21:56', '890_567_234', 0.005); INSERT INTO ad_click (reseller_id, day, time, ad_id, amount) VALUES ('supaboobs', '2013-12-01', '2013-12-01 12:21:59', '890_567_010', 0.01);
それらを見てみましょう。
cqlsh:ad_network> SELECT * FROM ad_click; reseller_id | day | time | ad_id | amount -------------+------------+---------------------+-------------+-------- supaboobs | 2013-12-01 | 2013-12-01 12:21:59 | 890_567_010 | 0.01 supaboobs | 2013-11-30 | 2013-11-30 11:21:56 | 890_567_234 | 0.005 supaboobs | 2013-11-28 | 2013-11-28 07:17:35 | 890_567_234 | 0.005 supaboobs | 2013-11-28 | 2013-11-28 02:16:52 | 890_567_234 | 0.005 supaboobs | 2013-11-29 | 2013-11-29 22:20:37 | 890_567_211 | 0.0075 supaboobs | 2013-11-29 | 2013-11-29 17:18:51 | 890_567_211 | 0.0075
複合
配布キー (reseller_id, day)
、実際に4行が作成されました(理由がわかりにくい場合は、
前の記事を読んでください。すべてが適切に配置されます)。 再販業者ごとに毎日新しい行を作成し、データを入力することがわかりました。
クラスターキーも複合
time, ad_id
です。
Amount_by_dayテーブル
金利は1日に1回しか変更できないため、これで数ミリ秒とプロセッサー時間を稼ぐことができます。 同じお金を保存する別のテーブルを作成しましょう。ただし、クリックに分割することはありません。
CREATE TABLE amount_by_day ( reseller_id text, day text,
1日1回記入する必要があります。 システムの別のコードが
ad_click
からデータを収集し、要約して
amount_by_day
書き込みます。
クリック数テーブル
当然、どのバナーをクリックしたかを知ることが重要です。 ただし、6つすべてのノードで
SELECT COUNT(0) FROM ad_click WHERE ad_id='...'
を実行するとコストが高くなり(CQLに
COUNT
操作がない)、C *には
counterなどのようなものがあります。 s。
カウンターは列のタイプ、つまり
timestamp
、
text
、
double
などのように構文的に使用され
text
。ただし、制限があります。 テーブルに少なくとも1つのカウンターがある場合、他のすべての列もカウンター型でなければなりません(もちろん、PRIMARY KEYを除く)。 テーブルを作成しましょう:
CREATE TABLE clicks_per_ad ( ad_id text, clicks counter, PRIMARY KEY (ad_id));
そのため、表では
clicks
列の値を変更できます。
cqlsh:ad_network> SELECT * FROM clicks_per_ad; (0 rows) cqlsh:ad_network> UPDATE clicks_per_ad SET clicks = clicks + 1 WHERE ad_id = '890_567_234'; cqlsh:ad_network> SELECT * FROM clicks_per_ad; ad_id | clicks -------------+-------- 890_567_234 | 1 (1 rows) cqlsh:ad_network> UPDATE clicks_per_ad SET clicks = clicks + 1 WHERE ad_id = '890_567_234'; cqlsh:ad_network> SELECT * FROM clicks_per_ad; ad_id | clicks -------------+-------- 890_567_234 | 2 (1 rows) cqlsh:ad_network> UPDATE clicks_per_ad SET clicks = 0 WHERE ad_id = '890_567_234'; cqlsh:ad_network> SELECT * FROM clicks_per_ad; ad_id | clicks -------------+-------- 890_567_234 | 0 (1 rows)
したがって、
signed int
れていれば、何でも考慮できます。 つまり 例外的な整数も考慮できますが、範囲は-2 ^ 63-+ 2 ^ 63です。
最初はテーブルに行がなかったが、
UPDATE
コマンドの後に突然行が表示されたことは注目に値します。 これはCQLの機能です。
INSERT
と
UPDATE
は基本的に同じコマンドです。 C *にデータが既に存在する(または「まだ」ではない)場合、データを更新/挿入しない機会があることを予約します。 これは「軽量トランザクション」と呼ばれ、通常のデータ書き込み操作に比べて動作が遅くなります。
もちろん、クリック数は任意の基準(キー)で収集できます。 例:
CREATE TABLE clicks_per_reseller_per_day ( reseller_id text, day text,
テキストIDについて少し
RDBMSでは、int型の一意の識別子を文字列に割り当てるために使用されます。 識別子をテキストにすると、意味のあるものになりますか? はい。生産性が低下するためです。 個人的に、それは私を大いに落胆させました。 私たちは、運転免許証のIDが数字であり、保険証券のIDが数字であるという事実に慣れています。 しかし、パスポートIDなどの文字を混ぜなければならないことがよくあります-2文字と6桁、多くの場合は文字またはハイフンを含む家番号など。
C *では、RDBMSとは異なり、加速を行わないため、キーとしてドライナンバーを使用することは一般的ではありません。 はい。C*の自動インクリメントはありません(ただし、一意のIDが突然必要な場合は
timeuuidがあります)。 異常は、列タイプ
reseller_id
として
text
見える場合があり
text
。 C *では、パーティションキーはハッシュを比較して検索されます。 つまり 文字列の直接比較は行われません。つまり、パフォーマンスは低下しません。
データ記録
ワンクリックを記録するには、
4回もの UPDATE
操作を行う必要があります。 私は狂っていません。 C *への書き込みは操作が速すぎるため、パフォーマンスは低下しません。 6ノードでの書き込み速度は、RDBMSは言うまでもなく、
MongoDBの約
100倍、またはHBaseの2〜5倍です。 C *の最近のバージョンでは、ディスクスペース(
圧縮 、
圧縮 )を個別に最適化できるため、すべてのハードディスクスペースは問題ありません。
すべてのINSERTが機能することを確認するために、BATCHなどがあります。 残念ながら、それらは同じ配布キー内で(同じ行内で)動作します。
BEGIN BATCH
バッチは、RDBMSのトランザクションの代替ではありません。 それらの助けを借りて、C *は複数のコマンドではなく、1つのパッケージですべてのコマンドを転送するため、ネットワークが最適化されます。 バッチには2つのタイプがあります。
- ログに記録されていない-BEGIN UNLOGGED BATCH-通常のバッチ。 ただし、コーディネーターノード(そのノードに来たCQLコマンドと他のノードとの通信を担当するノード)がバッチの途中で停止すると、データの整合性が損なわれる可能性があります。
- アトミック(アトミック)-開始
BEGIN BATCH
-この場合、C *はすべてのデータが書き込まれるか、何も書き込まれないことを確認します。 ただし、この操作は約30%遅くなります。
データの読み取り
次の記事は 、このトピックに専念しています。
SELECT ... FROM ... WHERE
操作には、RDBMSと比較して多くの制限があるため、これには特に注意を払う必要があります。
おわりに
この投稿の目的は、Kassandraでデータベースをモデル化するアプローチがRDBMSとどのように異なるかを示すことでした。 ご覧のように、アプローチは根本的に異なります。 また、CQLとSQLの類似性に混乱しないでください。実際、構文のみが一致します。 ここではいくつかのトリックと特徴的な機能のみを示しましたが、さらに多くの機能があります。
サイクルの前の記事 。
シリーズの次の記事 。