Equalumアップデート検証をやってみた:3

#今回は少し番外編的な内容で・・・・
最近、Equalumの布教活動（？）を行っていると**Equalumのアドバンテージは何ですか？**と言う質問を頂く事が多くなってきました。この点については、Equalum自体も「有る意味、無駄にリアルタイム・・」を前面に出している所もありますので、その部分に大きな話の焦点が集まりがちですが、この点については「その筋の仕組みに関わった方であれば、”いやいや、それは流石に無理でしょう！”と言う冷静な反応になるのが普通です。

実際、全てがCPUの内部バスや、マザーボード上で完結出来るのであれば、それに極めて近い世界も実現出来るかもしれませんが、現実的に皆様が対峙されているIT市場の状況では、その様な化学実験室の理想状態環境下での実装は、「有る意味正しく有り得ない」と言わざるおえません。

では、何がEqualumの強みで有り優位点なのか？を以下に現実的な状況に摺り合わせた形で説明させて頂きたいと思います。

#即時性と低遅延
基本的にコンピュータの処理性能は、使用するCPU性能、メモリ容量と性能、内部バス性能、ストレージ性能及びネットワーク性能の上に成立しています。もちろん、それぞれを有機的に結合し高度な付加価値を創造するソフトウエアの存在も非常に重要では有りますが、極論を言えば、ソフトウエアはハードウエアの性能を超える事は出来ない・・・と言う宿命も同時に存在しています。（ソフトウエアは、有る意味でハードウエア側から見た場合に「ボトルネックの元凶」になりますので）

Equalumのアプローチは、CDCやその周辺（タイムスタンプ駆動など）で発生する状況偏移をメッセージとして取り扱う事で（リアルなクエリを投げて、その結果を判断し、その結果を指定された先へ移動させる・・と言うアプローチでは無く）出来るだけ軽量・軽微なアクションで最大の効果を獲る戦略を選択した点が、先行・既存の多くの類似系（・・と言われる）製品と異なっています。

そこで「**要素技術**」として選択した物が**kafka**と**SPARK**になります。

Equalum開発陣は、これらのクラウド・分散処理系で実績・定評の有るソリューションの「強み」と「弱み」を的確に評価・判断し、前者はEqualum自身で開発した関連モジュールとの相乗効果で高い付加価値に昇華させ、後者（特にkafka・SPARK業界で言われ続けていたAt least Once問題）を解決し、技術的に実装が可能なモノについては、後述の**Exactly Once**を提供しています。

その結果、Equalumが統合SQLイベント・メッセージ・ブローカーの役割を担う事により、ソース側で発生したSQLメッセージを「即時」「無駄なく」ターゲット側に伝える仕組みで圧倒的な性能を実現する事が出来ました。一般的なクエリを投げて、その結果を判断・取捨選択し、それらを下流側に自動処理する・・・系のアプローチとは一線を画す部分がこの「データ特化型のメッセージング処理」であり、メッセージング処理としてのkafkaなのだと言えるかもしれません。

#卓越したCDC技術に立脚したExactly Onceの実現
ご存知の通り、CDCコンセプト自体の歴史は古く、いくつものアプローチで実装されて市場で利用されている実績も数多く存在しています。Equalumの優位点は、このCDC（多くのケースでは、人間が直読出来ないバイナリ形式でログを蓄積するケースが多い）の処理を如何に高速・効率的且つ正確に行うか？が非常に重要な処理能力の「最初の優劣ポイント」になり、その領域における利用実績は業界TOPクラスの技術とノウハウに基づき、企業・団体活動のデータパイプラインを支えています。（最近では、大手医療系メーカでの医薬品開発の最先端を支えるデータ・インフラとして採用されたとの事です）

また、有る意味これが最大のアドバンテージになるかと思いますが、単体kafka環境周辺でずっと課題に上がっていた「**エンタープライズ・グレード**」で、「**エンド・トゥ・エンド**」の「**Exactly Onceの実現**」を達成しておりますので、通信の状態変化や、何らかのアクシデントで処理状態が怪しくなった場合でも、Equalumは「その全体の処理連携機能」をフルに活用してユーザのデータ状況の辻褄をきちんと合わせる事が可能になっています。（CDC対応の構造化データベース、kafkaコネクタ経由での接続等で利用可能です）各種のクラウドネィティブなデータソリューションが市場で使われていますが、エンタープライズの現場では、まだ圧倒的に電子帳簿型のデータ運用を構造化データベースで実現されていると思います。それらの仕組みに対して「彼らが標準で持っている機能を活用」し、「出来るだけ外部中立的な仕組み」で高度なデータ利活用やデータ戦略のサポートする・・というのが、Equalumの可能性であり付加価値になります。

