概要
この記事では、WebAssemblyを使って技術的負債を解消し、モノリシック構造から脱却するための実践的なガイドを提供します。このテーマは、多くの開発者にとって重要であり、新たな可能性を探る手助けとなるでしょう。 要点のまとめ:
- WebAssemblyを活用して、クラウドやエッジデバイスにおけるセキュリティモデルを強化する方法を解説します。
- モノリシックアーキテクチャからマイクロサービスへの移行を実現し、複雑性やオーバーヘッドを軽減するための具体的な戦略が示されています。
- C++、Rust、Goなど多様な言語との連携により、Wasmエコシステムの現状や将来展望について詳しく分析しています。
WebAssemblyとは何か
技術的負債は、情報技術(IT)システムの実装に関する決定から生じます。たとえば、モノリシックなアプリケーションを構築するような慣行は、技術的負債を生み出し、将来の利益を損なうことがあります。最近注目されているWebAssembly(Wasm)という技術があるのをご存知かもしれません。このWasmは、モノリシックな構造を分解し、パフォーマンスを向上させる手助けとなり得ます。また、高効率でポータブルなコードをブラウザやサーバー、デスクトップ、モバイル端末、エッジコンピューティングさらにはIoTデバイスで普遍的に実行することで、将来的にも安心できるシステムを作ります。
技術的負債の概要
この文章では、クラウドコンピューティングの進化とともに、Wasm(WebAssembly)がどのように既存のシステムを変革し、技術的負債を軽減する可能性があるかについて説明しています。さて、Wasmは技術的負債とどのように関係しているのでしょうか?多くのシステムでは、開発者が特定のプラットフォームに結びついたモノリシックなサーバーサイドコードベースや、メンテナンスやスケールが難しい膨大なJavaScriptコードベースに依存することで技術的負債が蓄積されてしまいます。
視点の拡張比較:
項目 | 内容 |
---|---|
技術的負債の定義 | ITシステムの実装に関する不適切な決定から生じる問題 |
Wasmの利点 | 軽量で高性能なコード、モジュール化、プラットフォームロックイン回避 |
クラウドコンピューティングとエッジコンピューティング | データ処理をクライアント側に移行し、近接データ利用を可能にする技術進化 |
Wasmによる影響 | サーバーコスト削減、新しいデザイン選択肢、オフライン体験の向上 |
結果例 | 100万行Excelデータ処理が842.62ミリ秒で完了 |
モノリシックアーキテクチャの問題点
Wasmは、軽量で高性能なコードを実現できる手段を提供し、モジュール化の実装を可能にします。これにより、チームは古いコンポーネントをリファクタリングしたり置き換えたりして、現代的で効率的な代替品を構築することができます。過去数年間、多くの企業やプロジェクトがレガシーサーバーから他のクラウドソリューションへ移行してきたことが、この流れを後押ししています。その理由はいくつかあります。
まず第一に、スケーラビリティの問題があります。アプリケーション全体が一つのコードベースとして存在するため、特定の機能だけを拡張することが難しくなります。また、小さな変更でも全体を再デプロイしなくてはならないため、デプロイメントも非常に複雑になります。このような状況ではリスクも高まります。
さらに、新しい技術やフレームワークへの移行が困難になることで技術的負債が蓄積され、それが保守性にも影響を与えることがあります。このようにWasmの導入は単なる選択肢ではなく、時代遅れになったシステムから脱却するための重要なステップと言えるでしょう。
まず第一に、スケーラビリティの問題があります。アプリケーション全体が一つのコードベースとして存在するため、特定の機能だけを拡張することが難しくなります。また、小さな変更でも全体を再デプロイしなくてはならないため、デプロイメントも非常に複雑になります。このような状況ではリスクも高まります。
さらに、新しい技術やフレームワークへの移行が困難になることで技術的負債が蓄積され、それが保守性にも影響を与えることがあります。このようにWasmの導入は単なる選択肢ではなく、時代遅れになったシステムから脱却するための重要なステップと言えるでしょう。
Wasmがもたらす解決策
ほとんどの企業や政府機関は、オンサイトで自己管理するサーバーからクラウドコンピューティングソリューションに移行しています。クラウドソリューションには多くの利点があり、その一つとしてユーザー(クライアント)のデータをより近くで利用できるようになることがあります。このようなクラウドコンピューティングの進化は「エッジコンピューティング」として知られています。
クラウドコンピューティングとエッジコンピューティングの進化
エッジコンピューティングは、計算が行われる「場所」を変える技術です。具体的には、アプリケーション全体の処理負荷の一部をクライアント側のデバイスに移すことができます。このアプローチは、WebAssembly(Wasm)の利点と非常に相性が良く、高性能なコードをブラウザ上でほぼネイティブスピードで実行できるようになります。また、Wasmはプラットフォームへのロックインを回避する柔軟性も提供します。異なる言語で書かれたコードでも同じ`.wasm`ターゲットにコンパイルされれば、さまざまなオペレーティングシステムやブラウザ、ハードウェアアーキテクチャ上で問題なく動作します。過去には、クライアントデバイスが計算集約型の処理を行うという発想自体が考えられませんでしたが、この技術によってその可能性が広がっています。
Wasmによるプラットフォームロックインの回避
Wasmのおかげで、私たちはこれを実現できます。クライアントのウェブブラウザが100万行のExcelスプレッドシートを処理するところを想像してみてください。このシナリオはかなり非現実的に思えます。特に2007年以前は、`.xls`ファイル形式には各Excelスプレッドシートに65,536行という制限がありました。しかし、もうその心配はいりません。以下では、クライアントのウェブブラウザがExcelデータの100万行をわずか800ミリ秒で処理できることを示します。
## C++
ここでは私が書いたC++プログラムをご紹介します。このプログラムは以下の機能があります:
- Microsoft Excelワークブックを作成する
- 100万行のデータを生成する
- すべてのデータ値の合計を返す
- このタスクにかかった時間も返す
下記はWasmにコンパイルされるコードです:
## C++
ここでは私が書いたC++プログラムをご紹介します。このプログラムは以下の機能があります:
- Microsoft Excelワークブックを作成する
- 100万行のデータを生成する
- すべてのデータ値の合計を返す
- このタスクにかかった時間も返す
下記はWasmにコンパイルされるコードです:
#include <emscripten.h>
#include <xlnt/xlnt.hpp>
#include <thread>
#include <vector>
extern "C" {
EMSCRIPTEN_KEEPALIVE
float processSpreadsheet(float * data, int size) {
xlnt::workbook wb;
std::vector<std::thread> threads;
std::vector<float> partial_totals(4, 0.0f);
auto worker = [&](int start, int end, int thread_id) {
xlnt::workbook thread_wb;
xlnt::worksheet thread_ws = thread_wb.active_sheet();
for (int i = start; i < end; i++) {
thread_ws.cell(xlnt::cell_reference(1, i + 1)).value(data[i]);
partial_totals[thread_id] += data[i];
}
};
int num_threads = 4;
int chunk_size = size / num_threads;
for (int i = 0; i < num_threads; i++) {
int start = i * chunk_size;
int end = (i == num_threads - 1) ? size : start + chunk_size;
threads.emplace_back(worker, start, end, i);
}
for (auto & t: threads) t.join();
float total = 0.0f;
for (float part: partial_totals) total += part;
return total;
}
}
ブラウザでの高性能処理の実現
このコードは、C++用のクロスプラットフォームで使いやすい`.xlsx`ライブラリであるXLNT(トーマス・ファッセルによる)を活用しています。## C++をWasmにコンパイルするEmscriptenコマンドを使用して、C++コードをWasmターゲット(`.wasm`実行可能ファイル)にコンパイルし、WebブラウザでこのC++コードを使用できるように必要なJavaScript(`.js`ファイル)も生成します:
em++ src/spreadsheet.cpp \ -s EXPORTED_FUNCTIONS='["_processSpreadsheet", "_malloc", "_free"]' \ -s EXPORTED_RUNTIME_METHODS='["ccall", "cwrap", "allocate", "getValue"]' \ -s USE_ZLIB=1 -s WASM=1 -s MODULARIZE=1 -s EXPORT_NAME='createModule' \ -s USE_PTHREADS=1 \ -msimd128 \ -s PTHREAD_POOL_SIZE=4 \ -s INITIAL_MEMORY=536870912 \ -s MAXIMUM_MEMORY=1073741824 \ -s ALLOW_MEMORY_GROWTH=1 \ -I/Users/tpmccallum/webassembly-spreadsheet-engine/xlnt/include \ -L/Users/tpmccallum/webassembly-spreadsheet-engine/xlnt/source -lxlnt \ -o web/spreadsheet.js -O3
## HTML以下のHTMLは、このC++コード(WasmおよびJavaScript形式)とウェブブラウザ上でインタラクションできるように設計されています:<!DOCTYPE html><html lang="ja"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>WASM スプレッドシートプロセッサ</title> <!-- Bootstrap 5 CDN --> <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"> <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script></head><body class="bg-light"><div class="container text-center mt-5"> <h1 class="mb-4">C++ を使って WASM 上で100万レコード処理</h1> <div class="input-group mb-3 w-50 mx-auto"> <input type="number" id="rowCount" class="form-control" value="1000000" min="1" max="10000000"> <button id="processButton" class="btn btn-primary" onclick="processData()" disabled>処理開始</button> </div> <pre id="output" class="alert alert-secondary p-3">結果がここに表示されます...</pre> <p class="fw-bold">時間: <span id="time">0</span> ms</p></div><script src="spreadsheet.js"></script><script> let Module; createModule().then((module) => { Module = module; console.log("WASM 準備完了"); window.malloc = Module._malloc; window.free = Module._free; document.getElementById('processButton').disabled = false; }).catch((e) => { console.error("WASM 初期化失敗:", e); });
C++からWasmへのコンパイル手順
function processData() { const rowCount = parseInt(document.getElementById('rowCount').value); const data = new Float32Array(rowCount).map(() => Math.random() * 1000); const start = performance.now(); const ptr = malloc(data.length * data.BYTES_PER_ELEMENT); const batchSize = 100000; const totalSize = data.length; const chunkCount = Math.ceil(totalSize / batchSize); for (let i = 0; i < chunkCount; i++) { const startIdx = i * batchSize; const endIdx = Math.min(startIdx + batchSize, totalSize); const chunk = data.subarray(startIdx, endIdx); Module.HEAPF32.set(chunk, ptr / 4 + startIdx); document.getElementById('output').textContent = `チャンク ${i + 1}/${chunkCount} を処理中...`; } const result = Module.ccall('processSpreadsheet', 'number', ['number', 'number'], [ptr, data.length]); free(ptr); document.getElementById('output').textContent = `合計: ${result.toFixed(2)}`; const time = performance.now() - start; document.getElementById('time').textContent = time.toFixed(2);
HTMLを使ったインタラクティブな体験
私は「1000000」を入力して、「処理」ボタンをクリックしました。その結果、100万行のExcelデータを生成するのにわずか「842.62」ミリ秒かかったことが分かりました。また、全ての行の合計は「500210272.00」となりました。興味を持って、異なる行数で試してみることにしました。以下はその結果です:
行数 | ミリ秒10 | 1.34100 | 1.861000 | 2.3110000 | 10.76100000 | 82.551000000 | 842.62
Wasmで得られる利点と今後の展望
ブラウザ内での処理能力をWasmで活用することによって、計算集約型タスクにおいて大きな利点が得られます。これまでサーバー側で実行していたタスクが、今ではどこでも動作可能になりました。画像レンダリングや動画エンコーディング、音声処理など、多岐にわたる作業が可能です。この変化はサーバーコストを削減し、全く新しいデザインの選択肢を提供し、オフラインでもシームレスな体験を確保します。技術的負債は利益を損なうものですから、新たな選択肢が増えた今、自分たちの「普通」を再考してみてください。
参考記事
303 results
本書では、簡単なゲーム開発を通じて、JavaScriptやTypeScriptを使わずに、安全性、高速性、並列性で定評のあるRustを使って、従来より高速かつ安全にブラウザを動かす方法 ...
ソース: O'Reilly Media記事一覧 | レバテックラボ(レバテックLAB)
... 負債にどう向き合うか。ログラス・カミナシが語る、技術的負債をコントロールする方法. 2025年2月28日. “糸”コンピュータ? マイコンや通信機器を1本の繊維型に。服に編 ...
ソース: レバテック
関連ディスカッション