2.18로 업그레이드하기#

AgensGraph 2.18은 PostgreSQL 18 위에 만들어졌으므로 그리로 옮기는 것은 메이저 버전 업그레이드입니다. 데이터 디렉터리 형식이 바뀌었고, 2.17 데이터 디렉터리는 2.18 바이너리로 기동할 수 없습니다. 경로는 둘입니다. 기존 데이터 파일을 재사용해 빠른 pg_upgrade, 또는 덤프 후 다시 적재하는 것입니다.

어느 쪽이든 하기 전에 무엇이 바뀌었는지를 읽고 자기 애플리케이션을 그에 비추어 확인하십시오. 2.17에서 잘 도는 쿼리를 망가뜨릴 변경이 여럿 있고, 업그레이드 도구는 그중 어느 것도 잡아 주지 않습니다.

애플리케이션부터 확인하기#

이 목록을 자기 코드베이스에 대고 하나씩 짚어 보십시오. 각 항목은 2.17에서 잘 돌던 코드를 2.18에서 오류나 다른 답으로 바꾸는 변경입니다.

  • xor·current_graph·current_property_graph라는 이름의 식별자 — 이제 예약어입니다. 이름을 바꾸거나 큰따옴표로 감싸십시오(MATCH (n:"xor")). 여기서 백틱은 따옴표가 아닙니다. 변수 이름으로 쓰는 let과 finish, 레이블로 쓰는 let도 거부되며, 패턴 표기 MATCH (n:insert)는 여전히 되지만 CREATE VLABEL insert; 에는 따옴표가 필요합니다. 어느 단어가 어느 자리에서 실패하는지의 표는 키워드를 참고하십시오.

  • call(...) 또는 (call { ... }) — 이름이 글자 그대로 call인 함수, 또는 변수가 call이고 레이블 없이 속성 맵을 지닌 정점 패턴입니다. 둘 다 뜻이 달라지므로 이름을 따옴표로 감싸십시오.

  • 불리언이 아닌 조건 — WHERE n.count, FILTER n.name입니다. 전에는 0이 아닌지, 비어 있지 않은지로 골랐지만 이제 형 변환 오류를 냅니다. ::boolean을 붙이거나 명시적으로 비교하십시오.

  • 정점·간선·경로에 대한 collect() — 이제 사본을 담은 jsonb 배열이 아니라 네이티브 배열을 반환합니다. jsonb 형태를 파싱하던 클라이언트 코드는 고쳐야 하고, 모은 요소에서 속성을 읽던 코드는 이제 동작하기 시작합니다.

  • 정점이나 간선에 대한 min() / max() — 이제 모호해져 오류입니다. min(v::jsonb)이나 min(id(v))를 쓰십시오.

  • range()·toStringList·toIntegerList·toFloatList — 반환 타입이 바뀌었습니다.

  • SKIP이나 LIMIT이 붙은 WITH … WHERE — 이제 걸러 낸 뒤에 나누므로 결과 집합이 달라집니다.

  • 그래프에 대한 행 수준 보안 — 이제 RLS가 그래프 쓰기에 실제로 적용됩니다. 레이블에 정책이 걸려 있다면 다시 시험하십시오. 전에는 빠져나가던 쓰기가 거부됩니다.

  • 레이블에 대한 ALTER TABLE — 구조를 바꾸는 것은 모두 거부됩니다. 레이블 DDL을 쓰거나 enable_graph_ddl을 설정하십시오.

  • EXPLAIN 회귀 기준 — 요소에 대한 count(), 속성 읽기, 가변 길이 순회 노드에서 계획 텍스트가 바뀌었습니다.

  • 양쪽 콜레이션이 다른 외래키 — 둘 중 하나라도 비결정 콜레이션이면 거부됩니다(42P21). 2.17은 만들어 주었습니다. 양쪽이 같은 비결정 콜레이션이면 지금도 됩니다. 서로 다른 결정 콜레이션 둘도 됩니다. NOT VALID로도 미룰 수 없고, 라벨 열에 건 외래키도 마찬가지로 거부됩니다. 이 항목은 애플리케이션만의 문제가 아닙니다. 2.17 덤프를 복원하면 그 테이블이 제약 없이 만들어집니다. 업그레이드 전에 해당 쌍을 찾으십시오 — 비결정 콜레이션이 낀 외래키를 보십시오.

비결정 콜레이션이 낀 외래키#

