プログラマーのメモ書き

伊勢在住のプログラマーが気になることを気ままにメモったブログです

OpenStreetMap タイルサーバー:地図データの再セットアップ

以前、こちらの記事で書いたように、 OpenStreetMap のタイルサーバーをほそぼそと運用しています。

最近、Postgresql のDB容量が非常に大きくなって、ディスク容量不足で、地図データの更新ができなくなってしまいました。削除前は、 postgresql だけで 100GB 超えるディスク使用量でした。

mor@map:~$ sudo du -h -s /var/lib/postgresql/
108G    /var/lib/postgresql/
mor@map:~$ 

ディスクの容量を増やそうか、これを機に EC2 などでの運用に切り替えようかいろいろと悩んだのですが、最終的には、

  • ハードウェアおよび既存のインストールしてあるソフトウェアは、なるべく今あるものをそのまま利用する
  • 地図データを再セットアップし、DB容量をスリムにする

という方針にして、地図データを再セットアップすることにしました。ということで、今回はタイルサーバーの地図データの再セットアップを行った際のメモをまとめておきます。

事前調査

最初にタイルサーバーをセットアップしたのが2017年12月頃だったので、ずいぶんと立ってます。なので、まず、以前にインストールしたものと最新版の比較をして、準備するべきことがないか確認します。

ソフトウェア セットアップ時(2017/12頃) 現時点(2020/9頃) 備考
Postgresql v9.5 v12
mod_tile & renderd
(SomeoneElseOSM版)
旧masterブランチ(現switch2osm)
7b284e9
現switch2osm ブランチ
aa3d8ed
ブランチ名に変更があった
更新スクリプト周りで若干コミットがある
Mapnik v3.0.9 v.3.0.23
osm2pgsql v0.95.0-dev
(da50b02)
v1.3.0 リポジトリから最新版を利用
openstreetmap-carto v4.6.0
(ac7d4fb)
v5.2.0+ + はリリース版から進んでいることを示す
リポジトリから最新版を利用
CartoCSS (carto) v0.18.2 v1.2.0

この中でも openstreetmap-carto が 2020/4/27 のコミットで、シェープファイルのダウンロードとその扱いを大きく変更しています(2019/3/31 のコミットでダウンロード先自体も切り替わってますし、その後も特定のファイルを使わなくなったりいろいろと変わってます)。

なので、 openstreetmap-carto については、最新版を使うようにして、その他は既存のままで運用しようと思います(openstreetmap-carto については CartoCSS が 0.18.0 以上, Mapnik が 3.0 以上であれば良さそうなので)。

今回は特に追加のライブラリ等はありませんでしたが、 openstreetmap-carto が v5.0.0 あたりで python3 ベースに切り替わっているので、必要があれば関連するライブラリ等もインストールしておきます。

再セットアップ作業

再セットアップは大まかに次のように進めます。

  1. 作業に先立ち準備
  2. 既存のデータベース(gis)を削除して、ディスク容量を回復
  3. 再度 gis データベースを作成
  4. 最新の openstreetmap-carto によるスタイルシートを作成
  5. 日本の地図データ(再セットアップ時の最新データ)を投入
  6. 最新の openstreetmap-carto によるシェープファイルを設定
  7. タイルサーバーを再起動

準備

まずは、作業時にトラブらないように、地図データの更新を停止します。

crontab を編集して、

osm@map:~$ crontab -e

コメントアウトしておきます。

# comment out for rebuilding gis db, 2020/9/7
#6 */1 * * *  /home/osm/bin/osm-tile-update-expire-w-mail > /dev/null 2>&1
crontab: installing new crontab
osm@map:~$ 

なお、 osm-tile-update-expire-w-mail は、内部で openstreetmap-tiles-update-expire スクリプトを呼び出し、エラーがあった場合はメールを送信するためのスクリプトです。

gis データベースの削除

次に、postgressqlのデータベースを削除し、再作成します。ですが、いきなり dropdb を実行してもできませんでした。

osm@map:~$ dropdb gis
dropdb: database removal failed: ERROR:  database "gis" is being accessed by other users
DETAIL:  There are 2 other sessions using the database.
osm@map:~$ 

なので、一旦 apache と renderd を止めます。

mor@map:~$ sudo service apache2 stop
mor@map:~$ sudo service renderd stop

もういちど、 dropdb を行います

mor@map:~$ su - osm
パスワード: 
osm@map:~$ dropdb gis

削除できました。

ちなみに、削除前のテーブル構成はこんな感じでした。

osm@map:~$ psql -d gis
psql (9.5.23)
Type "help" for help.