#（３）プログラムレスで最新のクラウド技術に立脚したデータコミュニケーション環境が構築可能
さて、長々と前説を書いて参りましたが、それらの性能や機能、また現場での総合的な利用環境を実際に導入しようとした場合、どれだけの開発コスト（人的、時間的）が掛かるか？を考えてみましょう。

勿論、おそらくスクラッチから専用システムとして開発する事は可能だと思いますが、それを具体的に実装する技術レベルを有する人的布陣に対するコスト見積もり、また途中での仕様変更や新規追加等で発生するコスト等を考えると、多くのケースでは「まあ、運用等で工夫して何とか凌ごう・・」となる場合が多いかと思います。

Equalumの場合は、利用環境の導入・整備後での留意点として「その環境のコンピューティング能力が足りているか？」のチェック位で、万が一想定を超え始めた場合も、クラスター構成をシンプルに追加していく形で対応が可能です。また、現場側から見た場合は「Javaプログラミング」等を行わないで、オンデマンド＆セルフでのデータ・ストリーミングの変更・追加が出来る環境でもあります。昨今、データの民主化とかData Opsというキーワードが出てきておりますが、Equalumを活用する事で「意外にサクッと」これらを実現する事が可能になるかもしれません。「データを電子帳簿上に蓄えておく」だけではなく、「データを運用する」という考え方も面白いかと思います。

実は以前の投稿で、旧MemSQL時代でのkafkaパイプライン周りの紹介を書こう・・・かと企画していた時期があり、慌ててのkafka周辺プログラミングや、構造・設定の自習等を事前にスタートさせ、順調に行けば記事投稿になっていたの・・・ですが、現実的には本業との絡みや時間の関係で無念のリタイアをした過去の悲しいトラウマになっていました。

ところが、その数年後・・・・

このEqualumを使えば、誰でも一瞬で高度なkafka使いになると同時に、プログラムを書かないでデータベースからデータを高速・高効率でCDC処理可能な環境を構築する事が出来ます。以前の挫折の後にEqualumの存在を知り、幾つかの紆余曲折の末に前回挫折のリベンジを極めて他力本願で実現出来た事になり、一度知ってしまった楽な環境に慣れたあとは、2度とあの星雲の志の頃には戻れない・・・（苦笑）

#幾つかの実験結果をご紹介します・・
まずは、エッジで完結できるデータ環境（ネット回線等は切れても、フロントはその責任範囲でデータを処理出来る様な仕組み）からEqualumのCDCストリーミングを活用してデータを同期させ、その過程で最終形態のデータベースへ自動仕分けして着地させる仕組みです。

![スクリーンショット 2021-02-28 22.40.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197589/ca04efbf-bbb2-97eb-da6f-1996b4f9373f.png)

実際にこの環境を検証環境で構成し、上流側に設定した各店舗に対応するMySQLに対して、Pythonで作成した販売データ（っぽい）の連続生成・挿入を行うと、EqualumのCDCストリーミングが即時起動してそれぞれの店舗データから用途別統合データベース向けにデータを抽出・前処理して即時同期を実行し、その状況を可視化する事が可能になります。

![画面録画 2021-01-17 時刻 10.48.01.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197589/23257d28-aa8c-3c80-a31f-3d66e68417a3.gif)

動画的には、立ち上がり部分のみを切り出した形になりますが、Equalum経由しても十分な即時性を持って分類・可視化が出来ている事がご理解頂けるかと思います（SingleStoreのI/O性能にも助けられていますが・・・）


次に、今回のEqualumアップデート検証シリーズの最後の実験として、CDCストリーミングの多段構成実験を行ってみたいと思います。

![スクリーンショット 2021-03-02 9.32.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197589/855ce0d4-1bc1-2d53-ffcf-6a0135f20523.png)

今までの想定はEqualumがデータ創出側のデータベースに対して「ある種のファイアーウォール的な仕事」をし、ターゲット側に発生する大量のSQLトランザクション影響を、オリジナル側に負担させない仕組みでの構成になっていました。この仕組みで殆どのケースが対応可能だと思いますが、今回のバージョンアップで普通に活用できる様になった、レプリケーション機能を君こんだ構造（BCP的な感じでしょうか・・・）も検証します。

