Martin’s Cloak: クラウドネイティブジオの速度を保つ

ウェブ地図において速度は機能です。Source Cooperative に集約された PMTiles ファイルを高い速度で使えるための工夫として、ユーザーの近くに Caddy にリバースプロキシされた Martin を置く手法を試してみました。

![martins-cloak.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/102082/5890a07c-6b38-44fb-a119-bb1575e8e329.jpeg)

## 対応しようとする課題
### 背景
地理空間情報をウェブで高速に使えるようにする方法として、タイル化するという方法があります。ソースデータが画像であれば画像タイル、ベクトルデータであればベクトルタイル、ラスタデータであればラスタタイルが用いられます。

タイルの切り方は事実上の標準化が進んでおり、Slippy map tilenames がよく使われています。なお、これに高さの要素等を加えたものが[空間ID](https://www.ipa.go.jp/digital/architecture/guidelines/4dspatio-temporal-guideline.html)です。

生のタイルデータはファイル数が多くなって取り回しも難しくなるので、パッケージ化して取り回しやすくすることが行われます。

SQLite 上にパッケージ化するものが MBTiles であり、HTTP range-request で静的なリソースから必要なタイルのみを取れるようにパッケージ化するものが PMTiles です。

PMTiles はクラウドネイティブフォーマットとして、例えば [Cloud-native Geospatial Forum](https://cloudnativegeo.org/) でも取り上げられています。

クラウドネイティブフォーマットは、スケーラビリティ、可用性、柔軟性に優れており、地理空間情報の利用をより広範なユーザーに開放することになるでしょう。

クラウドネイティブフォーマットのデータを広く共有するためのツールとして、[Source Cooperative](https://source.coop/)があります。このツールをうまく活用すれば、ウェブ地図に地理空間情報を供するにあたって、供する側がサーバーを準備しないと始まらない、という隘路を回避できる可能性があると考えています。Source Cooperativeは、分散型の地理空間情報共有を結果的に可能にしていく、自由で開かれたプラットフォームの一つであると考えています。

### 対応しようとする課題
Source Cooperative から PMTiles 形式の地理空間情報を共有し、それを例えば MapLibre GL JS のサイトから消費することは可能ですが、タイルデータを受け取るために必要な時間が長いです。

2025年3月現在、日本からアクセスした場合には、ブラウザ上の地図画面が埋まるまでに30秒ほどの時間がかかる事例もありました。

Source Cooperative のような自由で開かれたプラットフォームに地理空間情報を託すことは前提として堅持しながら、ウェブ地図に必要な速度を出す技術が必要でした。

## 概念
この課題に対応するために考えたのが Martin’s Cloak です。

MapLibre Organization のベクトルタイルサーバである [Martin](https://martin.maplibre.org/) を Source Cooperative とウェブ地図ユーザの間に挟むことで、Martin にタイルデータをキャッシュさせ、ウェブ地図ユーザーから見たウェブ地図の速度を保ちます。

この概念を比喩的に図にしたものが、本記事の冒頭にある画像です。

単一のサーバーでウェブサイトも提供するようにすること、HTTP/3 対応などの果実も用いること、を目的として、Martin サーバを Caddy からリバースプロキシさせています。

Martin’s Cloak によってサポートするべきユーザは、低リソースの要求者（resource-limited requester）と位置付けています。エンタープライズネットワークの中にいたり、ブロードバンドインターネット接続を持っていなかったりするユーザにこそ、ウェブ地図を必要とするユーザがいる。そういったユーザにクラウドネイティブジオの価値を届けたい、というのが Martin’s Cloak の狙いになります。

### high orbit, low orbit
Martin’s Cloak には二つのモードが考えられます。それぞれに high orbit と low orbit というコードネームをつけています。

#### High orbit mode
Martin は Source Cooperative 上のリソースの URL を知っていて、サーバのライフサイクルの範囲内でタイルをキャッシュするモード。

このモードでは、Martin’s Cloak をほぼ準備ゼロで展開することができます。また、Martin’s Cloak 自身が少ないリソースしか持っていなくても、ユーザのアクセスパターンが比較的揃ったものであれば、それなりに速度が稼げそうです。

#### Low orbit mode
サーバを起動する前に Source Cooperative 上のリソースの全部をキャッシュフォルダにダウンロードしておいて、Martin はローカルのクラウドネイティブファイルを用いてタイルを提供するモード。

このモードでは、高速なタイルを確実にユーザに届けることが可能です。ただし、数十GBから数百GBになることが多いクラウドネイティブファイルをあらかじめダウンロードする必要があります。

### 情報源
概念図のソースは、ニューヨークのメトロポリタン美術館から公開されているパブリックドメインの [Saint Martin, on horseback, giving his cloak to a beggar, angels overhead](https://www.metmuseum.org/art/collection/search/816024) です。

Martin’s Cloak のアナロジーは、ドイツなどで祝われている [Martinstag の動画](https://www.youtube.com/watch?v=x1fQFEuLDhA)を見ていただけると分かりやすいかもしれません。

## プロトタイプ
プロトタイプ実装は https://github.com/hfu/kanto に作っています。

これは、迅速測図の画像タイルに対して Martin’s Cloak を適用するプロトタイプです。簡単に実装を解説します。

### high.yaml
High orbit mode 用の Martin の設定ファイルです。

```yaml
base_path: /martin
pmtiles:
  sources:
    kanto: https://data.source.coop/wata909/historical-topomaps-jp/kanto_rapid.pmtiles
```

`base_path` を設定しているのは、提供するタイルが https://server/martin/kanto/{z}/{x}/{y} という URL になるようにメタデータを設定されるようにするためです。リバースプロキシとの関係で、この設定をしています。

`pmtiles` は、`kanto` という名前で、指定した URL の PMTiles に含まれているベクトルタイルを提供するように設定するものです。Martin は適宜 `data.source.coop` にアクセスし、メタデータやタイルを提供するように動いてくれます。 

### low.yaml
Low orbit mode 用の Martin の設定ファイルです。

```
base_path: /martin
pmtiles:
  sources:
    kanto: cache/kanto_rapid.pmtiles
```

`high.yaml` との違いは最終行だけです。オンラインの `data.source.coop` 上からメタデータやタイルを取り出す代わりに、ローカルの `cache/kanto_rapid.pmtiles` からメタデータやデータを取り出して送付します。

あわせて [Martin の configuration file のドキュメント](https://maplibre.org/martin/config-file.html) も参照していただけると理解が進むと思います。

### Caddyfile
[caddy](https://caddyserver.com/) の設定ファイルです。

```
{
}

localhost:8086

root * ./docs
file_server

handle_path /martin/* {
  reverse_proxy localhost:3000
}

handle /* {
  file_server
}
```

次の設定をしています。

- localhost の 8086　番ポートでサーバを運営すること
- `./docs` フォルダにあるファイルを提供すること
- `/martin/` 以下へのリクエストは、`/martin/` を取り外した上で、3000番ポートで動いている Martin インスタンスにリバースプロキシすること。

### Makefile
コマンドをまとめたものです。

```
high:
	martin --config high.yaml

download:
	curl -C - -o cache/kanto_rapid.pmtiles \
	https://data.source.coop/wata909/historical-topomaps-jp/kanto_rapid.pmtiles

low:
	martin --config low.yaml

caddy:
	caddy run --config Caddyfile
```

- high: Martin を high orbit mode で起動
- download: PMTiles ファイルを cache にダウンロード
  - 対象のファイルは巨大で、ダウンロードには半日以上かかります。
  - low orbit mode を動かすためには　download が必要。
- low: Martin を low orbit mode で起動
- caddy: Caddy を起動

## 使い方
```sh
git clone git@github.com/hfu/kanto
cd kanto
### high orbit mode
make high #&
make caddy #access https://localhost:8086
### low orbit mode
make download
make low #&
make caddy #access https://localhost:8086
```


## 今後の課題
- Raspberry Pi 4B または 400 で運用できるか試してみる。
  - 現時点では、MacBook Pro の上で運用しているところ。
  - Raspberry Pi 4B / 400 だと、例えばメモリやストレージ、あるいはネットワークインタフェースの貧弱さに直面してしまうかも知れない。
  - 現在の設計でも Raspberry Pi で動けば、現場に進出させるのに Raspberry Pi を使える可能性が高まるし、動かないようであれば、Raspberry Pi に合った形になるようにリソースパラメータを調整する必要がある。

### 関連する過去の教訓
- Raspberry Pi 4B で IPFS ノード実装 kubo を動かした場合、Raspberry Pi のリソースの問題に直面した。
- Raspberry Pi 4B でオブジェクトストレージ実装 [MinIO](https://min.io/) を動かしてみたところ、Raspberry Pi のリソースの問題に直面した。

### 呼びかけ
国連オープンGISイニシアティブの第７作業部会である [UN Smart Maps Group](https://unopengis.github.io/smartmaps) では、貢献を歓迎しています。

最近では、Portable Web と Generative AI に関する活動が盛んです。