덤프하거나 업그레이드하기 전에, 2.17 클러스터의 데이터베이스마다 다음을 실행하십시오.

SELECT c.conrelid::regclass AS referencing, c.conname, fa.attname AS col,
       fc.collname AS referencing_collation, pc.collname AS referenced_collation
  FROM pg_constraint c
  CROSS JOIN LATERAL unnest(c.conkey, c.confkey) AS k(fkatt, pkatt)
  JOIN pg_attribute fa ON fa.attrelid = c.conrelid AND fa.attnum = k.fkatt
  JOIN pg_attribute pa ON pa.attrelid = c.confrelid AND pa.attnum = k.pkatt
  JOIN pg_collation fc ON fc.oid = fa.attcollation
  JOIN pg_collation pc ON pc.oid = pa.attcollation
 WHERE c.contype = 'f'
   AND fa.attcollation <> pa.attcollation
   AND NOT (fc.collisdeterministic AND pc.collisdeterministic);

나오는 행 하나하나가 2.18이 거부할 제약입니다. 2.17에서 두 열의 콜레이션을 같게 맞춘 다음 덤프하십시오. 조건은 서버가 적용하는 조건 그대로이고 서버가 읽는 카탈로그 열을 그대로 읽으므로, 업그레이드가 거부할 제약보다 더 많이도 더 적게도 고르지 않습니다.

경고

어느 경로도 미리 알려 주지 않습니다. pg_upgrade --check는 *Clusters are compatible*로 끝나고, 업그레이드는 그 제약을 다시 만드는 자리에서 실패합니다. 덤프·복원은 더 나쁩니다. 복원이 성공했다고 보고하고 테이블은 외래키 없이 들어오며, 그 뒤로는 아무것도 참조하지 않는 행이 통과합니다.

경로 1. pg_upgrade 쓰기#

pg_upgrade는 새 클러스터의 카탈로그를 만든 다음 기존 사용자 데이터 파일을 재사용하므로 데이터를 다시 쓰지 않습니다. 그래프는 평범한 스키마와 테이블로 저장되므로, 그래프 데이터도 관계형 데이터와 똑같이 옮겨 갑니다.

시작하기 전에#

  • 2.18을 별도의 위치에 설치하십시오. 2.17 설치본을 덮어쓰지 마십시오. pg_upgrade에는 두 바이너리가 모두 필요하고, 2.17을 그대로 두는 것이 되돌아갈 길을 만들어 줍니다.

  • 디스크 공간. 기본적으로 데이터 파일을 복사하므로 두 번째 사본을 둘 자리가 필요합니다. --link는 대신 하드 링크를 겁니다. 거의 즉시 끝나고 공간도 거의 들지 않지만, 두 데이터 디렉터리가 한 파일시스템에 있어야 하고 새 서버가 기동한 뒤에는 되돌릴 수 없게 됩니다.

  • 2.17 클러스터가 쓰는 외부 모듈을 2.18 설치본에도 똑같이 설치하십시오. 예를 들어 pgvector입니다. AgensGraph 자신의 그래프 기능은 서버에 내장돼 있으므로 다시 만들 그래프 확장은 없습니다.

  • 평범한 컬럼을 지닌 레이블이 업그레이드를 막습니다. pg_upgrade는 pg_dump --binary-upgrade에 일을 넘기는데, 그것은 id·start·end·properties 말고 다른 컬럼을 가진 그래프 레이블을, 물리적 컬럼 배치를 조용히 망가뜨리는 대신 거부합니다. 시작하기 전에 찾아 두십시오:

    SELECT c.relname, a.attname
    FROM pg_catalog.ag_label l
      JOIN pg_class c ON c.oid = l.relid
      JOIN pg_attribute a ON a.attrelid = c.oid AND a.attnum > 0 AND NOT a.attisdropped
    WHERE a.attname NOT IN ('id', 'start', 'end', 'properties');
    

    업그레이드하기 전에 그 컬럼들을 지우거나 데이터를 다른 곳으로 옮기십시오.

  • 모든 명령은 데이터 디렉터리를 소유한 운영체제 사용자로 실행하십시오.

아래 명령은 다음 변수를 씁니다:

export OLD=/usr/local/agensgraph-2.17
export NEW=/usr/local/agensgraph-2.18
export OLDDATA=$OLD/data
export NEWDATA=$NEW/data

1단계. 옛 서버 정지#