![スクリーンショット 2021-03-02 12.41.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/197589/bb14300d-50c6-3d99-b35f-9147e6905680.png)

上段・中段が最初にデータを挿入した最上流側のMySQL状況を可視化したもので、下段の２つがそれらを二層目のMySQLでEqualumのCDCストリーミングで統合し、今回のバージョンから利用可能になったMySQLのレプリケーション機能を活用し、最終ターゲットのSingleStoreにレプリケーションした状況を可視化（売り上げ方向で集計処理を行って可視化してみました）した状況になります。

無事に想定通りの結果になった様です。

因みに、今回の可視化用に作ったPythonは以下の通りです。

~~~Python
# coding: utf-8
#
#       多段デモの経過状況可視化
#　　　　　　　

import pymysql.cursors

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec

%matplotlib

# 日本語フォントの設定
from matplotlib import rcParams
rcParams['font.family'] = 'sans-serif'
rcParams['font.sans-serif'] = ['Hiragino Maru Gothic Pro', 'Yu Gothic', 'Meirio', 'Takao', 'IPAexGothic', 'IPAPGothic', 'VL PGothic', 'Noto Sans CJK JP']

# SQL文で使う情報設定
# 各店舗データを可視化（商品名で集計表示）
SQL00 = "SELECT SUM(Units) as UU, Product FROM S0_CDC_Table GROUP BY Product ORDER BY UU DESC "
SQL01 = "SELECT SUM(Units) as UU, Product FROM S1_CDC_Table GROUP BY Product ORDER BY UU DESC "
SQL02 = "SELECT SUM(Units) as UU, Product FROM S2_CDC_Table GROUP BY Product ORDER BY UU DESC "
SQL03 = "SELECT SUM(Units) as UU, Product FROM S3_CDC_Table GROUP BY Product ORDER BY UU DESC "

# 各統括データを可視化（カテゴリ別の売り上げで集計表示）
SQL10 = "SELECT SUM(Payment) as PP , Category FROM M0_CDC_Table GROUP BY Category ORDER BY PP DESC "
SQL11 = "SELECT SUM(Payment) as PP , Category FROM M1_CDC_Table GROUP BY Category ORDER BY PP DESC "

# 共通関数の定義(可視化グラフの表示)
def chart_draw(db,cursor,sql, ax, Color, Title1,Title2, scale, offset):
    
    i = 0
    Tmp_Data = []
    Data_Label = []
    Data_Data = []
    
    cursor.execute(sql)                  
    db.commit()
    
    for Query_Data in cursor.fetchall():                
                for item in Query_Data.values():                  
                    Tmp_Data.append(item)     
    
    for start in range(0, len(Tmp_Data), offset):              
                Data_Data.append(Tmp_Data[i]/scale) 
                Data_Label.append(Tmp_Data[i + 1]) 
                i = i  + offset
    
    y_pos = np.arange(len(Data_Label))
    ax.barh(y_pos, Data_Data, color = Color)
                
    ax.set_yticks(y_pos)   
    ax.set_yticklabels(Data_Label)            
    ax.invert_yaxis()  # labels read top-to-bottom
            
    ax.set_xlabel(Title1, fontsize = 12)
    ax.set_title(Title2, fontsize = 16)
    

