백업 가져오기 오류: "고유한 인덱스를 생성할 수 없음"

안녕하세요,

포럼을 새 서버로 이주하려고 하고 있습니다. 두 서버 모두 최신 버전의 discourse docker를 실행 중입니다. 명령줄을 통해 백업을 가져올 때 다음과 같은 오류가 발생합니다:

ERROR:  could not create unique index "index_incoming_referers_on_path_and_incoming_domain_id"
DETAIL:  Key (path, incoming_domain_id)=(/search/, 418) is duplicated.
EXCEPTION: psql failed: DETAIL:  Key (path, incoming_domain_id)=(/search/, 418) is duplicated.

이것은 다음과 같은 오류와 동일하거나 유사한 것 같습니다:

그러나 제 경우, 중복된 레코드는 위에서 링크된 스레드에서와 같이 /m/search가 아니라 /search/ 경로에 있습니다.

저는 구 서버의 컨테이너(./launcher enter app)에 연결하여 Rails 콘솔(rails c)에서 다음을 사용하여 중복된 레코드를 검색해 보았습니다:

IncomingReferer.where(path: "/search")
그리고
IncomingReferer.where("path LIKE '%/search%'")

그러나 이렇게 하면 수백 개의 레코드가 표시됩니다. 어떤 레코드가 중복된 것인지 어떻게 파악할 수 있으며, 이 레코드들을 안전하게 삭제하고 다시 구성할 수 있을까요? 현재 포럼은 구 서버에서 정상적으로 작동하고 있으며, 단순히 새 하드웨어로 이전해야 하는 상황입니다.

관리자 GUI를 사용해 보셨나요?

아니요, GUI를 통해 가져오면 동일한 가져오기 프로세스가 실행되는 줄 알았거든요. 이제 시도해 보겠습니다.

인덱스가 손상된 것 같습니다. 어떤 버전의 Postgres를 사용하고 계신가요?

아래와 같은 명령을 실행해 보세요:

cd /var/discourse
cat shared/standalone/postgres_data/PG*

(정확한 Postgres 파일명을 기억이 나지 않습니다.)

여기서 "postgres corrupt index"를 검색하면,我曾经이 그런 문제 기록을 찾아내고 삭제하는 방법에 대해 작성했던 주제를 찾을 수 있습니다.

기본적으로 해당 인덱스를 재구성한 다음, 오류가 보고된 기록을 삭제하고 다시 인덱스를 재구성해 보는 과정을 반복합니다.

방금 GUI를 통해 가져오기를 시도해 보았는데, 정확히 동일한 결과가 나왔습니다:

구 서버에는 PG_VERSION이라는 파일이 없는데, 어떤 버전이 실행 중인지 어떻게 알 수 있을까요? 오늘 docket 설치를 최신 버전으로 업데이트했습니다.

새 서버(새로 부트스트랩된 것)는 postgres V13을 실행 중입니다.

cat shared/standalone/postgres_data/PG_VERSION
13

이를 수행하는 권장 절차가 있나요?

힌트가 포함된 주제가 하나 있었는데, 지금은 더 이상 보이지 않습니다. postgres 12 업그레이드 이후 거의 1년이 지났습니다.

  reindex index index_incoming_referers_on_path_and_incoming_domain_id;

그리고

 ActiveRecord::Base.connection.execute('reindex index index_incoming_referers_on_path_and_incoming_domain_id;')

은 인덱스를 재구성하기 위한 방법입니다. 오류가 발생하면 해당 오류를 확인하여 잘못된 기록을 삭제할 수 있습니다. path와 ID를 모두 포함해야 합니다.

네, 해결했습니다. 다음 작업을 수행했습니다

컨테이너에 진입

./launcher enter app

데이터베이스에 연결

su postgres -c 'psql discourse'

중복 항목을 찾아보기

discourse=# select * from incoming_referers where path LIKE '%/search/' ORDER BY incoming_domain_id;`

  id  |    path    | incoming_domain_id
------+------------+--------------------
 3339 | /search/   |                 33
 6257 | /search/   |                 91
 1567 | /search/   |                298
 1777 | /search/   |                341
 3010 | /search/   |                418
 6247 | /search/   |                418
 4293 | /search/   |                644
 2899 | /search/   |                653
 3447 | /search/   |                793
 3696 | /search/   |                852
 4395 | /a/search/ |               1050
 6968 | /search/   |               1305
 5634 | /search/   |               1387
 5834 | /search/   |               1437
 6519 | /search/   |               1637
 7127 | /search/   |               1787
 7280 | /search/   |               1827
(17 rows)

중복 항목 삭제

DELETE FROM incoming_referers WHERE path LIKE '%/search/' AND id IN (6247);

그 다음 재인덱싱 수행

discourse=# REINDEX SCHEMA CONCURRENTLY public;
WARNING:  cannot reindex invalid index "public.incoming_referers_pkey_ccnew" concurrently, skipping
WARNING:  cannot reindex invalid index "public.index_incoming_referers_on_path_and_incoming_domain_id_ccnew" concurrently, skipping
WARNING:  cannot reindex invalid index "pg_toast.pg_toast_20732_index_ccnew" concurrently, skipping
REINDEX

그 후 백업을 한 번 더 생성하고, 새 서버로 복사한 뒤 성공적으로 가져왔습니다 :smiley:

백업 과정에서 중복 항목을 감지하여 문제를 방지할 수 있다면 좋겠습니다. 다행히도 여전히 실행 중인 원래 서버에 접근할 수 있었기 때문에 문제가 되지 않았습니다. 만약 콜드 백업(정지된 상태의 백업)을 복원하는 상황이었다면 훨씬 더 큰 문제가 되었을 것입니다.

도와주셔서 정말 감사합니다.