gis=> \d
               List of relations
 Schema |        Name        | Type  |  Owner   
--------+--------------------+-------+----------
 public | geography_columns  | view  | postgres
 public | geometry_columns   | view  | osm
 public | planet_osm_line    | table | osm
 public | planet_osm_nodes   | table | osm
 public | planet_osm_point   | table | osm
 public | planet_osm_polygon | table | osm
 public | planet_osm_rels    | table | osm
 public | planet_osm_roads   | table | osm
 public | planet_osm_ways    | table | osm
 public | raster_columns     | view  | postgres
 public | raster_overviews   | view  | postgres
 public | spatial_ref_sys    | table | osm
(12 rows)

gis=> 

postgres の場合、データベースを削除してもディスクがOSに戻されないようです。そいうときは、 vacuum をやるとよいようです。

mor@map:~$ sudo -u postgres -i
postgres@map:~$ vacuumdb --full

しかし、ディスク容量を見てもほとんど減ってない・・・

mor@map:~$ sudo du -h -s /var/lib/postgresql/
105M    /var/lib/postgresql/
mor@map:~$ 

vacuumdb ではなく vacuum を試したり postgres のプロセスをいったん止めたりしても変わらずでした。とここで困ってしまいました。

postgres でディスク容量を回復するために

postgres 普段使ってないので、慌ててあれこれと調べてみると、下記の記事の方法を参考にしたら、データベース削除後でもなんとかディスク容量を回復できそうなことがわかりました。

おもっきり要約すると、バックアップを取り、データ保存のディレクトリを削除してから、再度初期化する、という方法のようです。

ただ、Ubuntu の Postgresql の場合は initdb コマンドが見つからない(こちらの記事などを参照)のと、直接ディレクトリを削除するのは抵抗あるな、と思っていろいろと調べていたら、下記記事に pg_dropcluster を使った postgres のデータ保管場所を変更する方法が載っていたので、

User:Ngt - OpenStreetMap Wiki

これを参考にして、 pg_dropcluster / pg_createcluster (Ubuntu の postgresql 用のコマンド)を使っての作業としてやってみました。

作業前に現在のクラスターの情報を表示してみます。

mor@map:~$ pg_lsclusters
Ver Cluster Port Status Owner    Data directory               Log file
9.5 main    5432 online postgres /var/lib/postgresql/9.5/main /var/log/postgresql/postgresql-9.5-main.log
mor@map:~$ 

上記の記事にもあるように念のためバックアップを取っておきます(結局、今回は使いませんでしたが)。バックアップ先は /home/osm/tmp/archive/ としてだれでも書き込めるようにしておきます。

