18
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

MIERUNEAdvent Calendar 2023

Day 2

PMTilesでサーバーレスなタイルサーバーをつくる

Last updated at Posted at 2023-12-01

はじめに

「サーバーレスなタイルサーバー」とかいう1行で矛盾しているタイトルでお送りします。
さて、最近話題に事欠かないPMTilesですが、そのユースケースは大体、クライアントからPMTilesが配信されているサーバーへ直接リクエストしてタイルデータを得る、というパターンです。最もシンプルにタイル配信出来るので、間違いなくベストプラクティスと言えるでしょう。

本記事ではあえて、PMTilesを用いた「タイルサーバー」を作る方法と意図を述べます。

タイルサーバーとは

本記事のタイルサーバーとは、{z}/{x}/{y}のリクエストに対してタイルデータをレスポンスするサーバーのことを指すこととします。

たとえば所定のディレクトリ構造で配置したタイルデータを配信するウェブサーバーは、まさにタイルサーバーと言えます。PMTiles以前の、静的タイルの配信のベストプラクティスでした。

全球など広範囲のタイルになるとファイルの数が膨大になってしまい、ファイルの生成・アップロードに大きなコストを要するため、MBTilesを作成してタイルを配信するサーバーを実装することもありました。サーバーレスの文脈では、ジオロニアさんのtileserverlessが記憶にあります。

PMTilesでサーバーレスなタイルサーバー

tileserverlessはAWS Lambdaを用いたサーバーレス実装ですが、MBTilesを利用しているのでEFSが必要なのがネックです(実体がSQLiteでありファイルシステムが必要であるため)。PMTilesなら、たとえばS3に置いておき、LambdaからRange-Requestを行うことが出来ます。EFSがいらなくなって、もっとサーバーレスになってうれしい。以下はHonoによる実装例(かなり端折ってますが本質部分は読めるはず)。

import { Hono } from 'hono';
import { PMTiles } from 'pmtiles';

const app = new Hono();

app.get('/tiles/:id/:z/:x/:y', async (c) => {
    const id = c.req.param('id'); // タイルの識別子
    const z = Number(c.req.param('z'));
    const x = Number(c.req.param('x'));
    const y = Number(c.req.param('y'));

    const url = await getPresignedUrl(id); // S3の署名付きURLを得る
    const pmtiles = new PMTiles(url);
    const tile = await pmtiles.getZxy(z, x, y);

    if (tile === undefined) return c.text('tile not found', 404);
    return c.body(Buffer.from(tile.data), 200, {
        'Content-Type': 'application/vnd.mapbox-vector-tile',
    });
});

他のサービスと組み合わせると以下のような構成になります。

Lambda->S3はけっこう速いので、タイルのレスポンスも速いです、うれしい。CloudFrontでキャッシュしてあげるともっとうれしくなります。CloudFromt->Lambdaという動線は、Function URLを使うと実現出来ます。API Gatewayが必要なくなりうれしいです。

上記はNode.js + Lambdaのコード例ですが、筆者はCloudflare WorkersとR2でも動かしたりしています。安くて良いです(が、AWSの方が速いです)。

PMTilesなのになぜサーバー?という問いに対しての回答:

  • クライアントにPMTilesの実装を要求する
  • キャッシュとか認証とか入れたい

前者はわかりやすくて、例えばPMTilesを読む事例ではMapLibre GL JSがよく登場しますが、MapLibre GL JSはPMTilesをサポートしていません(プラグインが実装されているだけ)。同じく、QGISもまだPMTilesを読むことは出来ません(いずれ出来るようになるでしょうけど)。特殊な実装を要求するという点は明確なデメリットです。

後者はあまり思いつかなかったのでこじつけですが、サーバー実装が必要なときってありますよね。

追記:
PMTilesの実体を隠せるので、タイルデータ全体をダウンロードされてしまうとかいう事態を避けられることもメリットのひとつですね

18
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?