*이 이야기는, 어느 직장인이 겪은 지극히 기술적이지 않은 일대기를 다룹니다.
—
'관심 지점'을 뜻하는 POI(Point Of Interest)는 사용자들이 지도를 사용하기 위해 관심을 두고 접근할 만한 장소, 즉 특정한 의미를 지닌 위치를 나타내는 공간 정보 데이터를 의미합니다.
지도를 구성하는 세 가지 요소인 점/선/면 중 ‘점’에 해당하며, 일반적으로 지도상 장소의 위치를 표시하는 ‘디스플레이 POI’와 길 안내에 사용되는 ‘검색 POI’로 구성되어 있습니다.
POI는 지도에서 가장 작은 존재지만 그 수는 모래알처럼 많습니다. 어떤 길이든 선으로 잇고, 어떤 건물이든 면으로 그릴 수 있듯이, 점으로 표현할 수 있는 장소와 그 안에 담을 정보도 무궁무진하지요. 따라서 방대한 POI 데이터를 효율적으로 관리하고 활용하기 위해선 그에 걸맞은 좋은 보금자리가 반드시 필요합니다.
아이나비는 30여 년간 대한민국의 길 안내를 책임져 온 만큼, 더 나은 POI 제공을 위해 끊임없이 연구하고 도전해 왔습니다. 오늘은 Oracle Database에서 PostgreSQL까지 이어졌던 POI의 소박한 여정을 여러분께 소개해 보고자 합니다.
아이나비의 POI 데이터는 여러 형태로 존재합니다.
대표적으로 아래와 같은 데이터가 있습니다.
1. 상호, 좌표, 카테고리 등 기초 정보가 담긴 [기본 데이터]
2. POI 간의 관계를 정의한 [Relation 데이터]
3. 전화번호, 운영시간, 층 정보 등 장소의 상세 정보가 담긴 [Detail 데이터]
4. 지도상 표출을 위한 [Display 데이터]
이러한 POI의 원도 데이터들은 현재 Oracle Database(이하 ‘Oracle’)를 기반으로 관리되고 있으며, 용도에 따라 PostgreSQL, MySQL 등 별도의 DBMS(데이터베이스 관리 시스템)와 연계하고 있습니다.
DBMS의 대명사로 불리는 Oracle은 대용량 POI 원도 데이터를 운용하기에 적합합니다. 지금까지도 POI 중심 자리를 굳건히 지키고 있는 비결은, 세월이 지나도 뒤처지지 않는 성능과 뛰어난 안정성 덕분입니다.
그동안 우리는 각종 SQL Editor와 공간 처리 프로그램을 활용해 Oracle 기반 데이터로 다양 서비스를 제작해 왔습니다.
하지만, 새로운 모빌리티 플랫폼의 등장과 소셜 네트워크의 진화로, 유통되는 POI 정보량이 빠르게 증가하기 시작했습니다. 우리는 서비스 다각화에 빠르게 대응하고, 더 많은 POI를 활용하기 위해 발행 과정을 고도화해야 했습니다.
Oracle에도 Spatial이라고 하는 공간 도구가 존재하는데요. 하지만, 여러 사용자에 의해 상시 변동하는 원도 데이터베이스에서 복잡한 처리를 거치는 발행 데이터를 제작하는 것은 다소 부담이 있었습니다. 만만찮은 비용도 무시할 수 없었죠. 결국 조금 더 넓은 시야로 새로운 수단을 찾아야만 했던 그때, 우리는 PostgreSQL를 만났습니다.
- ✨ Oracle Database
- ✨ PostgreSQL
PostgreSQL을 선택한 이유는, 데이터 정제 과정에 공간 분석을 손쉽게 결합할 수 있어 보다 고도화된 결과물을 ‘무료로’, 그리고 제법 그럴싸하게 만들어낼 수 있기 때문입니다.
특히 PostgreSQL의 확장 기능 중 하나인 PostGIS는 공간 데이터의 저장, 인덱싱, 쿼리에 대한 강력한 분석 기능을 제공합니다. PostgreSQL의 기능 확장만으로도 바로 사용할 수 있으며 공간 함수를 통해 지리 데이터를 만들거나 가공할 수 있습니다.
데일리 담당자 ★★★★★(5.0)
저는 통신형 서비스에 제공하는 검색 POI를 매일 업데이트하고 있어요. 평소 필요할 때마다 손쉽게 분석할 수 있기도 하지만, 무엇보다 매일 진행하는 정제 기본 과정에 공간 분석을 더해 더욱 풍부한 검색어를 제공할 수 있었어요.
디스플레이 담당자 ★★★★★(5.0)
단지/건물/도로 폴리곤과의 매칭을 통해 표출 우선순위를 다르게 부여할 수 있었고, POI의 주변 환경에 따라 유연하게 조정된 디스플레이 POI를 만들 수 있었습니다.
평화롭게 잘 쓰고만 있었다면 이 이야기는 시작되지 않았을 겁니다. 어느 날, 긴급한 요청을 받아 당장 하던 일을 모두 멈추고 700만 개의 POI를 부랴부랴 준비하기 시작했습니다. 그런데! 평소 10분이면 해냈던 쿼리가 도무지 끝날 기미를 보이지 않습니다! 다급해진 담당자는 새 스크립트를 열어 적기 시작합니다.
/* DB에서 실행되고 있는 동작을 확인해보자 */
select pid, state, wait_event, query_start, now() - query_start AS elapsed_time, query
from pg_stat_activity
where state != 'idle'
order by query_start asc ;
직접 실행한 쿼리 내역 아래에 pid가 ‘4885’인 Autovacuum이라는 정체불명의 작업이 있습니다. 이것이 방해하는 것 같으니, 강제로 쫓아내 봅니다.
/* DB에서 실행 중인 작업을 중단해 보자 */
-- 차 좀 빼주시겠어요? (시도 1)
select pg_terminate_backend(4885) ;
-- 제발 차 좀 빼주세요! (시도 2)
select pg_cancel_backend(4885)
from pg_stat_activity
where wait_event in ('Extension', 'relation') ;
그러나 아무리 중단해도 다시금 살아납니다. 급감하는 효율에 반비례로 혈압이 올라가기 시작합니다. 결국 평소보다 더 오랜 시간이 지나서야 작업이 끝났는데, 이 Autovacuum이란 도대체 무엇이었을까요?
PostgreSQL을 가벼운 작업 위주로 사용한다면 기본 설정대로 사용해도 체감상 불편은 거의 없을 것입니다. 하지만, 그렇지 않다면 유의할 것이 많아집니다.
앞서 겪은 고통도 이를 간과해서 발생한 해프닝이었죠. 요컨대 데이터의 볼륨이 크거나 특정 작업을 자주 사용할 경우에는, 환경에 맞는 별도의 세팅과 관리가 필요합니다. 특히 Dead Tuple을 정리해 주는 Vacuum 기능에 주목해 볼 필요가 있습니다.
Row(=Record=Data)를 PostgreSQL에서 부르는 또 다른 표현입니다. 이 중 Live Tuple(살아있는 튜플)은 테이블에 실제로 존재하는 데이터, Dead Tuple(죽은 튜플)은 여러 작용 결과 비활성화로 남겨진 일종의 과거 데이터입니다.
PostgreSQL는 레코드를 Delete했을 때 그것을 물리적으로 제거하는 것이 아니라 ‘Dead Tuple’로 구분 후 비활성화하며, Update 할 때는 변경 전 레코드를 Dead로 처리하고 변경 후 데이터를 새로운 Live Tuple로 추가합니다.
이 때문에 Update와 Delete를 자주 사용하는 환경이라면 Dead Tuple로 인해 효율이 떨어지는 부작용이 발생합니다.
Insert에서도 간혹 발생하는데, 성공적인 Insert는 Live Tuple만을 생성하고 끝나지만, 중복 키나 제약조건 위배 등으로 삽입이 실패해 트랜잭션이 롤백되면 실패한 레코드가 Dead Tuple로 남게 됩니다.
/* 내 DB의 Tuple 현황 확인(단, 시스템 테이블은 제외) */
select cls.relname as table_name,
pg_stat_get_live_tuples(cls.oid) as live_tuple,
pg_stat_get_dead_tuples(cls.oid) as dead_tupple
from pg_class as cls
join pg_catalog.pg_namespace as nsp
on nsp.oid = cls.relnamespace
where pg_stat_get_live_tuples(cls.oid) > 0
and cls.relname not like 'pg_%'
order by dead_tupple desc;
이 모든 현상은 PostgreSQL의 작동 방식이 MVCC(MultiVersion Concurrency Control, 다중버전 동시성 제어)모델에 기반하기 때문입니다.
튜플마다 트랜잭션 ID가 존재하고, 튜플이 생성되거나 삭제될 때마다 표시를 남겨 처리들이 서로 충돌하지 않도록 해줍니다. 안전하고 빠른 동작을 위해 만들어진 시스템이지만 관리해 주지 않으면 오히려 효율이 떨어지게 됩니다.
PostgreSQL은 Dead Tuple로 인해 발생하는 문제를 방지하고 DB를 최상의 상태로 유지하기 위해 Vaccum, 즉 ‘청소기’ 기능이 존재합니다.
DB 설정에 따라 Dead Tuple이 일정 수준을 넘어가면 자동으로 정리를 시작하는데, 이것이 바로 ‘Autovacuum’입니다. 직역하면 ‘자동 진공청소기’ 정도인데, 필자는 강렬했던 첫 만남에 정이 든 나머지 ‘로봇청소기’(는 역시 로보락)라고 부르고 있습니다.
/* 로봇청소기 전원 상태 확인 */
show autovacuum ;
보통의 경우 초기 설정 그대로 사용해도 Autovacuum의 상태는 ‘On’입니다. Dead Tuple에 따라 작동 여부가 결정되므로 이에 대한 내용도 확인해 봅니다.
/* 로봇청소기는 “언제” 돌아가는가? */
-- 청소가 시작되기 위한 먼지(Dead Tuple)의 최소 개수. 기본값 50
show autovacuum_vacuum_threshold ;
-- 청소가 시작되기 위한 Live 대비 Dead의 최소 비율. 기본값 0.2 (20%)
show autovacuum_vacuum_scale_factor ;
앞서 언급한 ‘일정 수준’이란 저 둘을 더한 값으로, 이론적으로는 10,000개의 레코드를 가진 테이블에서 50 + (0.2 × 10,000) = 즉 2,050개 이상의 Dead Tuple이 쌓이면 실행하게 됩니다.
/* 로봇청소기는 “얼마나” 돌아가는가? */
-- 먼지를 물색하는 주기. 기본값 1min
show autovacuum_naptime ;
-- 1회 자동 청소에 주어진 배터리. 기본값 -1 (= vacuum_cost_limit = 기본값 200)
show autovacuum_vacuum_cost_limit ;
-- 1회 자동 청소 후 대기(재충전)시간. 기본값 2ms
show autovacuum_vacuum_cost_delay ;
-- 먼지를 청소할 때마다 소모되는 배터리
show vacuum_cost_page_dirty ;
그리고 설정된 시간마다 Dead Tuple이 어디에 있는지 DB를 돌아다니며 확인합니다. 청소할 때마다 사전에 설정된 분량의 Cost가 소모되고, 해당 Cost에 도달하면 작업을 멈춥니다.
이 모든 설정을 기본값으로만 운용한다면 원치 않을 때 Autovacuum이 동작하여 작업 효율을 떨어뜨리거나, 반대로 필요한 만큼 청소되지 않아 성능 저하를 유발할 수 있습니다. 로봇청소기의 공장 출고 당시 설정이 10평으로 되어있다고 해서 그대로 사용한다면 34평에서는 제대로 활약할 수 없겠죠.
따라서 PostgreSQL의 데이터 저장소 루트에서 ‘postgresql.conf’ 파일의 내용을 수정하거나 쿼리를 사용하여 환경에 맞는 값으로 변경해 주는 것이 좋습니다. 변경 후에는 반드시 해당 DB의 PostgreSQL 서비스를 재시작해 주어야 합니다.
/* 자동 청소 코스 설정 */
-- 자동 청소 끄기
alter system set autovacuum = off ;
-- 먼지 최소 비율을 5%로 설정(예시)
alter system set autovacuum_vacuum_scale_factor = 0.05 ;
-- 최소 먼지 개수를 100개로 설정하기(예시)
alter system set autovacuum_vacuum_threshold = 100 ;
-- 먼지 검사 주기 30초로 줄이기(예시)
alter system set autovacuum_naptime = '30s' ;
/* 이번 세션만 청소기 끄기*/
-- 위 항목대로 다른 설정도 변경 가능
set autovacuum = off ;
/* 특정 테이블(작은 방)만 자동 코스에서 제외 */
-- 위 항목대로 다른 설정도 변경 가능
alter table 우리집(=스키마).작은방(=테이블명) set (autovacuum_enabled = false) ;
PostgreSQL는 분명 많은 장점을 가진 DBMS지만 한계 또한 명확하기 때문에 특성을 이해하고 적절히 설계하여 운용하는 것이 중요합니다. 불편을 겪기 전 최상의 성능을 위해 미리 고민하는 것도 좋고, 경험에 따라 알아가며 시도해 보는 것도 좋습니다.
이 좌충우돌 연대기는 현재진행형, 아니 미래 지향형입니다. PostgreSQL의 무한한 가능성이 새로운 세상을 열어줄 수도 있고, 그를 능가하는 또 다른 신성이 나타날 수도 있죠.
과거에 존재했던 POI부터 앞으로 생겨날 모든 POI까지, 그리고 궁극적으로 지도를 사용할 모든 이들의 더 나은 경험을 위해, 우리는 노력의 걸음을 멈추지 않을 것입니다. 낙원을 찾기 위한 우리의 여정은 앞으로도 계속됩니다.
덤렐루야 백멘, 덤무아미타불 백세음보살. 어떤 DB를 사용하든 덤프는 진리이고 사랑입니다.
최근 백업 확인하셨나요?
—
by 아이나비시스템즈 POI Plus팀 김서영
#POI #Oracle #PostSQL #MySQL #tuple #autovacuum #지도 #내비게이션 #아이나비지도 #아이나비시스템즈