mor@map:~$ sudo -u postgres -i
postgres@map:~$ pg_dumpall | gzip -9 > /home/osm/tmp/archive/all.dbs.gz
postgres@map:~$ exit
ログアウト
mor@map:~$ sudo ls -l /var/lib/postgresql/9.5/main/
合計 84
-rw------- 1 postgres postgres    4 1227  2017 PG_VERSION
drwx------ 6 postgres postgres 4096  97 11:54 base
drwx------ 2 postgres postgres 4096  97 14:32 global
drwx------ 2 postgres postgres 4096  79 23:19 pg_clog
drwx------ 2 postgres postgres 4096 1227  2017 pg_commit_ts
drwx------ 2 postgres postgres 4096 1227  2017 pg_dynshmem
drwx------ 4 postgres postgres 4096 1227  2017 pg_logical
drwx------ 4 postgres postgres 4096 1227  2017 pg_multixact
drwx------ 2 postgres postgres 4096  97 14:11 pg_notify
drwx------ 2 postgres postgres 4096 1227  2017 pg_replslot
drwx------ 2 postgres postgres 4096 1227  2017 pg_serial
drwx------ 2 postgres postgres 4096 1227  2017 pg_snapshots
drwx------ 2 postgres postgres 4096  97 14:11 pg_stat
drwx------ 2 postgres postgres 4096 1227  2017 pg_stat_tmp
drwx------ 2 postgres postgres 4096  820 14:42 pg_subtrans
drwx------ 2 postgres postgres 4096 1227  2017 pg_tblspc
drwx------ 2 postgres postgres 4096 1227  2017 pg_twophase
drwx------ 3 postgres postgres 4096  94 22:58 pg_xlog
-rw------- 1 postgres postgres   88 1227  2017 postgresql.auto.conf
-rw------- 1 postgres postgres  133  97 14:11 postmaster.opts
-rw------- 1 postgres postgres  101  97 14:11 postmaster.pid
mor@map:~$ 
mor@map:~$ sudo cp -p /var/lib/postgresql/9.5/main/postgresql.auto.conf /home/osm/tmp/archive/
mor@map:~$ mkdir /home/osm/tmp/archive/etc/
mor@map:~$ sudo cp -p /etc/postgresql/9.5/main/* /home/osm/tmp/archive/etc/
mor@map:~$ 

って感じです。

次はクラスターの削除です。

mor@map:~$ sudo -u postgres -i
postgres@map:~$ pg_dropcluster --stop 9.5 main
Warning: stopping the cluster using pg_ctlcluster will mark the systemd unit as failed. Consider using systemctl:
  sudo systemctl stop postgresql@9.5-main
Warning: systemd was not informed about the removed yet. Operations like "service postgresql start" might fail. To fix, run:
  sudo systemctl daemon-reload
postgres@map:~$ exit
ログアウト
mor@map:~$ sudo du -h -s /var/lib/postgresql/
12K     /var/lib/postgresql/
mor@map:~$ df -h
Filesystem                Size  Used Avail Use% Mounted on
udev                      3.9G     0  3.9G   0% /dev
tmpfs                     799M   27M  772M   4% /run
/dev/mapper/map--vg-root  138G   23G  109G  18% /
tmpfs                     3.9G     0  3.9G   0% /dev/shm
tmpfs                     5.0M     0  5.0M   0% /run/lock
tmpfs                     3.9G     0  3.9G   0% /sys/fs/cgroup
/dev/sda1                 472M  161M  287M  36% /boot
tmpfs                     799M     0  799M   0% /run/user/1000
mor@map:~$ 

無事にクラスターで使っていた領域が削除され、ディスク容量が空きました。

クラスターを再作成します。

mor@map:~$ sudo -u postgres -i
postgres@map:~$ pg_createcluster 9.5 main
Creating new cluster 9.5/main ...
  config /etc/postgresql/9.5/main
  data   /var/lib/postgresql/9.5/main
  locale ja_JP.UTF-8
  socket /var/run/postgresql
  port   5432
Warning: systemd does not know about the new cluster yet. Operations like "service postgresql start" will not handle it. To fix, run:
  sudo systemctl daemon-reload
postgres@map:~$ 

warning があるように postgres がうまく再起動できていないので、手作業で再起動しておきます。

mor@map:~$ sudo service postgresql restart

この状態で、現在のデータベースを表示させると、

mor@map:~$ sudo -u postgres -i
postgres@map:~$ psql -l
                                  List of databases
   Name    |  Owner   | Encoding |   Collate   |    Ctype    |   Access privileges   
-----------+----------+----------+-------------+-------------+-----------------------
 postgres  | postgres | UTF8     | ja_JP.UTF-8 | ja_JP.UTF-8 | 
 template0 | postgres | UTF8     | ja_JP.UTF-8 | ja_JP.UTF-8 | =c/postgres          +
           |          |          |             |             | postgres=CTc/postgres
 template1 | postgres | UTF8     | ja_JP.UTF-8 | ja_JP.UTF-8 | =c/postgres          +
           |          |          |             |             | postgres=CTc/postgres
(3 rows)

postgres@map:~$ 

となり、gis データベース削除前のセットアップ直後と同じになってました。

再作成したクラスターの情報も見ておきます。

mor@map:~$ pg_lsclusters
Ver Cluster Port Status Owner    Data directory               Log file
9.5 main    5432 online postgres /var/lib/postgresql/9.5/main /var/log/postgresql/postgresql-9.5-main.log
mor@map:~$ 

削除前と同じですね。

これで最初の状態(postgresをインストールした直後の状態)に戻ったと思います(思いたいです)。 結局のところ、どうも postgres の場合は、データベースを消してからディスク容量を回復させるのではなく、データベースを消す前に一旦テーブルの中身を削除して、 vacuum full とかで容量を回復してから、データベースを消すのが比較的楽だったように思えます。もっとも、これもまだ試してないので、次回の機会に試すことにしたいと思います。

ちなみに、使用しているクラスターに他で利用しているデータベースとかがあると、気軽に再作成というわけにはいかないので、この方法だと難しいかもしれません。今回の場合は、 OpenStreetMap のタイルサーバー用のデータベースだけなので、比較的問題なく進めた印象です。

gis データベースの再作成

ここからはタイルサーバーのセットアップ方法に従って gis データベースを作っておきます。

db 用のユーザーが残っているか確認します。

mor@map:~$ sudo -u postgres -i
[sudo] mor のパスワード: 
postgres@map:~$ psql
psql (9.5.23)
Type "help" for help.

postgres=# \du
                                   List of roles
 Role name |                         Attributes                         | Member of 
-----------+------------------------------------------------------------+-----------
 postgres  | Superuser, Create role, Create DB, Replication, Bypass RLS | {}

postgres=# 

ユーザーも消えてますね。クラスター毎削除しているので当たり前といえば当たり前ですかね。なので、ユーザーを作成するところからもう一度やります。

mor@map:~$ sudo -u postgres -i
postgres@map:~$ 
postgres@map:~$ createuser osm
postgres@map:~$ createdb -E UTF8 -O osm gis
postgres@map:~$ psql
psql (9.5.23)
Type "help" for help.

postgres=# \c gis
You are now connected to database "gis" as user "postgres".
gis=# \d
No relations found.
gis=# CREATE EXTENSION postgis;
CREATE EXTENSION
gis=# \d
               List of relations
 Schema |       Name        | Type  |  Owner   
--------+-------------------+-------+----------
 public | geography_columns | view  | postgres
 public | geometry_columns  | view  | postgres
 public | raster_columns    | view  | postgres
 public | raster_overviews  | view  | postgres
 public | spatial_ref_sys   | table | postgres
(5 rows)

gis=# CREATE EXTENSION hstore;
CREATE EXTENSION
gis=# \d
               List of relations
 Schema |       Name        | Type  |  Owner   
--------+-------------------+-------+----------
 public | geography_columns | view  | postgres
 public | geometry_columns  | view  | postgres
 public | raster_columns    | view  | postgres
 public | raster_overviews  | view  | postgres
 public | spatial_ref_sys   | table | postgres
(5 rows)

gis=# ALTER TABLE geometry_columns OWNER TO osm;
ALTER TABLE
gis=# ALTER TABLE spatial_ref_sys OWNER TO osm;
ALTER TABLE
gis=# \d
               List of relations
 Schema |       Name        | Type  |  Owner   
--------+-------------------+-------+----------
 public | geography_columns | view  | postgres
 public | geometry_columns  | view  | osm
 public | raster_columns    | view  | postgres
 public | raster_overviews  | view  | postgres
 public | spatial_ref_sys   | table | osm
(5 rows)

gis=# \q
postgres@map:~$ exit

作業ごとにテーブルを表示しているのは、どんなものが作られているのか見てみたかったからですので、それ以上の他意はありません。

最新の openstreetmap-carto によるスタイルシートの作成

最新の openstreetmap-carto をインストールする前に、既存の openstreetmap-carto の退避しておきます。

osm@map:~/src$ mv openstreetmap-carto/ openstreetmap-carto.old/

最新のリポジトリを clone します。

osm@map:~/src$ git clone git://github.com/gravitystorm/openstreetmap-carto.git
Cloning into 'openstreetmap-carto'...
remote: Enumerating objects: 6, done.
remote: Counting objects: 100% (6/6), done.
remote: Compressing objects: 100% (6/6), done.
remote: Total 15162 (delta 1), reused 0 (delta 0), pack-reused 15156
Receiving objects: 100% (15162/15162), 14.99 MiB | 5.48 MiB/s, done.
Resolving deltas: 100% (10353/10353), done.
Checking connectivity... done.
osm@map:~/src$ 

スタイルシートを生成します。

osm@map:~/src$ cd openstreetmap-carto
osm@map:~/src/openstreetmap-carto$ carto project.mml > mapnik.xml
osm@map:~/src/openstreetmap-carto$ 

最新の地図データの投入

改めて、今日(2020/9/7)時点の、日本の pbf ファイルをダウンロードします。

osm@map:~$ cd data/
osm@map:~/data$ mv japan-latest.osm.pbf japan-latest.osm.pbf.20171227
osm@map:~/data$ wget https://download.geofabrik.de/asia/japan-latest.osm.pbf

地図データを db へインポートします。前回の記事とほとんど同じですが、メモリとプロセッサ数を多く割り当ててます。

osm@map:~$ osm2pgsql -d gis --create --slim  -G --hstore --tag-transform-script ~/src/openstreetmap-carto/openstreetmap-carto.lua -C 7500 --number-processes 4 -S ~/src/openstreetmap-carto/openstreetmap-carto.style ~/data/japan-latest.osm.pbf
osm2pgsql version 0.95.0-dev (64 bit id space)

Using lua based tag processing pipeline with script /home/osm/src/openstreetmap-carto/openstreetmap-carto.lua
Using projection SRS 3857 (Spherical Mercator)
(中略)
node cache: stored: 191123228(100.00%), storage efficiency: 52.57% (dense blocks: 6600, sparse nodes: 154735389), hit rate: 100.00%

Osm2pgsql took 12846s overall
osm@map:~$ 

今回は3時間半ぐらいでした。

新しい openstreetmap-carto によるシェープファイルの設定

openstreetmap-carto のスクリプトを利用して、必要なシェープファイルをダウンロードします。前回のセットアップ時とはこの部分が異なっています。

osm@map:~/src/openstreetmap-carto$ ./scripts/get-external-data.py 
/home/osm/.local/lib/python3.5/site-packages/psycopg2/__init__.py:144: UserWarning: The psycopg2 wheel package will be renamed from release 2.8; in order to keep installing from binary please use "pip install psycopg2-binary" instead. For details see: <http://initd.org/psycopg/docs/install.html#binary-install-from-pypi>.
  """)
INFO:root:Checking table water_polygons
INFO:root:Checking table icesheet_outlines
INFO:root:Checking table simplified_water_polygons
INFO:root:Checking table ne_110m_admin_0_boundary_lines_land
INFO:root:Checking table icesheet_polygons
osm@map:~/src/openstreetmap-carto$ 

これで、地図データの再セットアップが完了したはずです。

動作確認

早速、動作確認します。

renderd および apache2 を起動します。

mor@map:~$ sudo service apache2 start
mor@map:~$ sudo service renderd start

テスト用に接続してみます。 問題なく地図データが表示されることが確認できました。

地図データの再セットアップ後のディスク容量としては、

mor@map:/var/lib/postgresql$ sudo du -h -s ./*
[sudo] mor のパスワード: 
40G     ./9.5
mor@map:/var/lib/postgresql$ 

ずいぶんと減りました。

地図データの更新設定

以前行ったタイルサーバーの更新設定の記事を参考にして、 mod_tile/openstreetmap-tiles-update-expire を利用した地図データの更新を有効にします。

今回も更新間隔は、以前と同じく hourly にします。ちなみに、更新間隔はそんなに頻繁でなくてもいいと思うので、実は一度 daily にして試したのですが、処理途中でメモリが足りなくてきちんと終了できなかったので、諦めました。

なお、タイルサーバーの更新設定の記事の中で参考にしていた更新手順の説明へのリンクが切れています。いまだと、下記のURLなどがまとまっているようです。

Keeping the local database in sync with OSM | OpenStreetMap Carto Tutorials

mod_tile リポジトリの更新

mod_tile のリポジトリをみると、スクリプトがいくつか更新されているので、最新にしておきます。

osm@map:~/src/mod_tile$ 
osm@map:~/src/mod_tile$ git branch --all
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/master
  remotes/origin/zoom
osm@map:~/src/mod_tile$ git fetch
remote: Enumerating objects: 35, done.
remote: Counting objects: 100% (35/35), done.
remote: Total 56 (delta 35), reused 35 (delta 35), pack-reused 21
Unpacking objects: 100% (56/56), done.
From git://github.com/SomeoneElseOSM/mod_tile
 + 7b284e9...e25bfdb master     -> origin/master  (forced update)
 * [new branch]      switch2osm -> origin/switch2osm
 * [new branch]      typos_etc  -> origin/typos_etc
   140bedc..7fe2f03  zoom       -> origin/zoom
osm@map:~/src/mod_tile$ 
osm@map:~/src/mod_tile$ git branch --all
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/master
  remotes/origin/switch2osm
  remotes/origin/typos_etc
  remotes/origin/zoom
osm@map:~/src/mod_tile$ 

そのうえで、リモートブランチ switch2osm に切り替えます。

osm@map:~/src/mod_tile$ git checkout -b switch2osm origin/switch2osm
M       debian/renderd.init
Branch switch2osm set up to track remote branch switch2osm from origin.
Switched to a new branch 'switch2osm'
osm@map:~/src/mod_tile$ 

これは、以前の記事の時点だと、 master ブランチからcloneしていたのが、switch2osmブランチからcloneするように変わっているのに対応するためです。

必要に応じて openstreetmap-tiles-update-expire のスクリプトを修正しておきます。修正内容は、タイルサーバーの更新失敗で対応した記事の通りです。

設定ファイルの修正

次に、どこまでの差分が反映されているかの設定ファイル(state.txt)を再作成します(やり方は以前行ったタイルサーバーの更新設定の記事に準じています)。

今回の地図データは 2020/9/7 時点のデータをダウンロードしていたので、 2020/9/6 時点の state.txt を取得し作成します。

osm@map:~/src/mod_tile$ cd /var/lib/mod_tile/.osmosis/
osm@map:/var/lib/mod_tile/.osmosis$ wget https://planet.openstreetmap.org/replication/hour/000/070/000.state.txt
--2020-09-08 11:36:23--  https://planet.openstreetmap.org/replication/hour/000/070/000.state.txt
planet.openstreetmap.org (planet.openstreetmap.org) をDNSに問いあわせています... 130.117.76.10, 2001:978:2:2c::172:a
planet.openstreetmap.org (planet.openstreetmap.org)|130.117.76.10|:443 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 84 [text/plain]
`000.state.txt' に保存中

000.state.txt                                 100%[=================================================================================================>]      84  --.-KB/s    時間 0s    

2020-09-08 11:36:24 (11.6 MB/s) - `000.state.txt' へ保存完了 [84/84]

osm@map:/var/lib/mod_tile/.osmosis$ cat 000.state.txt 
#Sun Sep 06 23:02:09 UTC 2020
sequenceNumber=70000
timestamp=2020-09-06T23\:00\:00Z
osm@map:/var/lib/mod_tile/.osmosis$ mv 000.state.txt state.txt

設定ファイルのほうは変更ありません(一応、設定内容を掲載しておきます)。

osm@map:/var/lib/mod_tile/.osmosis$ cat configuration.txt
# The URL of the directory containing change files.
baseUrl=https://planet.openstreetmap.org/replication/hour

# Defines the maximum time interval in seconds to download in a single invocation.
# Setting to 0 disables this feature.
#maxInterval = 3600
#maxInterval = 7200
maxInterval = 14400
osm@map:/var/lib/mod_tile/.osmosis$ 
補足

なお、上記では欲しい日時の state.txt を直接取得していますが、下記のURLを呼び出せば、wgetで取得しなくても、state.txtの内容を得ることができます。

replicate-sequences

また、 openstreetmap-tiles-update-expire スクリプトを 日付の引数付き(yyyy-mm-dd の形式で与える)で呼び出しても、初期化の過程で引数のstate.txtを作成してくれます。

例えば、こんな感じになります。

osm@map:~/tmp/mod_tile$ ./openstreetmap-tiles-update-expire 2020-09-07
--2020-09-08 13:41:24--  http://replicate-sequences.osm.mazdermind.de/?2020-09-07T00:00:00Z
replicate-sequences.osm.mazdermind.de (replicate-sequences.osm.mazdermind.de) をDNSに問いあわせています... 188.68.50.52, 2a03:4000:6:d080::1
replicate-sequences.osm.mazdermind.de (replicate-sequences.osm.mazdermind.de)|188.68.50.52|:80 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 301 Moved Permanently
場所: https://replicate-sequences.osm.mazdermind.de/?2020-09-07T00:00:00Z [続く]
--2020-09-08 13:41:25--  https://replicate-sequences.osm.mazdermind.de/?2020-09-07T00:00:00Z
replicate-sequences.osm.mazdermind.de (replicate-sequences.osm.mazdermind.de)|188.68.50.52|:443 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 332 [text/plain]
`/home/osm/tmp/jm//.osmosis/state.txt' に保存中

/home/osm/tmp/jm//.osmosis/state.txt          100%[=================================================================================================>]     332  --.-KB/s    時間 0s    

2020-09-08 13:41:26 (42.1 MB/s) - `/home/osm/tmp/jm//.osmosis/state.txt' へ保存完了 [332/332]

osm@map:~/tmp/mod_tile$ 

スクリプトで指定した作業ディレクトリ(この例では ~/tmp/jm/.osmosis/ )が作られ、その中には

osm@map:~/tmp/jm$ ls -laF .osmosis/
合計 20
drwxrwxr-x 2 osm osm 4096  98 13:41 ./
drwxrwxr-x 4 osm osm 4096  98 13:41 ../
-rw-rw-r-- 1 osm osm  253  98 13:41 configuration.txt
-rw-rw-r-- 1 osm osm  253  98 13:41 configuration_orig.txt
-rw-rw-r-- 1 osm osm    0  98 13:41 download.lock
-rw-rw-r-- 1 osm osm  332  98 13:41 state.txt
osm@map:~/tmp/jm$ 

といくつかのファイルができています。configuration.txt と state.txt を見ると下記のようになっていました。

configuration.txt の URL は minutely のものになっています。

osm@map:~/tmp/jm/.osmosis$ cat configuration.txt 
# The URL of the directory containing change files.
baseUrl=https://planet.openstreetmap.org/replication/minute

# Defines the maximum time interval in seconds to download in a single invocation.
# Setting to 0 disables this feature.
maxInterval = 3600
osm@map:~/tmp/jm/.osmosis$ 

state.txt は引数で与えた日付けに対する minutely のファイルになります。

osm@map:~/tmp/jm/.osmosis$ cat state.txt 
#original-source: http://planet.openstreetmap.org/replication/minute/004/184/319.state.txt
#generated-by: https://replicate-sequences.osm.mazdermind.de/?2020-09-07T00:00:00Z
#Sun Sep 06 23:59:03 UTC 2020
sequenceNumber=4184319
txnMaxQueried=3010675683
txnActiveList=
txnReadyList=
txnMax=3010675683
timestamp=2020-09-06T23\:59\:02Z
osm@map:~/tmp/jm/.osmosis$ 

これらを使って初期化するのもありかと思います。

テスト

一度、マニュアルで実行します

osm@map:~/src/mod_tile$ ./openstreetmap-tiles-update-expire
osm@map:~/src/mod_tile$ 

特にエラー等が表示されず、ログファイルにもエラーが記録されていなければ、問題ないと思います。 問題なければ、 crontab を編集して、定期的に実行するようにします。

# m h  dom mon dow   command
#6 */1 * * *  /home/osm/src/mod_tile/openstreetmap-tiles-update-expire > /dev/null 2>&1
#
# this script run openstreetmap-tiles-update-expire to send email if failed
# Junichi MORI, 2020/9/8
6 */1 * * *  /home/osm/bin/osm-tile-update-expire-w-mail > /dev/null 2>&1