try:
    
    # 使用変数の初期化
    Counter = 0            #  処理回数のカウント用
    Time_Wait = 0.5   #　描画間隔の調整用
    Size1 = 2   #  カテゴリ・配送センター別のデータ抽出用オフセット
    
    #　可視化処理関連の準備
    fig = plt.figure(figsize=(14,8))
    gs = gridspec.GridSpec(3,2)
    fig.subplots_adjust(hspace=0.6, wspace=0.4)
    
    # add_subplot()でグラフを描画する領域を追加する．引数は行，列，場所
    #  酒類の受注状況　MySQL１
    ax1 = fig.add_subplot(gs[0,0])
    #　家電の受注状況　MySQL1
    ax2 = fig.add_subplot(gs[0,1])
    # 書籍の受注状況　MySQL1
    ax3 = fig.add_subplot(gs[1,0])
    #　雑貨の受注状況　MySQL1
    ax4 = fig.add_subplot(gs[1,1])
    
    # 複製された集約DB1の状況　SingleStore
    ax5 = fig.add_subplot(gs[2,0])
    #　複製された集約DB2の状況　SingleStore
    ax6 = fig.add_subplot(gs[2,1])
    
    # １段目のMySQLとの接続
    db1 = pymysql.connect(host = 'xxx.xxx.xxx.xxx',
                         port=3306,                
                         user='xxxxxxxx',
                         password='zzzzzzzz',
                         db='xxxxxxxx',        
                         charset='utf8mb4',
                         cursorclass=pymysql.cursors.DictCursor)

    # 3段目のSingleStoreとの接続
    db3 = pymysql.connect(host = 'xxx.xxx.xxx.xxx',
                         port=3306,
                         user='xxxxxxxx',
                         password='zzzzzzzz',
                         db='xxxxxxxx',
                         charset='utf8',
                         cursorclass=pymysql.cursors.DictCursor)
       
    # 無限ループで対応（停止はSTOPボタン（■）で行う）
    while True:
                          
        with db1.cursor() as cursor1, db3.cursor() as cursor3:
            
            # クエリ関連の初期化設定
            cursor1.arraysize = 1000
            cursor3.arraysize = 1000
            
            chart_draw(db1,cursor1,SQL00, ax1, 'Green', '受注数', '酒類取り扱い状況（１段目のMySQL)', 1, Size1)
            chart_draw(db1,cursor1,SQL01, ax2, 'Red', '受注数', '家電取り扱い状況（１段目のMySQL)', 1, Size1)
            chart_draw(db1,cursor1,SQL02, ax3, 'Blue', '受注数', '書籍取り扱い状況（１段目のMySQL)', 1, Size1)
            chart_draw(db1,cursor1,SQL03, ax4, 'Yellow', '受注数', '雑貨取り扱い状況（１段目のMySQL)', 1, Size1)
            
            chart_draw(db3,cursor3,SQL10, ax5, 'Magenta', 'カテゴリ別の総売上（単位：千円）', '統括データベース１の状況（SingleStore）', 1000, Size1)
            chart_draw(db3,cursor3,SQL11, ax6, 'Cyan', 'カテゴリ別の総売上（単位：千円）', '統括データベース2の状況（SingleStore）', 1000, Size1)
   
            fig.tight_layout()     
                          
            # 画面更新までの待ち時間（適宜調整）    
            plt.pause(Time_Wait)
      
            # 表示を初期化    
            ax1.cla() 
            ax2.cla() 
            ax3.cla()
            ax4.cla()           
            ax5.cla()
            ax6.cla()
        
        Counter = Counter + 1
    
except KeyboardInterrupt:
    
    db1.close()
    db3.close()
       
    print('!!!!! 割り込み発生 !!!!!')
    
finally:
   
    print('処理の終了')
    print(str(Counter) + "回の処理を実行しました")

~~~

#最後に・・
５G時代に突入し、各種のコネクテッド-X社会の到来と共に、各種のデータ流通も静かに、そして劇的・速やかにある種の革命を起こすのではないか？と考えております。
また、この世界では「データの流通過程」や「運用過程」も時代の速度や変化への柔軟な対応力を確保しなければなりません。今回数回に分けてアップデート検証を行ってきたEqualumには、その新世代データプラットホームになれる可能性や、周辺環境との高度な連携による「新たなデータドリブン環境」における「新たなDXの実現」をサポートで出来るでしょう。また、既存でBI環境が「前向きに行き詰まり」袋小路の状態に陥っている様なケースでも、EqualumをSQLトランザクション・ブリッジ＆ファイアーウォールとして展開し、データ利活用やデータ運用の仕組みを劇的に改善できるかと思います。

データの流通経路を持続発展可能なソリューションで抑えておく・・これはその周辺や新たに発生するデータ系ビジネスにおいて、大きなアドバンテージと可能性を創造し、Equalumが皆様の「次の一手」の選択の幅を皆様の「都合で選択出来る」様になる「キラーソリューション」となるのではないでしょうか？（いよいよ日本国内でも、正式な外販（SI)代理店が立ち上がる様です・・）

非常に駆け足の紹介・検証作業になりましたが、今回はひとまずこれにて一件落着！という事で・・
最後までお付き合い頂き、誠に有難うございました。

#謝辞
本検証は、Equalum社の公式バージョン（V2.２３)を利用して実施しています。
この貴重な機会を提供して頂いたEqualum社に対して感謝の意を表すると共に、本内容とEqualum社の公式ホームページで公開されている内容等が異なる場合は、Equalum社の情報が優先する事をご了解ください。