Aerospikeこんにちは、k_oomoriです。アクセスログを記録するにあたり、以下の要件を満たすデータベースが必要になりました。ユーザを区別するID(uid)、アクセス時刻、アクセスURL、その他必要に応じて追加される属性を記録する特定のuidに対して過去のアクセスログをまとめて取得できる過去400日(約13か月分)のログを蓄積できる今回は、AerospikeとDynamoDBを比較検討しましたのでその結果をまとめようと思います。DynamoDBとは、AWSによって提供されているフルマネージドNoSQLデータベースサービスです*1。DynamoDBではデータは「テーブル」という単位に保存し、テーブルには検索のためのプライマリーキー(PK)が必要となります。DynamoDBのPKの付け方には2種類あって、一つは「ハッシュキー」、もう一つは「ハッシュキー+レンジキー」と呼ばれます*2。ハッシュキーはRDBにおける単一カラムに対するPKのようなもので、KVS的な使い方をするときに使います。ハッシュキーの値に重複は許されません。対してハッシュキー+レンジキーはRDBの複合プライマリーキーのようなもので、こちらはレンジキーの値が違えばハッシュキーの値が同じであっても別itemとして登録できます。今回の要件に対してはハッシュキー=uid、レンジキー=アクセス時刻とするのがよさそうですので、次のようなテーブル設計で進めます。Javaを使ってデータを取得するコーディング例を紹介します。01:00:00)//)Scalaと言いましたが実際はほとんどJavaですね(笑)。それではパフォーマンスの検証をしましょう。+ドメインのみ)ものと長い(2kBほど)もので、クエリで100件、1,000件、10,000件、100,000件ヒットするようなテストデータを用意し、取得にかかる時間を計測したところ、結果は以下のようになりました。時間の単位はミリ秒です。この値は計測を5回行いその平均値としています。ms100件くらいまでなら20ms前後で返ってきますが、件数に比例して時間が延びていく感じですね。1万件を越えたあたりから秒単位の時間がかかってしまうようになるので、リアルタイム処理に利用するのは現実的ではないかもしれません。capacityの設定がありますが、これは並列アクセスをどのくらい捌けるかという量なので、今回のような1発のクエリが重い場合にはcapacityを上げても速くなりません(実際にスループットを10倍にして試してみましたが、ほぼ変わらずでした)。逆にcapacityの設定が少なすぎるとProvisionedThroughputExceededExceptionが発生します。DynamoDBの利点としては、フルマネージドのためサーバ管理の必要がない点や、データ量が多くなっても実質的にほぼ無尽蔵にデータを溜められることなどが挙げられます。データ量に応じて課金はされますが、1TBのデータを入れても月に$285(@東京リージョン)と、比較的お財布にやさしい金額設定ではないでしょうか。AerospikeAerospikeとはNoSQLに分類される分散KVSです。高速なKVSといえばMemcachedやRedisが有名ですが、これらはデータをメモリ上に保持するため長期間のアクセスログを保存するといったような用途には適していません。それに対してAerospikeではアクセスの高速性を保ちつつSSD上にデータを保持することができるため、大容量データに対応できます。このブログでもyu_ishikawaさんがAerospikeに関する解説記事を書いてくれていますので、あまり馴染みがないという方はこちらを参照してみてください。List型AerospikeにはListsというデータ型が存在し、1つのrecordの中に複数のデータを持つことができます。よって表1に相当するものはAerospikeでは次のように表現できます。clientを用いてScalaから操作してみましょう。//)}client.close()しかし、Aerospikeには1レコードの最大容量が1MBまでという制限があるため、このList型の中に全てのログを保存することはできません。解決策としてはuidをキーにするのではなく、uid+日付などデータが1MBに収まるようにキーを細かく分けて保存する方法が挙げられます。パフォーマンスの検証結果は以下のようになりました。上記容量制限のため、1つのキーに短いURLでも1000件、長いURLだと100件くらいまでしかログデータが入りませんでしたので、より多いログ件数を実現するためにキーを分割しました。URLの100,000件=100件×1,000キーなど)なお、検証に使用したサーバはAWSのm3.medium×3台でクラスタを組んだものになります。(LList)型という容量1MB制限を突破できる特別なデータ型があり、これを使えば表2のデータ構造がそのまま実現できるのですが、一つのキーに巨大データを入れるというのはそもそも分散KVSの思想に沿っていないということですでに非推奨になっています。利用可能なのでとりあえずやってみました。Any]()//"key"が必須!これでソートされているらしい。1464833977000))パフォーマンスは以下のようになりました。msまあ、deprecatedと言われているので、これから新たに開発しようとする場合は使用を避けた方がよいでしょう(笑)。まとめ本記事ではアクセスログを保存するという観点で、DynamoDBとAerospikeを操作するScalaコードの紹介と、パフォーマンスの計測を行いました。測定結果を図にまとめると以下のようになります。両対数グラフで傾きはほぼ1の直線になっているので、データ量に比例して取得にかかる時間が長くなるということがわかります。速さではAerospikeでList型を使うのが勝っていましたが、DynamoDBの場合は(お金さえ払えば)AWSがよしなに管理してくれるという利点がある(Aerospikeでは容量が足りなくなってサーバを追加したりサーバが故障したりした際にマイグレーション(クラスタ内でのデータの再分配)が起こったりして管理が結構大変...)ので、メリット・デメリットを把握した上でどのデータベースを使うのかを決めるといいと思います。(英語版)*1:ここではDynamoDBの基本的な説明は割愛しますので、DynamoDBのことをあまり知らないという方はRef.[1-2]などを参照していただくとよいかと思います。[3-4]などをご参照ください。14:16Tweet関連記事2018-03-22ScalaのSくらいしか知らなかったモバイルアプリエンジニアですが、はじめてサーバーをつくりましたこんにちは、はじめましての方々ははじめまして。皆さんこんにちは、h_matsumotoです。nend担当@tosh01です。Are青山のアドテク会社。アドネットワークやDSPを開発・運用。サーバを止めてみたよ。インターン:実業務体験編インターンでCTR予測をしましたSearchArchiveスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。