postgres の autovacuum を設定

恥ずかしながら、今回の作業時まで、 postgres の場合は削除とか更新の際に、古いデータが消されずに追記されるということを知りませんでした。 データベースの動作がこれを前提にしているので、ディスク容量が過剰に増えないように、自動的に不要領域の回収を行う機能もついてるようです(自動バキューム)。 デフォルトでも有効という情報もちらほら見かけますが、念のため、設定ファイルでこれを有効にしたいと思います。

/etc/postgres/9.5/main/postgresql.conf

#------------------------------------------------------------------------------
# RUNTIME STATISTICS
#------------------------------------------------------------------------------

# - Query/Index Statistics Collector -

#track_activities = on
track_counts = on
(中略)
#------------------------------------------------------------------------------
# AUTOVACUUM PARAMETERS
#------------------------------------------------------------------------------

autovacuum = on                         # Enable autovacuum subprocess?  'on'
                                        # requires track_counts to also be on.

再起動します。

mor@map:/etc/postgresql/9.5/main$ sudo service postgresql restart

プロセスを見ると autovacuum というがあるので、これで動いているということなのかな?

mor@map:/etc/postgresql/9.5/main$ ps aux | grep postgres
postgres 10211  0.4  0.3 294616 24544 ?        S    14:38   0:00 /usr/lib/postgresql/9.5/bin/postgres -D /var/lib/postgresql/9.5/main -c config_file=/etc/postgresql/9.5/main/postgresql.conf
postgres 10213  0.0  0.0 294616  3972 ?        Ss   14:38   0:00 postgres: checkpointer process   
postgres 10214  0.0  0.0 294616  3972 ?        Ss   14:38   0:00 postgres: writer process   
postgres 10215  0.0  0.0 294616  3972 ?        Ss   14:38   0:00 postgres: wal writer process   
postgres 10216  0.0  0.0 295064  6652 ?        Ss   14:38   0:00 postgres: autovacuum launcher process   
postgres 10217  0.0  0.0 149748  4208 ?        Ss   14:38   0:00 postgres: stats collector process   
mor      10232  0.0  0.0  13972   892 pts/0    S+   14:38   0:00 grep --color=auto postgres
mor@map:/etc/postgresql/9.5/main$ 