pg_upgrade가 도는 동안 두 클러스터 모두 내려가 있어야 합니다.

$OLD/bin/ag_ctl -D $OLDDATA stop

2단계. 새 클러스터 초기화#

옛 클러스터와 같은 슈퍼유저·인코딩·로케일을 쓰고, 데이터 체크섬 설정도 맞추십시오.

$NEW/bin/initdb -D $NEWDATA -U postgres --encoding=UTF8 --no-data-checksums

경고

대부분의 업그레이드에서 --no-data-checksums는 선택 사항이 아닙니다. PostgreSQL 18은 데이터 페이지 체크섬을 기본으로 켜고 PostgreSQL 17은 껐습니다. 그러므로 2.17 클러스터를 -k로 초기화하지 않았다면 두 클러스터가 어긋나고, pg_upgrade는 아무것도 하기 전에 멈춥니다:

Performing Consistency Checks
-----------------------------
Checking cluster versions                                     ok

old cluster does not use data checksums but the new one does
Failure, exiting

초기화하기 전에 어느 쪽인지 확인하십시오:

$OLD/bin/pg_controldata -D $OLDDATA | grep checksum

Data page checksum version: 0으로 나오면 --no-data-checksums를 주십시오. 1로 나오면 그 플래그를 빼십시오. 체크섬을 켜는 것은 별개의 작업이며 (pg_checksums 참고) 할 만한 일이지만, 업그레이드의 일부로 하지 말고 그 뒤에 하십시오.

3단계. 호환성 확인#

--check는 두 클러스터를 검사하며 아무것도 바꾸지 않습니다.

$NEW/bin/pg_upgrade \
  -b $OLD/bin -B $NEW/bin \
  -d $OLDDATA -D $NEWDATA \
  -U postgres --check

검사가 성공하면 *Clusters are compatible* 로 끝납니다.

경고

검사를 통과했다고 업그레이드가 성공한다는 뜻은 아닙니다. 이 검사는 비결정 콜레이션이 낀 외래키를 찾지 않으며, 4단계는 그 제약을 다시 만드는 자리에서 실패합니다. 위 질의를 직접 실행하십시오.

데이터베이스 슈퍼유저를 -U로 주십시오. 기본적으로 pg_upgrade는 운영체제 사용자로 접속하는데, 그것은 보통 데이터베이스 롤이 아닙니다.

4단계. 업그레이드 실행#

--check만 뺀 같은 명령입니다:

$NEW/bin/pg_upgrade \
  -b $OLD/bin -B $NEW/bin \
  -d $OLDDATA -D $NEWDATA \
  -U postgres

Upgrade Complete로 끝납니다. 데이터 파일을 복사하는 대신 하드 링크하려면 검사와 업그레이드 양쪽에 --link를 더하십시오.

5단계. 새 서버 기동#

$NEW/bin/ag_ctl -D $NEWDATA -l $NEW/logfile start

새 서버에 붙어 있는지, 그리고 그래프가 넘어왔는지 확인하십시오:

SELECT version();
SET graph_path = <your graph>;
MATCH (n) RETURN count(n);

6단계. 업그레이드 뒤에 할 일#

이 중 셋은 AgensGraph에만 해당하며, 어느 것도 선택 사항이 아닙니다.

통계를 다시 만드십시오. pg_upgrade는 옵티마이저 통계를 가져오지 않으므로, 다시 만들기 전까지 계획이 나쁩니다:

$NEW/bin/vacuumdb -U postgres --all --analyze-in-stages

그래프 메타데이터를 다시 수집하십시오. ag_graphmeta가 플래너의 스캔 쳐내기를 이끕니다. 바이너리 업그레이드는 그것을 빈 채로 두고 그래프를 무효로 표시하므로, 그래프마다 한 번씩 다시 만들기 전까지 쳐내기가 꺼져 있습니다:

SET graph_path = <your graph>;
SELECT regather_graphmeta();

반영됐는지 확인하십시오:

SELECT graphname, graphmeta_valid FROM pg_catalog.ag_graph;

간선 레이블의 통계를 다시 조정하십시오. 2.18은 새 간선 레이블의 start·end 컬럼에 대한 통계 목표치를 10000에서 1000으로 낮췄습니다. 2.17에서 만든 레이블은 옛 값을 그대로 지녀 간선 조인 때마다 큰 계획 비용 — 큰 레이블에서는 수백 밀리초 — 을 치릅니다. 간선 레이블마다 이렇게 하십시오:

ALTER TABLE <graph>.<elabel> ALTER COLUMN start SET STATISTICS 1000;
ALTER TABLE <graph>.<elabel> ALTER COLUMN "end" SET STATISTICS 1000;
ANALYZE <graph>.<elabel>;

그런 다음 업그레이드한 클러스터가 잘 도는 것을 확인했으면, pg_upgrade를 실행한 디렉터리에 그것이 써 둔 스크립트로 옛 데이터 파일을 지우십시오:

./delete_old_cluster.sh

되돌리기#

복사 모드에서, 그리고 delete_old_cluster.sh를 실행하기 전이라면 2.17 데이터 디렉터리는 그대로 있습니다. 새 서버를 정지하고 옛 서버를 기동하십시오:

$NEW/bin/ag_ctl -D $NEWDATA stop
$OLD/bin/ag_ctl -D $OLDDATA -l $OLD/logfile start

--link 업그레이드 뒤에는 두 클러스터가 데이터 파일을 공유하므로, 새 서버가 기동한 뒤에는 되돌릴 수 없습니다. 백업에서 복원하십시오.

경로 2. 덤프하고 다시 적재하기#

더 느리지만 모든 것을 다시 쓰고, 실행 중에 바이너리 사본을 둘씩 두지 않아도 됩니다.

$OLD/bin/pg_dumpall -U postgres -f cluster.sql
# start the 2.18 cluster, then:
$NEW/bin/psql -U postgres -d postgres -f cluster.sql

경고

psql은 오류가 나도 멈추지 않고, 그러고도 종료 코드 0 을 냅니다. 새 서버가 거부하는 것은 — 예를 들어 비결정 콜레이션이 낀 외래키 — 출력 한 줄로 지나가고 복원은 그것 없이 계속됩니다. 복원을 믿기 전에 로그를 읽으십시오.

복원이 멈추게 하려면 롤과 데이터를 따로 덤프하십시오. 롤 부분은 ON_ERROR_STOP으로 복원할 수 없습니다. pg_dumpall은 이미 새 클러스터에 있는 부트스트랩 슈퍼유저의 CREATE ROLE을 쓰고, --clean --if-exists는 접속 중인 롤의 DROP ROLE로 실패 지점을 옮길 뿐입니다.

$OLD/bin/pg_dumpall -U postgres --globals-only -f globals.sql
$OLD/bin/pg_dump    -U postgres -Fc -d mydb -f mydb.dump       # once per database
# start the 2.18 cluster, then:
$NEW/bin/psql -U postgres -d postgres -f globals.sql           # roles; errors here are benign
$NEW/bin/createdb -U postgres mydb
$NEW/bin/pg_restore -U postgres --exit-on-error -d mydb mydb.dump

알아 둘 것 둘입니다:

  • 복원에 enable_graph_ddl이 필요할 수 있습니다. 평범한 컬럼을 지닌 레이블의 덤프는 자기 ALTER TABLE … ADD COLUMN 문장 둘레에 SET enable_graph_ddl = on을 내보냅니다. 그 설정은 어느 롤이든 쓸 수 있으므로 평범한 사용자도 복원할 수 있습니다. 그 롤에 ALTER ROLE … SET으로 강제로 꺼 두지 않았다면 말입니다.

  • 위의 그래프 메타데이터와 통계 작업은 여기서도 그대로 적용됩니다.

다운그레이드는 지원하지 않는다#

어떤 그래프든 승격된 컬럼을 쓰고 있으면 2.18 덤프는 2.17에 복원되지 않습니다. 덤프에 2.17 파서가 거부하는 CREATE VLABEL 형태가 들어 있고, 평문 스트림에서는 그 문장 뒤의 모든 것이 유실됩니다. 되돌아갈 길이 필요하다면 업그레이드 전에 받아 둔 2.17 백업을 보관하십시오.

pg_dump와 pg_restore가 AgensGraph 버전을 검사하지 않는다는 점도 유의하십시오. PostgreSQL의 server_version 범위 검사만 적용됩니다. 그래서 어긋남은 앞에서 거부되는 대신 복원 도중의 파싱 실패로 드러납니다.

실제 예제#

업그레이드 실습은 작은 클러스터에서 실제 명령과 출력으로 전체 절차를 돌려 봅니다.