본문 바로가기

개발

PMTiles로 polygon 효율적으로 다루기

들어가기 전에

 

다음 내용을 알고 있단 가정 하에 작성했습니다.

    - geoserver로 지도를 렌더링 해본 경험

    - WMS, WFS의 차이

    - GeoJson이 어떻게 생겼는지

 

 

알계 된 계기

 

지도를 확대, 축소, 이동을 하면 네트워크, 서버 상황에 따라 하얀색 타일이 잠깐 보이곤 했다.

지도 데이터 구조상, 유명한 지도 서비스에서도 발생하는 일이어서 어쩔 수 없다고 생각을 했지만,

이 문제를 효과적으로 해결할 수 있는 방법을 찾아 정리하게 됐다.

 

 

어느정도 효율을 보였는지?

 

전국 행정구역 데이터를 GeoJSON -> PMTiles 형태로 변환한 기준

 

필지: 26.7GB → 3.06GB (약 2시간 소모)

건물: 1.16GB → 577MB (약 30분 소모)

시도: 172MB → 19MB (1분 이내)

시군구: 543MB → 18MB (1분 이내)

 

일정 크기 미만의 공간 데이터면, PMTiles 변환에 적은 시간이 걸렸지만,

임계점을 넘으면 걸리는 시간이 크게 증가했다.

 

그래프로 대략적으로 표현하면 다음과 같다.

 

 

 

geoserver와 비교

1. 속도

GeoServer / PMTiles

 

새로운 지도 타일을 보기 위해선 geoserver는 다음 과정을 거쳐야 한다

 

    1. 클라이언트가 벡터 데이터(지도 데이터) 요청

 

    2. GeoServer가 WFS 파라미터 파싱 (+ 캐시 확인)

 

    3. (캐시 미스라면) 내부 데이터에 SQL 실행

 

    4. 조회된 지리 데이터를 요청된 형식(GeoJSON, GML, CSV 등)으로 변환 후, 벡터 데이터 반환 (캐시 저장)

 

    5. 클라이언트 애플리케이션이 지도 라이브러리(Leaflet, OpenLayers 등)를 통해 벡터 데이터 렌더링

 

 

2. 데이터 수정

PMTiles는 핫픽스에 취약하다

 

geoserver는 공간 DB를 조회해 응답 데이터를 만드는 형식이기 때문에

DB 내용이 변경되면, 인덱싱 재조정 등의 시간을 제외하고 수정 대응이 빠르다.

 

pmtiles의 경우, 공간 데이터 전문의 용량이 1~2GB 내로 작다면 수분 내로 끝낼 수 있지만,
그 이상으로 넘어가면 시간 단위로 걸린다.

 

어찌 됐든 데이터 수정하면 PMTiles는 geoserver에 비해 손이 조금 더 간다.

 

 

왜 이렇게 될까?

GeoServer WFS 방식

기본적으로 GeoJSON, GML은 포맷 때문에 용량이 크다

 

클라이언트가 요청하면 GeoServer가 데이터베이스에서 조회한 벡터 데이터를
GeoJSON, GML 등의 형식으로 전송한다.


클라이언트는 데이터를 파싱 해 점, 선, 면 데이터를 가지고 지도 라이브러리를 통해 화면에 직접 그린다.

 

매 요청마다 서버가 데이터베이스를 조회하고 데이터를 변환하여 전송하기 때문에 서버에 부담이 있다.


하지만 데이터베이스만 업데이트하면 즉시 반영되므로 수정이 간편하다.

 

 

PMTiles 방식

 

클라이언트의 PMTiles 라이브러리는 처음 한 번만 파일 헤더(디렉토리)를 다운로드하고,
이후 요청된 X/Y/Z 좌표를 디렉토리에서 찾아 해당 타일이 저장된 바이트 위치를 확인한다.


그리고 HTTP Range Request로 필요한 바이트 범위만 요청하여 다운로드한다.

 

클라이언트는 다운로드한 타일의 압축을 해제하고, 타일 안의 수학적 표현(점, 선, 다각형)을
렌더링 엔진(MapLibre, Mapbox 등)으로 계산하여 화면에 그린다.

 

스타일은 클라이언트에서 적용한다.

 

 

설치

https://github.com/felt/tippecanoe

 

GitHub - felt/tippecanoe: Build vector tilesets from large collections of GeoJSON features.

Build vector tilesets from large collections of GeoJSON features. - felt/tippecanoe

github.com

 

기존 레포 fork 해서 만든 레포. 편의성이 많이 개선됐다.

 

기존 PMTiles 레포는 mbtiles라는 Mapbox에서 만든 표준 포맷을 한번 거쳐가야 했던 것을 한 단계 생략했다.

 

즉, geojson → mbtiles → pmtiles 순으로 변환해야 했던 것을
geojson → pmtiles 한 번에 가능하게 개선했다.

 

확인 결과, 리눅스 환경에서 c++ 빌드 환경을 구성해야 한다.

$ sudo apt-get install gcc g++ make libsqlite3-dev zlib1g-dev
$ git clone https://github.com/felt/tippecanoe.git
$ cd tippecanoe
$ make -j
$ make install

 

PMTiles 변환

$ tippecanoe -o {geojson 파일} {변환할 pmtiles 파일명}

 

여기서 문제가 있는데, 필지나 건물같이 데이터 용량이 큰 경우

polygon이 이상하게 보이거나 중간중간 예쁜 정사각형이 껴있는 문제가 생긴다.

 

따라서, 해상도를 제한해야 한다.

 

다음 명령어는 최대 최소 줌 레벨을 10으로 고정해 polygon이 이상하게 보이는 문제를 해결한다.

 

만약, 파일이 너무 커서 10레벨도 비정상적으로 보이면, 줌 레벨을 더 높여야 한다.

$ tippecanoe -o -Z10 -z10 {geojson 파일} {변환할 pmtiles 파일명}

 

 

시각화

geoserver를 많이 다뤄본 것은 아니지만

css, js가 손에 익은 기술이 아니다 보니 xml로 지정하는 것보다 좀 어려운 감이 있었다.

 

반대로 말하자면, 잘 쓸 수 있다면 커스텀이 자유롭다고 생각한다.

 

1. openlayers

https://docs.protomaps.com/pmtiles/openlayers

 

2. MapLibre GL

https://docs.protomaps.com/pmtiles/maplibre

 

reference

https://docs.maptiler.com/guides/general/raster-vs-vector-map-tiles-what-is-the-difference-between-the-two-data-types/

https://docs.geoserver.org/main/en/user/services/wms/index.html

https://docs.geoserver.org/main/en/user/services/wfs/index.html

https://docs.protomaps.com/pmtiles/