しばらくこれで様子見したいと思います。

雑感

ディスク容量について

上記でもどこかで触れたように、実は今回の作業を通じて、そもそも postgres では削除や更新の場合に、前のデータを消すわけではなく、常に追記していくということがわかりました。なるほど、そりゃあディスク容量が足りなくなりますね。

一応、 autovacuum の動作設定をしましたが、デフォルトで既に有効になっているという記述も見かけたので、今回のディスク容量不足は autovacuum では解決できない可能性もあります。

OpenStreetMap の Wiki を見ていたら、DB容量が肥大化する理由の一つとして、更新の際に削除された不要なノードへのリンクを持ったデータの存在があるようです。

HowTo minutely hstore - OpenStreetMap Wiki

今回は試しませんでしたが、次にディスク使用量が増えてきた時は試してもよいかもしれません。

EC2 での運用について

実は、ディスク容量不足が発覚した後、ついでにサーバー自体をクラウドに持っていこうとして、 EC2 (t3a.medium, 2vCPU, 4GB メモリ, 80GB SSD) 上に Ubuntu 20.04 ベースでタイルサーバーを構築したのですが、いかんせん処理が遅いのが気になりました。(計ってはないですが)今ある古い物理サーバーの処理よりも遅い印象です。まったくの推測ですがメモリが効いているのかな?

