電子マネー決済ゲートウエイ

ちょっと前に、ある機器での電子マネー決済サービスがはじまりました(・ω・)
そのサービス用の、ゲートウエイサーバを作ったりしたわけですが。
決済サービス自体のサーバ群は元々あるものを使い、サーバ向けのプロトコルと機器向けのプロトコルの変換を行うだけのものなので大したものではないんですが、そのアーキテクチャについてなんか少し雑記。

基本構造

ゲートウエイはJava*1でてきています(・ω・)


Webサービスとかではなくて、パフォーマンスが要求されるAPサーバー/ミドルというと、速度の観点からC/C++でみたいなイメージがあったりしますが。
今回のゲートウエイ開発の前にも、Android向け決済でのミドルやサーバー開発なんかをしており、その段階でC++での性能検証なんかもしていて。
やはりC++だと開発環境面などでの面倒さなどもあり、若干の工夫は必要ですがJavaでも十分な性能を出せることを検証した上で、Javaを選択しています。*2

通信のI/Oモデル

構成とししては、非同期I/Oとスレッドプールの合わせ技です。
ゲートウエイの特性として、機器側の通信と上位サーバ側の通信という、2方向/複数TCP及びUDP通信を非同期I/Oで処理しています。
非同期I/Oなのは、性能面での工夫もありますが、プロトコルがリクエスト/レスポンスのような単純なものではなく、双方向から任意の時点でデータ受信が発生するものであるので、それを処理するためでもあります。


また、セッションはステートフルであり、非同期I/Oとステートフルという点については、プロトコルスタックや変換レイヤをそれぞれステートマシンとして実装し、ステートマシンを大小さまざまな歯車を組み合わせるようなイメージでセッションの処理を構成しています。
このアーキテクチャ、何気に気に入ったりしています(・∀・)

オブジェクト指向

例えば、GoFデザパタ的に言えば、十数個のパターンを使用していますが。
これは。別に厨ニ的にそうしているわけではなく、必要な問題解決の手段を考えていけば必然的にそうなるというだけの話です(・ω・)


また、マイクロカーネル的というか、各コンポーネントを組み合わせてアプリケーションを構築するような構造としていますが、その点についてはコンポーネント管理機構を使ってDependency Injectionパターンなんかも使用しています。
これも、よく聞くように、DIはテストのためとか言ってみたり、わけもわからずインターフェースと実装を分離しているというような話ではなくて、問題解決に適した手段だから使用しているのであり、本当にプロバイダーもでるが必要なところでしかインターフェースと実装は分離していません。
DIについては、Webの初期に流行った後、disりが聞こえるようになったりもしましたが、DIパターンとAOPの話がぐっちゃになっていたり*3、インターフェースと実装の分離の意味や適用箇所をわかっておらずにdisっているケースが多くて、ちょっとぐんにょりした記憶があります(´・ω・`)


また、よく、糞詰まんないLOBアプリのWebアプリを基準にしてOOをdisったりする話もありますが(´д`;)
必要なケースでは普通にオブジェクト指向の知識は必要になるので、LOBアプリ開発者も、一度はエディタ、言語(スクリプト含)、サーバーミドル、ゲーム等を開発してみるべきだ、っというのが私の持論です。
そんな知識はなくてもLOBアプリを作ることはできる、っというのは単に見識の狭さと自分が土方作業者であることを露見させる発言でしかなく、こういった知識を応用して問題を解決するのが本当のSIだと自分は考えます、なんつって(・∀・)


なお、ドメイン的な話や、ファンクショナル的な話については、変換部分については割とドメインドメインしていたり(なんのこっちゃ)、Action/FunctionインターフェースやMaybe的な実装も普通にあるのですが、そこは今回はたいした話は無いので省略します。


…っと、その一方で、OOとは少し違う工夫をしている部分もあります。

JavaらしくないJava

パフォーマンスについて、基本的な部分についてはJavaの速度で問題無いのですが、それでもアプリケーションの特性的に注意が必要な部分もあります。
決済という特性上、カードとの通信、ユーザへのインタラクション、非同期I/OやUDP通信とタイムアウト等を考慮した場合、処理の遅延はなるべく排除したい所です。


そのため、プールできるものはプールして再利用するような構成にはしています(`・ω・´)
ただし、細かい部分までチューニングした作りにしているわけではなく、プロファイルによる分析をしたうえで、影響の大きいオブジェクトについてのみ工夫を行い、JavaらしくないJava、CみたいなJava、っという所まではチューニングしていません。


感覚的に言うと、負荷100%の状態になった状態で、結構な頻度で100msの遅延が発生する、は許せないが、まれに10msの遅延が発生する、くらいなら許容できる、っというくらいには工夫をしている、っという所でしょうか。

CPUバウンドなの?

負荷100%という話が出ましたが、ゲートウエイがCPUバウンドな作りなのかというと、そうです(・ω・)
機器側及び上位側に対して、1決済につき複数回の暗号化/署名が発生するため、CPUバウンドな処理になっています。


性能的には、Core i7 4770な環境で450決済/sといった程度でしょうか。
通信について言えば、1決済あたり50パケットと前述しましたが、単純に計算して1秒あたり22000〜23000パケットを捌いているわけで、通信性能的にはたいしたことはありません。


CPUが余っているのに通信性能が頭打ちになるのはプログラムの通信モデルの問題ですが、非同期I/Oのあたりをちゃんと考慮すれば、Javaでも.NETでも100,000 reqres/sくらいは普通に処理可能です。*4

その他の工夫や周辺ツールについて

後は、その他のトピックについて少し。


ゲートウエイサーバには、運用面を考慮して、管理ポートに接続すると使用できる簡易シェル機能や、JMXによる各種メトリクス値の取得や動的な設定値変更機能などは提供しています(`・ω・´)
今時だと、Webアプリなどにおいても、運用の改善や問題の兆候を捉えるため、アプリケーション固有のメトリクス値の提供等は必須であるともいえるかと思います。


また、ログについても、メトリクス値同様、収集して分析することで、問題の兆候の発見や設定値の改善に役立てることが可能な情報を出力するようにしています。
ただし、ログの粒度、項目、形式などについては、昨今のログ分析等におけるトレンドを踏まえ、最適な形とはどのようなものなのかについて、もう少し学んでみたいところです(・ω・)


ところで、ゲートウエイ自体はJava製なんですが、テストツール等、周辺ツールC#で作っていたりします。
機器の変わりのダミークライアントは普通のWPFアプリでMVVMとかしてますし、機器のクライアントミドル相当品もC#で作ってあって、それを使えば機器の決済と同様の事ができるものにはなっています。*5


あとは、ベンチマーク用の疑似クライアント、疑似サーバなんかも、C#で作ってそれをMono上で動作させたりもしています。
これら疑似クライアント、疑似サーバの通信I/Oモデルについては、Java側の作りと共有できる部分は共有した作りにするため(単に手抜きのため)、libeventモドキな抽象化機構で作っていたりします。


そげな感じ(・ω・)

*1:開発時期は一年前くらいから去年の末までくらい。Java 7で、7的な機能は普通にしようしています

*2:検証時には、PythonC#+Monoなんかでも性能検証をしていたり

*3:AOPは糞( ゚д゚)、

*4:ただのEchoサーバとかなら(・∀・;)

*5:別に不正ができるわけではなく、普通に金額が引き去られちゃうだけですが(・∀・;)