업그레이드 실패. 데이터베이스가 중지되었습니다. (멀티사이트 설치)

로그인했습니다. 11개월 동안 업데이트를 하지 않았습니다. Docker Manager를 업그레이드하는 것부터 시작했는데, 완료된 것처럼 보이지 않았습니다. 다음 날에는 관리자 페이지가 거의 망가져 있었습니다. ./launcher rebuild app을 실행해 보았지만, 다음과 같은 오류가 발생합니다.

2025-10-30 20:04:52.144 UTC [1892] discourse@c_discourse ERROR:  must be owner of extension vector
2025-10-30 20:04:52.144 UTC [1892] discourse@c_discourse STATEMENT:  ALTER EXTENSION vector UPDATE TO ‘0.7.0’;

하지만 데이터베이스가 정지되어 있어서 제가 찾은 해결책들이 작동하지 않습니다.

2025-10-31 00:27:40.021 UTC [662] FATAL:  database files are incompatible with server
2025-10-31 00:27:40.021 UTC [662] DETAIL:  The data directory was initialized by PostgreSQL version 15, which is not compatible with this version 13.16 (Debian 13.16-1.pgdg120+1).

하지만

root@main-app:/var/lib/postgresql# pg_config --version
PostgreSQL 16.4 (Debian 16.4-1.pgdg120+1)

수정: DB가 여전히 13 형식으로 남아 있는 것 같습니다?

root@main-app:/var/lib/postgresql# ls
13  take-database-backup

아직 PostgreSQL 15 업데이트 - 공지사항 주제를 보지 못했다면, 그곳부터 시작해 보시는 것이 좋습니다. 해당 주제에서는 여러 문제점과 권장 사항에 대해 논의하고 있습니다.

감사합니다. 전부 제대로 이해하기엔 너무 많은 내용이지만, 제 문제인 것 같지는 않아요. :frowning: 재구축 과정에서 데이터베이스가 실행되는 것 같는데, 그게 좀 이상한 부분이에요. 화면을 스쳐 지나가는 내용을 볼 때의 제 판단으로는 그렇습니다.

11개월이 지난 후에는 대부분 작동하지 않습니다.

반드시 postgres 15 업그레이드를 수행해야 하며, 이것이 문제의 일부입니다. 업그레이드를 수행하기 전에 postgres 13으로 전환하여 시스템을 다시 작동시킬 수 있을 수도 있습니다.

이것이 표준 설치인가요?

멀티사이트(multisite)가 여전히 비지원으로 간주되는 한 그렇지 않습니다.

문제는 설치 당시 개별 데이터베이스에 연결된 사용자/비밀번호가 없었던 것 같습니다. 이 부분은 변경되는 것 같습니다. 바로 그 지점에 문제가 있습니다. 사용자를 추가하거나 빈 비밀번호를 가진 사용자를 추가하는 방식으로 조금씩 조정해 보았지만 도움이 되지 않았습니다.

제 설정과 새로운 샘플 설정 비교:


secondsite:
adapter: postgresql
database: b_discourse

pool: 25
timeout: 5000
db_id: 2
host_names:

mlp:
adapter: postgresql
database: discourse_mlp
username: discourse_mlp
password: applejack
host: dbhost
pool: 5
timeout: 5000

host_names:

이것이 설치 과정에서 데이터베이스가 실제로 시작됨을 의미합니까?