これ以上のスペックのインスタンスに切り替えると、お試し用に小遣いの範囲で運用している身としては結構つらくなってくるので今回は諦めました。

ちなみに、 Ubuntu 20.04 ベースだと、こちらにあるように osm2pgsql のインストールが apt でできるので、その分作業が減って楽になってましたよ。

まあ、今だと Docker で簡単にタイルサーバーを立ち上げることもできるので、新たに試すならこれを使うのもいいかもしれませんね。

なんにせよ、これでまた当面タイルサーバーを運用していきたいと思います。

【Android】コンテンツプロバイダ一覧の取得

Android のアプリを作っているときに、端末に入っているコンテンツプロバイダの一覧を取得する必要が出てきました。

調べてみたら案外簡単でしたが、知らなかったのでメモっときます。

コンテンツプロバイダの一覧の取得

やり方は下記の Stackoverflow に示唆されていて、

How to find third party apps content providers URI in android? - Stack Overflow

PackageManager#queryContentProviders メソッドを使えば、コンテンツプロバイダの情報が取得できるようです。

あとはこれをループで回して、ログにでも出せばOKですね。MainActivity に埋め込んだらこんな感じです。

コンテンツプロバイダの一覧

上記のサンプルでは、下記記事を参考に、ログに出すときにパッケージ名だけでなくアプリケーション名も出しています。

android - get application name from package name - Stack Overflow

他のフィールドを出力すれば、いろいろな情報も取れそうです。 ご参考までに。

Firebase Authentication の Google ログインのサポートメールを変更

今度 Android アプリを作成するときに使うことになったので、今更ながらですが、 Firebase を触り始めました。

で、まずは Build Friendly Chat のチュートリアルを試してみました。Google ログインとかが簡単にできて、これはいいですね。

無事にチュートリアルが終わってから、Firebase プロジェクト画面の設定をあれこれ眺めていると、『サポートメール』という欄に自分のメールアドレスを設定していることを思い出しました。『?』のアイコンにカーソルを合わせると

f:id:junichim:20200807130026p:plain

Google で認証を行う際にユーザーに表示されるメールアドレスです。あなたのログイン メールアドレスか、あなたが管理する Google グループのメールアドレスに変更できます。

と出てきます。

この説明の通りだと、メールアドレスが利用者に表示されるっぽいので、ちょっと避けたいです。

とはいえ、下記のスクリーンショットのように、チュートリアルアプリのチャット画面では、特にサポートメールのメールアドレスは表示されていないようです(表示されているのはこのスマホで設定している Google アカウントとそのメアド)。実際にはどういうことなんでしょうね?

f:id:junichim:20200807130728p:plain