2025-10-31 15:14:30.984 UTC [45] LOG:  starting PostgreSQL 15.14 (Debian 15.14-1.pgdg12+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0
-14+deb12u1) 12.2.0, 64-bit
2025-10-31 15:14:30.984 UTC [45] LOG:  listening on IPv4 address “0.0.0.0”, port 5432
2025-10-31 15:14:30.984 UTC [45] LOG:  listening on IPv6 address “::”, port 5432
2025-10-31 15:14:31.055 UTC [45] LOG:  listening on Unix socket “/var/run/postgresql/.s.PGSQL.5432”
2025-10-31 15:14:31.135 UTC [56] LOG:  database system was shut down at 2025-10-31 02:08:49 UTC
2025-10-31 15:14:31.199 UTC [45] LOG:  database system is ready to accept connections
I, [2025-10-31T15:14:35.760150 #1]  INFO – :
I, [2025-10-31T15:14:35.760557 #1]  INFO – : > /usr/local/bin/create_db
2025-10-31 15:14:35.912 UTC [63] postgres@postgres ERROR:  database “discourse” already exists
2025-10-31 15:14:35.912 UTC [63] postgres@postgres STATEMENT:  CREATE DATABASE discourse;
createdb: error: database creation failed: ERROR:  database “discourse” already exists
2025-10-31 15:14:36.060 UTC [66] postgres@discourse ERROR:  role “discourse” already exists
2025-10-31 15:14:36.060 UTC [66] postgres@discourse STATEMENT:  create user discourse;
ERROR:  role “discourse” already exists
NOTICE:  extension “hstore” already exists, skipping
NOTICE:  extension “pg_trgm” already exists, skipping
NOTICE:  extension “vector” already exists, skipping
NOTICE:  version “0.8.1” of extension “vector” is already installed
NOTICE:  extension “hstore” already exists, skipping
NOTICE:  extension “pg_trgm” already exists, skipping
NOTICE:  extension “vector” already exists, skipping
NOTICE:  version “0.8.1” of extension “vector” is already installed
I, [2025-10-31T15:14:37.265035 #1]  INFO – : GRANT
ALTER SCHEMA
CREATE EXTENSION
CREATE EXTENSION
CREATE EXTENSION
ALTER EXTENSION
CREATE EXTENSION
CREATE EXTENSION
CREATE EXTENSION
ALTER EXTENSION
UPDATE 0

I, [2025-10-31T15:14:37.265325 #1]  INFO – : > echo postgres installed!
I, [2025-10-31T15:14:37.270967 #1]  INFO – : postgres installed!

I, [2025-10-31T15:14:37.271578 #1]  INFO – : > sudo -u postgres createdb b_discourse || exit 0
2025-10-31 15:14:37.380 UTC [104] postgres@postgres ERROR:  database “b_discourse” already exists
2025-10-31 15:14:37.380 UTC [104] postgres@postgres STATEMENT:  CREATE DATABASE b_discourse;
createdb: error: database creation failed: ERROR:  database “b_discourse” already exists
I, [2025-10-31T15:14:37.385149 #1]  INFO – :
I, [2025-10-31T15:14:37.385968 #1]  INFO – : > sudo -u postgres psql b_discourse
I, [2025-10-31T15:14:37.390476 #1]  INFO – : grant all privileges on database b_discourse to discourse;

I, [2025-10-31T15:14:37.515870 #1]  INFO – : > sudo -u postgres createdb c_discourse || exit 0
2025-10-31 15:14:37.625 UTC [111] postgres@postgres ERROR:  database “c_discourse” already exists
2025-10-31 15:14:37.625 UTC [111] postgres@postgres STATEMENT:  CREATE DATABASE c_discourse;
createdb: error: database creation failed: ERROR:  database “c_discourse” already exists
I, [2025-10-31T15:14:37.629387 #1]  INFO – :
I, [2025-10-31T15:14:37.630145 #1]  INFO – : > sudo -u postgres psql c_discourse
I, [2025-10-31T15:14:37.634672 #1]  INFO – : grant all privileges on database c_discourse to discourse;

I, [2025-10-31T15:14:37.758171 #1]  INFO – : > /bin/bash -c ‘sudo -u postgres psql b_discourse <<< “alter schema public owner to discourse;”’
I, [2025-10-31T15:14:37.876557 #1]  INFO – : ALTER SCHEMA

I, [2025-10-31T15:14:37.877104 #1]  INFO – : > /bin/bash -c ‘sudo -u postgres psql b_discourse <<< “create extension if not exists hstore;”’
NOTICE:  extension “hstore” already exists, skipping
I, [2025-10-31T15:14:37.997465 #1]  INFO – : CREATE EXTENSION

I, [2025-10-31T15:14:37.998029 #1]  INFO – : > /bin/bash -c ‘sudo -u postgres psql b_discourse <<< “create extension if not exists pg_trgm;”’
NOTICE:  extension “pg_trgm” already exists, skipping
I, [2025-10-31T15:14:38.117879 #1]  INFO – : CREATE EXTENSION

2025-10-31 15:14:30.984 UTC [45] LOG:  starting PostgreSQL 15.14 (Debian 15.14-1.pgdg12+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0
-14+deb12u1) 12.2.0, 64-bit
2025-10-31 15:14:30.984 UTC [45] LOG:  listening on IPv4 address “0.0.0.0”, port 5432
2025-10-31 15:14:30.984 UTC [45] LOG:  listening on IPv6 address “::”, port 5432
2025-10-31 15:14:31.055 UTC [45] LOG:  listening on Unix socket “/var/run/postgresql/.s.PGSQL.5432”
2025-10-31 15:14:31.135 UTC [56] LOG:  database system was shut down at 2025-10-31 02:08:49 UTC
2025-10-31 15:14:31.199 UTC [45] LOG:  database system is ready to accept connections
I, [2025-10-31T15:14:35.760150 #1]  INFO – :
I, [2025-10-31T15:14:35.760557 #1]  INFO – : > /usr/local/bin/create_db
2025-10-31 15:14:35.912 UTC [63] postgres@postgres ERROR:  database “discourse” already exists
2025-10-31 15:14:35.912 UTC [63] postgres@postgres STATEMENT:  CREATE DATABASE discourse;
createdb: error: database creation failed: ERROR:  database “discourse” already exists
2025-10-31 15:14:36.060 UTC [66] postgres@discourse ERROR:  role “discourse” already exists
2025-10-31 15:14:36.060 UTC [66] postgres@discourse STATEMENT:  create user discourse;
ERROR:  role “discourse” already exists
NOTICE:  extension “hstore” already exists, skipping
NOTICE:  extension “pg_trgm” already exists, skipping
NOTICE:  extension “vector” already exists, skipping
NOTICE:  version “0.8.1” of extension “vector” is already installed
NOTICE:  extension “hstore” already exists, skipping
NOTICE:  extension “pg_trgm” already exists, skipping
NOTICE:  extension “vector” already exists, skipping
NOTICE:  version “0.8.1” of extension “vector” is already installed
I, [2025-10-31T15:14:37.265035 #1]  INFO – : GRANT
ALTER SCHEMA
CREATE EXTENSION
CREATE EXTENSION
CREATE EXTENSION
ALTER EXTENSION
CREATE EXTENSION
CREATE EXTENSION
CREATE EXTENSION
ALTER EXTENSION
UPDATE 0

I, [2025-10-31T15:14:37.265325 #1]  INFO – : > echo postgres installed!
I, [2025-10-31T15:14:37.270967 #1]  INFO – : postgres installed!

I, [2025-10-31T15:14:37.271578 #1]  INFO – : > sudo -u postgres createdb b_discourse || exit 0
2025-10-31 15:14:37.380 UTC [104] postgres@postgres ERROR:  database “b_discourse” already exists
2025-10-31 15:14:37.380 UTC [104] postgres@postgres STATEMENT:  CREATE DATABASE b_discourse;
createdb: error: database creation failed: ERROR:  database “b_discourse” already exists
I, [2025-10-31T15:14:37.385149 #1]  INFO – :
I, [2025-10-31T15:14:37.385968 #1]  INFO – : > sudo -u postgres psql b_discourse
I, [2025-10-31T15:14:37.390476 #1]  INFO – : grant all privileges on database b_discourse to discourse;

I, [2025-10-31T15:14:37.515870 #1]  INFO – : > sudo -u postgres createdb c_discourse || exit 0
2025-10-31 15:14:37.625 UTC [111] postgres@postgres ERROR:  database “c_discourse” already exists
2025-10-31 15:14:37.625 UTC [111] postgres@postgres STATEMENT:  CREATE DATABASE c_discourse;
createdb: error: database creation failed: ERROR:  database “c_discourse” already exists
I, [2025-10-31T15:14:37.629387 #1]  INFO – :
I, [2025-10-31T15:14:37.630145 #1]  INFO – : > sudo -u postgres psql c_discourse
I, [2025-10-31T15:14:37.634672 #1]  INFO – : grant all privileges on database c_discourse to discourse;

I, [2025-10-31T15:14:37.758171 #1]  INFO – : > /bin/bash -c ‘sudo -u postgres psql b_discourse <<< “alter schema public owner to discourse;”’
I, [2025-10-31T15:14:37.876557 #1]  INFO – : ALTER SCHEMA

I, [2025-10-31T15:14:37.877104 #1]  INFO – : > /bin/bash -c ‘sudo -u postgres psql b_discourse <<< “create extension if not exists hstore;”’
NOTICE:  extension “hstore” already exists, skipping
I, [2025-10-31T15:14:37.997465 #1]  INFO – : CREATE EXTENSION

I, [2025-10-31T15:14:37.998029 #1]  INFO – : > /bin/bash -c ‘sudo -u postgres psql b_discourse <<< “create extension if not exists pg_trgm;”’
NOTICE:  extension “pg_trgm” already exists, skipping
I, [2025-10-31T15:14:38.117879 #1]  INFO – : CREATE EXTENSION


Pgvector 확장 기능이 최신이 아니거나 데이터베이스 중 하나에 설정되지 않은 것 같습니다. 몇 달 전 몇몇 설치 환경에서 이 문제를 경험했습니다. 해결 방법은 매우 간단하며, 업데이트만 하면 됩니다.

db 컨테이너에 진입하여 psql을 discourse(또는 데이터베이스 소유자)로 실행한 후, 각 데이터베이스를 선택하고 다음을 실행하세요.

ALTER EXTENSION vector UPDATE;

참고: 설정 구성이 조금 다른 것 같아, 위 명령은 별도의 데이터 컨테이너가 있는 경우에만 작동합니다.

c_discourse 데이터베이스의 확장 소유자가 discourse 사용자인 것 같지 않습니다. 소유자가 누구인지 확인해야 하는데, 예를 들어 다음과 같이 확인해 볼 수 있습니다:

discourse_development=# select extname, extowner, usename, extversion from pg_extension JOIN pg_user on pg_extension.extowner = pg_user.usesysid;
 extname  | extowner | usename  | extversion 
----------+----------+----------+------------
 vector   |    16385 | michael  | 0.8.0
 unaccent |       10 | postgres | 1.1
 pg_trgm  |       10 | postgres | 1.6
 hstore   |       10 | postgres | 1.8
 plpgsql  |       10 | postgres | 1.0

그리고 해당 사용자 또는 데이터베이스 슈퍼유저로 확장 업데이트 명령을 실행해야 합니다.

데이터베이스를 시작하는 방법에 대해 도움을 주실 수 있나요? 그게 바로 막히는 부분입니다.

수정: 제가 찾은 postgres 파일은 /13 버전의 것뿐입니다. 그래서 좀 애매한 상태에 놓여 있습니다. 데이터베이스 프로그램은 업그레이드되었는데 데이터베이스 파일은 그렇지 않은 것 같습니다. 검색을 해봤지만, 파일을 복사해서 직접 만져보는 것 외에는 확신이 서지 않습니다.

2025-10-31 00:27:40.021 UTC [662] FATAL: database files are incompatible with server
2025-10-31 00:27:40.021 UTC [662] DETAIL: The data directory was initialized by PostgreSQL version 15, which is not compatible with this version 13.16 (Debian 13.16-1.pgdg120+1).

앱을 편집하여 postgres 13 템플릿을 사용하고 다시 빌드할 수 있어야 합니다. 이 과정은 PostgreSQL 15 업데이트 토픽에서 설명된 바와 같습니다.

그 다음 다시 빌드할 수 있습니다. 그런 다음 컨테이너를 시작할 수 있습니다. 이어서 컨테이너에 진입할 수 있습니다. 마지막으로 pgvectkr 관련 작업을 수행할 수 있습니다.

음, 15를 제거하고 13을 설치했지만 이상하게도 같은 오류가 나네요. 프로세스가 훨씬 초반에 중단되었습니다. :frowning:

2025-11-01 15:30:26.522 UTC [2547] FATAL: database files are incompatible with server
2025-11-01 15:30:26.522 UTC [2547] DETAIL: The data directory was initialized by PostgreSQL version 15, which is not compatible with this versio
n 13.22 (Debian 13.22-1.pgdg12+1).

실패 지점은 다음과 같습니다:
Failed to migrate secondsite
#<StandardError:"An error has occurred, this and all later migrations canceled:\n\nERROR: must be owner of extension vector\n">
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rack-mini-profiler-4.0.1/lib/patches/db/pg/alias_method.rb:109:in `exec'
/var/www/discourse/vendor/bundle/ruby/3.3.0/gems/rack-mini-profiler-4.0.1/lib/patches/db/pg/alias_method.rb:109:in `async_exec'

13 템플릿을 시도해 보았습니다. 문제는 데이터베이스가 이미 15로 변경되어 있는데, 2개 추가된 멀티 사이트가 설치 프로그램에서 인식되지 않는 것으로 보이는 어떤 사용자로 추가된 상태라는 점입니다. 위에서 언급했듯이, 처음 이 사이트들을 추가할 때 사용자/비밀번호 조합이 요구되지 않았기 때문에 정확히 어떻게 데이터베이스에 추가되었는지 모르겠습니다.

사용자/비밀번호 옵션에 이들을 만족시킬 수 있는 값을 추가할 수 있을까요? 기억하시다시피, 제가 직접 추가한 것이 아니므로 초기 스크립트가 postgres(제가 보는 출력에서 기본 사용자로 표시되는 것)가 아니라 어떤 이름으로 그들을 넣었는지 궁금합니다.

데이터베이스를 올리기 위해 추가된 두 사이트를 주석 처리한 다음, 현재 사용 중인 어떤 임포트 방법을 사용하는 것이 가능할까요?

이것은 주로 개인용 사이트라 잃어버리면 짜증이 나겠지만 치명적인 수준은 아닙니다. 제 정기 백업이 이 정도는 잡아줄 거라고 'stew_pid’처럼(주: 'stew’은 'stew’이라는 단어를 'stew_pid’로 변형하여 '분명히/확실히’라는 뉘앙스를 풍기며 사용) 생각했거든요. :frowning:

pg 15 토픽을 살펴보면, 여전히 pg 13 파일이 있는 백업 디렉토리를 어떻게 이름 변경해야 하는지 알려줍니다.

게시글이 꽤 길어서 제가 올바른 부분을 보고 있는지 확인하고 싶습니다.

  1. 13 템플릿 사용
  2. mv /shared/postgres_data를 /shared/postgres_data.bak 같은 이름으로 변경
  3. mv /shared/postgres_data_old를 /shared/postgres_data로 변경

이렇게 하면 데이터베이스가 이전 버전으로 실행되는 건가요?

root@main-app:/shared/postgres_data_old# cat PG_VERSION
13
root@main-app:/shared/postgres_data# cat PG_VERSION
15

그리고 이 부분은 나중에 걱정하면 되는 건가요?

데이터베이스는 항상 제 약점입니다. :frowning: 제가 생각했던 것과는 구조가 다른 것 같습니다. 제 생각에는 이 모든 것이 /var/lib/posgresql 아래에 있는 그 이상하고 불투명한 번호가 매겨진 디렉터리 중 하나에 모여 있을 줄 알았거든요.

도와주셔서 정말 감사합니다. 제가 일부 사용자들을 보며 고개를 갸웃거리는 몇몇 포럼이 있기도 합니다. :wink:

번들된 플러그인을 포함하는 discourse 버전을 구축하고 있다면, 어떤 postgres 버전을 사용하든 pgvector 확장 기능이 누락되어 빌드가 실패합니다. 구버전의 postgres를 사용 중이라면 기존보다 더 많은 문제에 직면하게 될 것입니다.

이 업그레이드 과정을 시작하기 전에 백업을 취하셨기를 바랍니다.

다른 위치에 새로운 discourse 인스턴스를 설정하고 백업을 복원하는 것을 권장합니다. 이 상황에서 벗어나는 유일한 신뢰할 수 있는 방법입니다.

수동으로 처리할 수도 있지만, 훨씬 더 많은 노력이 필요하며 결과를 보장할 수 없습니다.

어젯밤 새 버전이 배포된 것 같아? git pull이 몇 번 실행되는 걸 본 것 같아. 어쨌든, 13 템플릿을 사용하고 데이터를 이동하니 작동은 해. 거의. :wink:
데이터베이스는 잘 마이그레이션된 것 같아. 출력 로그의 수많은 페이지에서 '권한 오류(grant error)'를 찾을 수 없어. 그렇다고 그 오류가 없다는 뜻은 아니지만. discourse_doctor를 실행해서 에러를 검색할 수 있는 저장된 출력을 만들어야 할 것 같아. DB는 정상적으로 구동 중이야. 이제 브라우저에서 bad gateway 대신 페이지 에러가 나와. 완결성을 위해 마지막 출력 내용을 여기에 올릴 테지만, 이전에 언급된 동일한 권한 오류를 찾지 못하면 새 스레드를 만들 거야.

지금까지 도움을 준 모든 분들께 감사드립니다. 최소한 이제 데이터베이스에 접속할 수 있게 되었어. 여기까지 올 수 있게 도와준 모든 분들께 큰 감사를 드립니다.

정말 감사드립니다!


== 20240611170904 UpgradePgvector070: migrating ===============================

I, [2025-11-02T15:17:02.281908 #1] INFO -- : Terminating async processes
I, [2025-11-02T15:17:02.282204 #1] INFO -- : Sending INT to HOME=/var/lib/postgresql USER=postgres exec chpst -u postgres:postgres:ssl-cert -U p
ostgres:postgres:ssl-cert /usr/lib/postgresql/13/bin/postmaster -D /etc/postgresql/13/main pid: 2547
I, [2025-11-02T15:17:02.282450 #1] INFO -- : Sending TERM to exec chpst -u redis -U redis /usr/bin/redis-server /etc/redis/redis.conf pid: 2644
2025-11-02 15:17:02.289 UTC [2547] LOG: received fast shutdown request
2644:signal-handler (1762096622) Received SIGTERM scheduling shutdown...
2644:M 02 Nov 2025 15:17:02.299 # User requested shutdown...
2644:M 02 Nov 2025 15:17:02.299 * Saving the final RDB snapshot before exiting.
2025-11-02 15:17:02.384 UTC [2547] LOG: aborting any active transactions
2025-11-02 15:17:02.391 UTC [2547] LOG: background worker "logical replication launcher" (PID 2562) exited with exit code 1
2025-11-02 15:17:02.452 UTC [2557] LOG: shutting down
2644:M 02 Nov 2025 15:17:02.549 * DB saved on disk
2644:M 02 Nov 2025 15:17:02.549 # Redis is now ready to exit, bye bye...
2025-11-02 15:17:06.304 UTC [2547] LOG: database system is shut down

FAILED
--------------------
Pups::ExecError: cd /var/www/discourse && sudo -E -u discourse bundle exec rake multisite:migrate failed with return #<Process::Status: pid 4308
exit 1>
Location of failure: /usr/local/lib/ruby/gems/3.3.0/gems/pups-1.3.0/lib/pups/exec_command.rb:131:in `spawn'
exec failed with the params "cd /var/www/discourse && sudo -E -u discourse bundle exec rake multisite:migrate"
bootstrap failed with exit code 1
** FAILED TO BOOTSTRAP ** please scroll up and look for earlier error messages, there may be more than one.
./discourse-doctor may help diagnose the problem.

수정: 로그에서 이것을 찾았어. doctor를 실행하고 에러를 검색하기 전까지는 아무 행동도 하지 않을 거야.
2025-11-02 16:10:09.680 UTC [6244] postgres@c_discourse LOG: provided user name (postgres) and authenticated user name (discourse) do not match
2025-11-02 16:10:09.680 UTC [6244] postgres@c_discourse FATAL: Peer authentication failed for user "postgres"
2025-11-02 16:10:09.680 UTC [6244] postgres@c_discourse DETAIL: Connection matched pg_hba.conf line 89: "local all postgres
peer"

이 스레드를 마무리하기 위해 말씀드리면, doctor를 실행하여 alter 오류를 확인했습니다. 데이터베이스가 실행 중이었기 때문에 멀티사이트에 포함된 데이터베이스에 대해 alter 명령어를 실행하고 빌드를 다시 실행했으며, 이제 마이그레이션이 완료되었습니다. 데이터베이스에 대한 사용자 접근 권한은 유지되고 있지만, 이 부분은 별도로 새 스레드를 열어 질문하겠습니다.

다시 한번, 이 지점까지 이끌어주신 모든 분께 감사드립니다.

루트 권한으로 파일을 이동했기 때문에 chown과 chmod를 실행해야 했습니다. 이 과정은 기록하지 않았지만, 오류 출력에서 확인했습니다.

현재 문제에 대한 링크.