いずれにしても、サポートメールを変更してみます。

なお、このサポートメール自体は、Google ログインで必要とされており、Authentication の Sign-in method の Google を選択した際の画面からも見ることができます。

f:id:junichim:20200807132154p:plain

サポートメールの変更方法

で、早速変えようとしたのですが、このサポートメールの部分は、ドロップダウンリストからの選択式で、任意のメールアドレスを入力することができません。

さきほどの画面に『Googleグループのメールアドレス』がうんぬんかんぬんなどと書いてありますが、ここに Google グループが登場するのがちょっとピンときません。

そのあたりが気になったので、どうやって変更するのかと思って調べてみると、Stackoverflow にやり方がありました。

How do I change the Support Email of a Firebase Project? - Stack Overflow

どうも、Firebase プロジェクトで『ユーザーと権限』からメンバーを追加すれば、追加したメンバーのメールアドレス(たぶんGoogleアカウントとして登録されている必要がありそう)に変更することができるようです。早速試してみます。

  1. 変更先として使いたいメールアドレスの Google アカウントを作成
  2. Firebase プロジェクトで、『メンバーを追加』ボタンを押す f:id:junichim:20200807125054p:plain
  3. メールアドレスを入れて、役割として『編集者』を選択して追加
  4. 追加したユーザーに招待メールが届くので、そのメールで 『Firebase コンソールを開く』をクリック
  5. Firebase の管理画面が表示されるので、『設定』の『全般』を開くと『公開設定』の『サポートメール』に追加したユーザーのメールアドレスが選択できるようになるので、そちらを選択 f:id:junichim:20200807125459p:plain
  6. 無事にサポートメールが変更されました

この方法のほうがピンときますね。 Google グループに追加してやる方法は試してないので、相変わらず謎のままですが、とりあえずこれで対応できるので、良しとします。