Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
본 안내서는 OpenSQL을 사용하는 사용자를 대상으로 기술합니다.
본 문서에서는 OpenProxy의 Connection Pooling, 로드밸런싱, 가상 IP 및 이중화 구성에 대한 설명과 Configuration 파라미터를 통해 해당 기능을 관리하는 방법에 대하여 기술합니다.
. ./setenv.sh `pwd`
OPENSQL_INSTALL_HOME is set to: /home/opensql3.0-rockylinux9.4-pg16.8
OPENSQL_HOME is set to: /home/opensql
OPENSQL_HOME added to /home/opensql/.bashrc./install.sh barman$ barman --version
3.11.1 Barman by EnterpriseDB (www.enterprisedb.com)OpenSQL 설치를 위한 기본환경 설정 및 PostgreSQL 설치 과정을 안내합니다.
OpenHA의 핵심 관리 모듈인 OpenHA 클러스터 매니저(OpenHA Cluster Manager) 설치 과정에 대해서 안내합니다.
{schema_name}.{function_name}
-- 예시) o2views extension 설치 후, 새로 추가된 sysdate라는 함수 사용
-- select oracle.sysdate();
$OPENSQL_HOME/etc/openproxy.pid[root@5c9e5c6ae5f2 openproxy]# ls
openproxy openproxy.service openproxy.toml. ./setenv.sh `pwd`
OPENSQL_INSTALL_HOME is set to: /home/opensql3.0-rockylinux9.4-pg16.8
OPENSQL_HOME is set to: /home/opensql
OPENSQL_HOME added to /home/opensql/.bashrc./install.sh openproxy[root@5c9e5c6ae5f2 openproxy]# openproxy --version
openproxy 1.1.0SYSTIMESTAMP()
RETURNS timestamptz;SELECT SYSTIMESTAMP();
systimestamp
-------------------------------
2025-03-06 23:41:29.160617+09
(1 row)SYSDATE()
RETURN TIMESTAMP;select sysdate();
sysdate
---------------------
2025-03-06 22:39:05
(1 row)SESSIONTIMEZONE()
RETURNS text;select sessiontimezone();
sessiontimezone
-----------------
Asia/Seoul
(1 row)SYS_GUID()SELECT SYS_GUID();
sys_guid
------------------------------------
\xc3a83bc2e6f845c8bdf884af0c0516ac
(1 row)-- 현재 접속 세션에서 스키마 'oracle'를 가장 우선순위 높은 search_path로 설정
set search_path to oracle, public;
{function_name}
-- 예시) o2views extension 설치 후, 새로 추가된 sysdate라는 함수 사용
-- select sysdate();DBTIMEZONE()
RETURNS text;select dbtimezone();
dbtimezone
------------
Asia/Seoul
(1 row)SINH(num)SELECT SINH(0);
sinh
------
0BIN_TO_NUM
(
expr1, expr2, ..., exprn IN numeric -- variadic: treated as numeric[]
)
RETURNS numeric;SELECT BIN_TO_NUM(1,0,1);
bin_to_num
------------
5
(1개 행)
SELECT BIN_TO_NUM('1',0,1);
bin_to_num
------------
5
(1개 행)
SELECT BIN_TO_NUM('2',0,1);
ERROR: Invalid value in array, only 0 and 1 are allowedHEXTORAW
(
str IN text
)
RETURNS bytea;SELECT HEXTORAW('DB') AS col;
col
------
\xdb
(1개 행)COSH(num)SELECT TANH(0);
tanh
------
0ASCIISTR
(
str IN text
)
RETURNS text;SELECT ASCIISTR('A한글B');
asciistr
--------------
A\D55C\AE00B
(1개 행)TO_SINGLE_BYTE
(
str IN text
)
RETURNS text;SELECT TO_SINGLE_BYTE('Hello, world!');
-- 예제 결과: 'Hello, world!'
to_single_byte
----------------
Hello, world!
(1 row)LENGTH(str) SELECT LENGTH('abc'::char(6));
length
--------
6
(1 row)
SELECT LENGTH(''::char(6));
length
--------
6
(1 row)LAST_DAY
(
value IN date
)
RETURNS date;
LAST_DAY
(
value IN TIMESTAMP with time zone
)
RETURNS TIMESTAMP without time zone;-- DATE 타입 예제: '2023-05-15'가 속한 달의 마지막 날짜 반환
SELECT LAST_DAY('2023-05-15'::date);
-- 결과: '2023-05-31' (2023년 5월의 마지막 날)
last_day
------------
2023-05-31
(1 row)
-- TIMESTAMPTZ 타입 예제: '2023-05-15 14:30:00+09'가 속한 달의 마지막 날짜 반환
SELECT LAST_DAY('2023-05-15 14:30:00+09'::timestamptz);
-- 결과: 타임스탬프 값으로 해당 달의 마지막 날과 원래 시간 정보가 결합되어 반환됨
last_day
---------------------
2023-05-31 14:30:00
(1 row)COSH(num)SELECT COSH(0);
cosh
------
1RAWTOHEX
(
raw IN { bytea | text }
)
RETURNS text;SELECT RAWTOHEX('AB');
rawtohex
----------
4142
(1개 행)./create_user.sh <password>export OPENSQL_HOME="path/to/install"
export PG_HOME="path/to/pg"
export PG_DATA_DIR="path/to/pg_data". ./setenv.sh `pwd`
OPENSQL_INSTALL_HOME is set to: /home/opensql3.0-rockylinux9.4-pg16.8sudo -E ./install.sh postgresql$ $PG_HOME/bin/pg_config
BINDIR = /usr/pgsql-16/bin
DOCDIR = /usr/pgsql-16/doc
HTMLDIR = /usr/pgsql-16/doc/html
INCLUDEDIR = /usr/pgsql-16/include
PKGINCLUDEDIR = /usr/pgsql-16/include
INCLUDEDIR-SERVER = /usr/pgsql-16/include/server
LIBDIR = /usr/pgsql-16/lib
PKGLIBDIR = /usr/pgsql-16/lib
LOCALEDIR = /usr/pgsql-16/share/locale
MANDIR = /usr/pgsql-16/share/man
SHAREDIR = /usr/pgsql-16/share
SYSCONFDIR = /etc/sysconfig/pgsql
PGXS = /usr/pgsql-16/lib/pgxs/src/makefiles/pgxs.mk
CONFIGURE = '--enable-rpath' '--prefix=/usr/pgsql-16' '--includedir=/usr/pgsql-16/include' '--mandir=/usr/pgsql-16/share/man' '--datadir=/usr/pgsql-16/share' '--libdir=/usr/pgsql-16/lib' '--with-lz4' '--with-zstd' '--enable-tap-tests' '--with-icu' '--with-llvm' '--with-perl' '--with-python' '--with-tcl' '--with-tclconfig=/usr/lib64' '--with-openssl' '--with-pam' '--with-gssapi' '--with-includes=/usr/include' '--with-libraries=/usr/lib64' '--enable-nls' '--enable-dtrace' '--with-uuid=e2fs' '--with-libxml' '--with-libxslt' '--with-ldap' '--with-selinux' '--with-systemd' '--with-system-tzdata=/usr/share/zoneinfo' '--sysconfdir=/etc/sysconfig/pgsql' '--docdir=/usr/pgsql-16/doc' '--htmldir=/usr/pgsql-16/doc/html' 'CFLAGS=-O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64-v2 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection' 'LDFLAGS=-Wl,--as-needed' 'LLVM_CONFIG=/usr/bin/llvm-config-64' 'CLANG=/usr/bin/clang' 'PKG_CONFIG_PATH=:/usr/lib64/pkgconfig:/usr/share/pkgconfig'
CC = gcc
CPPFLAGS = -D_GNU_SOURCE -I/usr/include/libxml2 -I/usr/include
CFLAGS = -Wall -Wmissing-prototypes -Wpointer-arith -Wdeclaration-after-statement -Werror=vla -Wendif-labels -Wmissing-format-attribute -Wimplicit-fallthrough=3 -Wcast-function-type -Wshadow=compatible-local -Wformat-security -fno-strict-aliasing -fwrapv -fexcess-precision=standard -Wno-format-truncation -Wno-stringop-truncation -O2 -flto=auto -ffat-lto-objects -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -fstack-protector-strong -specs=/usr/lib/rpm/redhat/redhat-annobin-cc1 -m64 -march=x86-64-v2 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection
CFLAGS_SL = -fPIC
LDFLAGS = -Wl,--as-needed -L/usr/lib64 -L/usr/lib64 -Wl,--as-needed -Wl,-rpath,'/usr/pgsql-16/lib',--enable-new-dtags
LDFLAGS_EX =
LDFLAGS_SL =
LIBS = -lpgcommon -lpgport -lselinux -lzstd -llz4 -lxslt -lxml2 -lpam -lssl -lcrypto -lgssapi_krb5 -lz -lreadline -lm
VERSION = PostgreSQL 16.8bash $OPENSQL_HOME/scripts/start_openproxy.shStarting OpenProxy with config: /opt/opensql/etc/openproxy.toml
OpenProxy started with PID 18472bash $OPENSQL_HOME/scripts/stop_openproxy.shStopping OpenProxy (PID: 18472)
OpenProxy stoppedbash $OPENSQL_HOME/scripts/restart_openproxy.shRestarting OpenProxy...
Stopping OpenProxy (PID: 18472)
OpenProxy stopped.
Starting OpenProxy with config: /opt/opensql/etc/openproxy.toml
OpenProxy started with PID 18531bash $OPENSQL_HOME/scripts/reload_openproxy.shReloading OpenProxy configuration (PID: 18531)...
OpenProxy configuration reloaded successfully.. ./setenv.sh `pwd`
OPENSQL_INSTALL_HOME is set to: /home/opensql3.0-rockylinux9.4-pg16.8
OPENSQL_HOME is set to: /home/opensql
OPENSQL_HOME added to /home/opensql/.bashrc sudo -E ./install.sh patroni[root@396dd54381db scripts]$ patroni --version
patroni 4.0.5
[root@396dd54381db scripts]$ patronictl version
patronictl version 4.0.5. ./setenv.sh `pwd`
OPENSQL_INSTALL_HOME is set to: /home/opensql3.0-rockylinux9.4-pg16.8
OPENSQL_HOME is set to: /home/opensql
OPENSQL_HOME added to /home/opensql/.bashrc./install.sh etcd[opensql@396dd54381db etcd-v3.5.6-linux-amd64]etcd --version
etcd Version: 3.5.6
Git SHA: cecbe35ce
Go Version: go1.16.15
Go OS/Arch: linux/amd64
[opensql@396dd54381db etcd-v3.5.6-linux-amd64]etcdctl version
etcdctl version: 3.5.6
API version: 3.5# 테스트 테이블
create table employees ( first_name varchar, last_name varchar );
INSERT INTO employees (first_name, last_name) VALUES
('John', 'Doe'),
('Jane', 'Smith'),
('Michael', 'Johnson'),
('Emily', 'Davis'),
('David', 'Wilson'),
('Sarah', 'Brown'),
('James', 'Taylor'),
('Jessica', 'Martinez'),
('Daniel', 'Anderson'),
('Laura', 'Thomas');
# 테스트 1
select wm_concat(last_name) from employees ;
wm_concat
----------------------------------------------------------------------
Doe,Smith,Johnson,Davis,Wilson,Brown,Taylor,Martinez,Anderson,Thomas
(1 row)
# 테스트 2
select wm_concat(first_name) from employees ;
wm_concat
----------------------------------------------------------------
John,Jane,Michael,Emily,David,Sarah,James,Jessica,Daniel,Laura
(1 row)SELECT NUMTOYMINTERVAL (10, 'YEAR');
numtoyminterval
-----------------
10 years
(1개 행)
SELECT NUMTOYMINTERVAL (10, 'month');
numtoyminterval
-----------------
10 mons
(1개 행)
SELECT NUMTOYMINTERVAL (0, 'month');
numtoyminterval
-----------------
00:00:00
(1개 행)# 테스트 1
SELECT GREATEST(5, 3, 9);
greatest
----------
9
(1 row)
# 테스트 2
SELECT GREATEST('apple'::text, 'banana', 'cherry'); -- 결과: cherry (문자열 사전순 비교)
greatest
----------
cherry
(1 row)
# 테스트 3
SELECT GREATEST(10, NULL, 7); -- 결과 NULL
greatest
----------
# 테스트 1
SELECT LNNVL(true);
lnnvl
-------
f
(1 row)
# 테스트 2
SELECT LNNVL(false);
lnnvl
-------
t
(1 row)
# 테스트 3
SELECT LNNVL(NULL);
lnnvl
-------
t
(1 row)# 테스트 1
SELECT SYS_EXTRACT_UTC('2023-06-01 12:34:56+07'::timestamptz);
sys_extract_utc
---------------------
2023-06-01 05:34:56
(1 row)
# 테스트 2
-- 세션 시간대 '+9:00' 기준으로 timestamptz 변환 후 UTC로 변경
SELECT SYS_EXTRACT_UTC('2023-06-01 12:34:56'::timestamp);
sys_extract_utc
---------------------
2023-06-01 03:34:56
(1 row)# 테스트 1
SELECT LEAST(5, 3, 9);
least
-------
3
(1 row)
# 테스트 2
SELECT LEAST('apple'::text, 'banana', 'cherry'); -- 결과: apple (문자열 사전순 비교)
least
-------
apple
(1 row)
# 테스트 3
SELECT LEAST(10, NULL, 7); -- 결과: NULL
least
-------
(1 row)# 테스트 1
SELECT NANVL(3.14, 0.0); -- 결과: 3.14 (3.14가 NaN이 아니므로 원래 값 반환)
nanvl
-------
3.14
(1 row)
# 테스트 2
SELECT NANVL('NaN'::float4, 0.0); -- 결과: 0.0 (첫 번째 값이 NaN이어서 대체값 0.0 반환)
nanvl
-------
0
(1 row)# 테스트 1
SELECT MONTHS_BETWEEN('2023-05-15'::date, '2022-01-10'::date);
months_between
------------------
16.1612903225806
(1 row)
# 테스트 2
SELECT MONTHS_BETWEEN('2023-05-15 12:00:00+09'::timestamptz, '2022-01-10 08:30:00+09'::timestamptz);
months_between
------------------
16.1659946143627 SELECT RPAD('RPAD', 10, '-=');
rpad
------------
RPAD-=-=-=
(1 row)SELECT TO_MULTI_BYTE('Hello, World!');
to_multi_byte
----------------------------
Hello, World!
(1 row)SELECT REGEXP_LIKE('Hello World', 'world', 'i');
regexp_like
-------------
t
(1 row)SELECT NAME FROM T ORDER BY NLSSORT(NAME);
name
------
BAR
FOO
(2 rows)SELECT MOD(-11, 4), MOD(11, -4);
mod | mod
-----+-----
-3 | 3SELECT DATE '2008-03-20' + TO_YMINTERVAL('2-7') AFTER;
after
------------------------
2010-10-20 09:00:00+09
(1개 행)
SELECT DATE '2008-03-20' + TO_YMINTERVAL('P2Y7M') AFTER;
after
------------------------
2010-10-20 09:00:00+09
(1개 행)SELECT TO_TIMESTAMP_TZ('2023-06-01 12:34:56+09', 'YYYY-MM-DD HH24:MI:SSOF');
to_timestamp_tz
------------------------
2023-06-01 12:34:56+09
(1 row)SELECT SUBSTR('ABCDEFG', 3, 2), SUBSTR('ABCDEFG', -3, 2);
substr | substr
--------+--------
CD | EFSELECT INSTR('ABCDEABCDEABCDE', 'CD');
instr
-------
3SELECT DUMP('abc'::TEXT, 1016);
dump
------------------------------------------
Typ=25 Len=3 CharacterSet=UTF8: 61,62,63
(1 row)SELECT REGEXP_COUNT('abcabcabc','abc', 2);
regexp_count
--------------
2
(1 row)SELECT BITAND(6,3);
bitand
--------
2 SELECT LPAD('LPAD', 10, '-=');
lpad
------------
-=-=-=LPAD
(1 row)SELECT RTRIM('ABCDEFGHIJKLMNOP', 'LMNOP');
rtrim
-------------
ABCDEFGHIJK
(1 row)SELECT LTRIM('ABCDEFGHIJKLMNOP', 'ABCDEF');
ltrim
------------
GHIJKLMNOP
(1 row)SELECT REMAINDER(3,2);
remainder
-----------
-1RAWTOHEX
(
raw IN { bytea | text }
)
RETURNS text;SELECT RAWTONHEX('AB');
rawtohex
----------
4142
(1개 행)NVL(expr1, expr2)# 테스트 데이터
create table employees (first_name varchar, last_name varchar, salary integer, hire_date timestamptz);
INSERT INTO employees (first_name, last_name, salary, hire_date) VALUES
('John', 'Doe', NULL, '2020-03-15 09:00:00'),
(NULL, 'Smith', 62000, '2019-07-22 10:30:00'),
('Michael', 'Johnson', 72000, '2018-11-10 08:45:00'),
('Emily', 'Davis', 48000, '2021-05-01 12:00:00'),
('David', 'Wilson', 53000, '2017-09-17 14:20:00'),
(NULL, 'Brown', NULL, '2016-12-05 09:15:00'),
('James', 'Taylor', NULL, '2015-06-30 16:45:00'),
('Jessica', 'Martinez', 68000, '2022-01-25 11:10:00'),
(NULL, 'Anderson', 58000, '2020-10-05 13:35:00'),
('Laura', 'Thomas', 49500, '2023-08-12 08:00:00');
# 테스트 1
# salary 값이 NULL이면 0 반환; first_name 값이 NULL이면 last_name 반환;
select NVL(salary,0), NVL(first_name, last_name) from employees ;
nvl | nvl
-------+---------
55000 | John
62000 | Jane
72000 | Michael
48000 | Emily
53000 | David
60000 | Sarah
75000 | James
68000 | Jessica
58000 | Daniel
49500 | Laura
(10 rows)
LISTAGG(
[ ALL | DISTINCT ]
expression
[, delimite]
)
[OVER ( [query_partition_clause] );
RETURNS text;
query_partition_caluse :
PARTITION BY
{ expr[, expr ]...
| ( expr[, expr ]... )
}# 테스트 테이블
create table employees ( first_name varchar, last_name varchar );
INSERT INTO employees (first_name, last_name) VALUES
('John', 'Doe'),
('Jane', 'Smith'),
('Michael', 'Johnson'),
('Emily', 'Davis'),
('David', 'Wilson'),
('Sarah', 'Brown'),
('James', 'Taylor'),
('Jessica', 'Martinez'),
('Daniel', 'Anderson'),
('Laura', 'Thomas');
# 테스트 1
select listagg(last_name, ',') from employees ;
listagg
----------------------------------------------------------------------
Doe,Smith,Johnson,Davis,Wilson,Brown,Taylor,Martinez,Anderson,Thomas
(1 row)
# 테스트 2
select listagg(last_name) from employees ;
listagg
-------------------------------------------------------------
DoeSmithJohnsonDavisWilsonBrownTaylorMartinezAndersonThomas
(1 row)NUMTODSINTERVAL
(
number IN double precision,
unit IN text
)
RETURNS interval;-- 1.5 DAY는 1일 12시간으로 변환됨
SELECT NUMTODSINTERVAL(1.5, 'DAY');
numtodsinterval
-----------------
1 day 12:00:00
(1 row)
-- 2.75 HOUR는 2시간 45분으로 변환됨
SELECT NUMTODSINTERVAL(2.75, 'HOUR');
numtodsinterval
-----------------
02:45:00
(1 row)
-- 30 MINUTE는 30분 0초로 변환됨
SELECT NUMTODSINTERVAL(30, 'MINUTE');
numtodsinterval
-----------------
00:30:00
(1 row)
-- 90 SECOND는 90초 그대로 반환됨
SELECT NUMTODSINTERVAL(90, 'SECOND');
numtodsinterval
-----------------
00:01:30
(1 row)REGEXP_SUBSTR(str, pattern [, position [, occurrence [, match_param [, subexp]]]])SELECT REGEXP_COUNT('abcabcabc','abc', 2);
regexp_count
--------------
2
(1 row)TO_DATE
(
str IN text
)
RETURNS timestamp;
TO_DATE
(
str IN text,
fmt IN text
)
RETURNS timestamp;
TO_DATE
(
num IN integer,
fmt IN text
)
RETURNS timestamp;-- 텍스트와 포맷 모델을 사용하여 날짜/시간 문자열을 TIMESTAMP로 변환
SELECT TO_DATE('2023-06-01 12:34:56', 'YYYY-MM-DD HH24:MI:SS');
to_date
---------------------
2023-06-01 12:34:56
(1 row)
-- 텍스트만 전달한 경우 기본 변환 형식을 사용 (빈 문자열은 NULL 반환)
SELECT TO_DATE('2023-06-01 12:34:56');
to_date
---------------------
2023-06-01 12:34:56
(1 row)
-- 정수형 값을 문자열로 해석하여 TIMESTAMP로 변환
SELECT TO_DATE(20230601, 'YYYYMMDD');
to_date
---------------------
2023-06-01 00:00:00
(1 row)TO_DSINTERVAL
(
sql_format IN text -- format: '[+|-]days hours:minutes:seconds[.frac_secs]'
)
RETURNS interval;
TO_DSINTERVAL
(
ds_iso_format In text -- format: '[-]P[<days>D][T[<hours>H][<minutes>M][<seconds>[.frac_secs]S]]'
)
RETURNS interval;SELECT DATE '2008-03-20' - TO_DSINTERVAL('50 00:00:00') before;
before
------------------------
2008-01-30 09:00:00+09
(1개 행)
SELECT DATE '2008-03-20' - TO_DSINTERVAL('P50DT0H0M0S') before;
before
------------------------
2008-01-30 09:00:00+09
(1개 행)REGEXP_COUNT(str, pattern [, position [, occurrence [, return_option [, match_param [, sub_expr}]]]])SELECT REGEXP_INSTR('abcabcabc','abc', 2);
regexp_instr
--------------
4
(1 row)REGEXP_LIKE(str, pattern [, replace_str [, position [, occurrence [, match_param]]]])SELECT REGEXP_REPLACE('aaaaaaa','([[:alpha:]])', 'x');
regexp_replace
----------------
xxxxxxx
(1 row)NEXT_DAY
(
value IN date,
weekday IN text
)
RETURNS date;
NEXT_DAY
(
value IN date,
weekday_index IN integer
)
RETURNS date;
NEXT_DAY
(
value IN TIMESTAMP WITH TIME ZONE,
weekday IN text
)
RETURNS TIMESTAMP without time zone;
NEXT_DAY
(
value IN TIMESTAMP WITH TIME ZONE,
weekday_index IN integer
)
RETURNS TIMESTAMP without time zone;데이터 타입에 대한 참조 안내서입니다.
n : 점(.)이 줄바꿈 문자도 포함합니다.n : 점(.)이 줄바꿈 문자도 포함합니다.n : 점(.)이 줄바꿈 문자도 포함합니다.
query_parser_enabled : Query Parsing 기능을 활성화합니다. Read / Write Splitting 외에도 Plugin 기능 활용을 위해서는 해당 옵션이 활성화되어 있어야 합니다.# 테스트 테이블
create table employees (name varchar, salary integer, hire_date timestamptz);
INSERT INTO employees (name, salary, hire_date) VALUES
('John Doe', 55000, '2020-03-15 09:00:00'),
('Jane Smith', 62000, '2019-07-22 10:30:00'),
('Michael Johnson', 72000, '2018-11-10 08:45:00'),
('Emily Davis', 48000, '2021-05-01 12:00:00'),
('David Wilson', 53000, '2017-09-17 14:20:00'),
('Sarah Brown', 60000, '2016-12-05 09:15:00'),
('James Taylor', 75000, '2015-06-30 16:45:00'),
('Jessica Martinez', 68000, '2022-01-25 11:10:00'),
('Daniel Anderson', 58000, '2020-10-05 13:35:00'),
('Laura Thomas', 49500, '2023-08-12 08:00:00');
-- 정수형 데이터의 중앙값 계산 예제
SELECT MEDIAN(salary) FROM employees;
median
--------
59000
(1 row)
-- 날짜형 데이터의 중앙값 계산 예제
SELECT MEDIAN(hire_date) FROM employees;
median
------------------------
2019-11-17 21:45:00+09# 테스트 1
-- 날짜 반올림 예제: '2023-05-15' 날짜를 월 단위로 반올림
SELECT ROUND('2023-05-15'::date, 'MONTH');
-- 결과: 해당 월의 시작일 또는 월의 특정 기준일로 조정된 날짜 반환
round
------------
2023-05-01
(1 row)
# 테스트 2
-- 날짜 반올림 예제 (포맷 미지정): 기본 포맷('DDD')으로 반올림
SELECT ROUND('2023-05-15'::date);
-- 결과: '2023-05-15' 날짜가 포맷 모델에 따라 반올림된 결과 반환
round
------------
2023-05-15
(1 row)
# 테스트 3
-- 타임스탬프 반올림 예제: '2023-05-15 14:35:20' 타임스탬프를 시간 단위로 반올림
SELECT ROUND('2023-05-15 14:35:20'::timestamp, 'HH24');
-- 결과: '2023-05-15 15:00:00' (분과 초가 0으로 조정됨)
round
---------------------
2023-05-15 15:00:00
(1 row)
# 테스트 4
-- 타임스탬프 with time zone 반올림 예제: 기본 포맷('DDD')으로 반올림
SELECT ROUND('2023-05-15 14:35:20+09'::timestamptz);
-- 결과: 포맷 모델에 따라 반올림된 타임스탬프 반환
round
------------------------
2023-05-16 00:00:00+09
(1 row)# 테스트 1
select add_months('2023-01-31'::date, 3);
add_months
------------
2023-04-30
(1 row)
# 테스트 2
select add_months('2023-01-31'::date, 3.9999);
add_months
------------
2023-04-30
(1 row)
# 테스트 3
SELECT ADD_MONTHS('2023-01-31 15:30:00+09'::timestamptz, 1);
add_months
---------------------
2023-02-28 15:30:00
(1 row)
# 테스트 4
SELECT ADD_MONTHS('2023-01-31 15:30:00+09'::timestamptz, 1.3);
add_months
---------------------
2023-02-28 15:30:00
(1 row)-- 문자형 요일 예제: '2023-05-15' 이후의 첫 번째 Monday 반환
SELECT NEXT_DAY('2023-05-15'::date, 'Monday');
next_day
------------
2023-05-22
(1 row)
-- 인덱스 기반 요일 예제: '2023-05-15' 이후의 첫 번째 월요일(인덱스 2) 반환
SELECT NEXT_DAY('2023-05-15'::date, 2);
next_day
------------
2023-05-22
(1 row)
-- TIMESTAMP WITH TIME ZONE 예제 (문자형):
SELECT NEXT_DAY('2023-05-15 14:30:00+09'::timestamptz, 'Friday');
next_day
---------------------
2023-05-19 14:30:00
(1 row)
-- TIMESTAMP WITH TIME ZONE 예제 (인덱스):
SELECT NEXT_DAY('2023-05-15 14:30:00+09'::timestamptz, 6);
next_day
---------------------
2023-05-19 14:30:00
(1 row)# 테스트 데이터
create table employees (
first_name varchar,
last_name varchar,
salary integer,
hire_date timestamptz,
commission_pct integer,
bonus integer,
status varchar
);
INSERT INTO employees (first_name, last_name, salary, hire_date, commission_pct, bonus, status) VALUES
('John', 'Doe', 55000, '2020-03-15 09:00:00', NULL, 2000, 'Active'),
('Jane', 'Smith', 62000, '2019-07-22 10:30:00', 10, 3000, 'Active'),
('Michael', 'Johnson', 72000, '2018-11-10 08:45:00', 7, 2500, 'Inactive'),
('Emily', 'Davis', 48000, '2021-05-01 12:00:00', NULL, 1500, NULL),
('David', 'Wilson', 53000, '2017-09-17 14:20:00', 8, 2200, NULL),
('Sarah', 'Brown', 60000, '2016-12-05 09:15:00', 12, 2800, 'Active'),
('James', 'Taylor', 75000, '2015-06-30 16:45:00', NULL, 2600, 'Resigned'),
('Jessica', 'Martinez', 68000, '2022-01-25 11:10:00', 5, 1800, NULL),
('Daniel', 'Anderson', 58000, '2020-10-05 13:35:00', 6, 2000, 'Active'),
('Laura', 'Thomas', 49500, '2023-08-12 08:00:00', 4, 1200, 'Probation');
# 테스트 1
-- commission_pct 값이 NULL이 아니면 bonus 값을, NULL이면 0을 반환함
SELECT NVL2(commission_pct, bonus, 0)
FROM employees;
nvl2
------
0
3000
2500
0
2200
2800
0
1800
2000
1200
(10 rows)
# 테스트 2
-- 첫 번째 인자가 NULL이 아니면 두 번째 인자(예: 'Active')를, NULL이면 세 번째 인자(예: 'Inactive')를 반환함
SELECT NVL2(status, 'Active', 'Inactive')
FROM employees;
nvl2
----------
Active
Active
Active
Inactive
Inactive
Active
Active
Inactive
Active
Active
(10 rows)# 테스트 1
-- 날짜 절삭: '2023-05-15'를 월 단위로 절삭하여, 해당 월의 첫 날을 반환함
SELECT TRUNC('2023-05-15'::date, 'MONTH');
-- 결과: '2023-05-01'
trunc
------------
2023-05-01
(1 row)
# 테스트 2
-- 날짜 절삭: 포맷 미지정 시, 원래 날짜가 그대로 반환됨
SELECT TRUNC('2023-05-15'::date);
-- 결과: '2023-05-15'
trunc
------------
2023-05-15\q
(1 row)
# 테스트 3
-- 타임스탬프 절삭: '2023-05-15 14:35:20'를 시간 단위로 절삭하여, 분과 초를 제거함
SELECT TRUNC('2023-05-15 14:35:20'::timestamp, 'HH24');
-- 결과: '2023-05-15 14:00:00'
trunc
---------------------
2023-05-15 14:00:00
(1 row)
# 테스트 4
-- timestamptz 절삭: '2023-05-15 14:35:20+09'의 경우, 포맷 미지정 시 기본 포맷('DDD')으로 절삭됨
SELECT TRUNC('2023-05-15 14:35:20+09'::timestamptz);
-- 결과: 타임스탬프 값이 절삭된 결과 반환 (일 단위로 절삭)
trunc
------------------------
2023-05-15 00:00:00+09
(1 row)-- 텍스트를 numeric로 변환 (기본 변환)
SELECT TO_NUMBER('12345.67');
to_number
-----------
12345.67
(1 row)
-- numeric 값과 numeric 값 포맷 모델을 사용하여 numeric 변환
SELECT TO_NUMBER(12345.12467, 99999.9);
to_number
-----------
12345.1
(1 row)
-- 정수형 값을 numeric로 변환
SELECT TO_NUMBER(12345::int);
to_number
-----------
12345
(1 row)
-- double precision 값을 numeric로 변환
SELECT TO_NUMBER(12345.67::double precision);
to_number
-----------
12345.67
(1 row)-- 숫자형 값 변환 (포맷 없이)
SELECT TO_CHAR(12345);
to_char
---------
12345
(1 row)
-- 숫자형 값 변환 (포맷 적용)
SELECT TO_CHAR(12345, 'FM0000000');
to_char
---------
0012345
(1 row)
-- 날짜형 값 변환 (기본 형식)
SELECT TO_CHAR(SYSDATE());
to_char
---------------------
2025-03-07 00:57:44
(1 row)
-- 날짜형 값 변환 (포맷 적용)
SELECT TO_CHAR(SYSDATE(), 'DD-MM-YYYY SS:MI:HH24');
to_char
---------------------
07-03-2025 46:58:00
(1 row)
-- 타임스탬프 변환 (timestamptz)
SELECT TO_CHAR(SYSTIMESTAMP(), 'YYYY-MM-DD"T"HH24:MI:SS');
to_char
---------------------
2025-03-06T15:59:30
(1 row)-- 4자리 16진수 Unicode escape를 사용한 예제 (예: \0041는 'A'로 변환)
SELECT UNISTR('\0041\0042\0043');
-- 결과: 'ABC'
unistr
--------
ABC
(1 row)
-- 다양한 형식의 escape 시퀀스를 포함한 예제
SELECT UNISTR('\u0041 \+00420042 \U00000041');
unistr
----------
A 䈀42 A
(1 row)
select unistr('\0441\043B\043E\043D');
unistr
--------
слон
(1 row)
select unistr('d\u0061t\U00000061');
unistr
--------
data
(1 row)
-- 잘못된 형식 예제
SELECT unistr('wrong: \db99');
ERROR: invalid Unicode surrogate pair
SELECT unistr('wrong: \db99\0061');
ERROR: invalid Unicode surrogate pair
SELECT unistr('wrong: \+00db99\+000061');
ERROR: invalid Unicode surrogate pair
SELECT unistr('wrong: \+2FFFFF');
ERROR: invalid Unicode escape value
SELECT unistr('wrong: \udb99\u0061');
ERROR: invalid Unicode surrogate pair
SELECT unistr('wrong: \U0000db99\U00000061');
ERROR: invalid Unicode surrogate pair
SELECT unistr('wrong: \U002FFFFF');
ERROR: invalid Unicode escape value
SELECT unistr('wrong: \0000');
ERROR: invalid Unicode code point
SELECT unistr('wrong: \u0000');
ERROR: invalid Unicode code point
SELECT unistr('wrong: \+000000');
ERROR: invalid Unicode code point
SELECT unistr('wrong: \U00000000');
ERROR: invalid Unicode code point## Patroni 설정 예시
postgresql:
pg_hba:
## OpenProxy 대역에 대해서 인증 없이 접속을 허용하는 trust 옵션을 적용합니다.
- host all all 172.18.65.0/24 trust[pools.simple_db.users.0]
username = "simple_user"
password = "simple_user"
pool_size = 5
statement_timeout = 30000[pools.simple_db.users.1]
username = "*"
pool_size = 3
statement_timeout = 5000[pools.simple_db.shards.0]
servers = [
[ "opensql1", 5432, "Auto", ],
[ "opensql2", 5432, "Auto", ],
[ "opensql3", 5432, "Auto", ],
]
database = "some_db"
use_patroni = true[pools.simple_db]
pool_mode = "session"
query_parser_enabled = true
query_parser_read_write_splitting = true
primary_reads_enabled = true
sharding_function = "pg_bigint_hash"[general.default_pool]
pool_mode = "transaction"
query_parser_enabled = true
query_parser_read_write_splitting = true
primary_reads_enabled = true
auth_query = "SELECT usename, passwd FROM pg_shadow WHERE usename = '$1'"
auth_query_user = "myuser"
auth_query_password = "mypassword"[pools.simple_db]
pool_mode = "session"
default_role = "primary"
query_parser_enabled = true
query_parser_read_write_splitting = true
primary_reads_enabled = true
sharding_function = "pg_bigint_hash"
prepared_statements_cache_size = 500
[pools.simple_db.users.0]
username = "simple_user"
password = "simple_user"
pool_size = 5
statement_timeout = 30000
[pools.simple_db.shards.0]
servers = [
[ "opensql1", 5432, "Auto", ],
[ "opensql2", 5432, "Auto", ],
[ "opensql3", 5432, "Auto", ],
]
database = "some_db"
use_patroni = trueopenproxy=> show pools;
database | user | pool_mode | cl_idle | cl_active | cl_waiting | cl_cancel_req | sv_active | sv_idle | sv_used | sv_tested | sv_login | maxwait | maxwait_us
------------+---------------+-------------+---------+-----------+------------+---------------+-----------+---------+---------+-----------+----------+---------+------------
simple_db | simple_user | session | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
(1 rows)
openproxy=> show databases;
name | host | port | database | force_user | pool_size | min_pool_size | reserve_pool | pool_mode | max_connections | current_connections | paused | disabled
------------------------------+-------------+------+----------+---------------+-----------+---------------+--------------+-------------+-----------------+---------------------+--------+----------
simple_db_shard_0_replica_0 | 178.176.0.4 | 5432 | some_db | simple_user | 5 | 0 | 0 | session | 5 | 0 | 0 | 0
simple_db_shard_0_replica_1 | 178.176.0.2 | 5432 | some_db | simple_user | 5 | 0 | 0 | session | 5 | 0 | 0 | 0
simple_db_shard_0_primary | 178.176.0.3 | 5432 | some_db | simple_user | 5 | 0 | 0 | session | 5 | 0 | 0 | 0
(3 rows){schema_name}.{type_name}
-- 예시) o2types extension 설치 후, 새로 추가된 date라는 타입을 사용합니다.
-- create table T (col1 oracle.date);
-- 현재 접속 세션에서 스미카 'oracle'를 가장 우선순위 높은 search_path로 설정합니다.
set search_path to oracle, public;
{type_name}
-- 예시) o2types extension 설치 후, 새로 추가된 date라는 타입을 사용합니다.
-- create table T (col1 date);DATECREATE TABLE T (a date);
INSERT INTO T VALUES ('4713-01-01 01:11:30 BC');
INSERT INTO T VALUES ('2023-03-19 13:29:30');VARCHAR2[(size)]EMP_NAME VARCHAR2(10)NVARCHAR(size)clobSELECT 'Hello, '::clob || 'World!'::clob;blobINSERT INTO files (data) VALUES (E'\\xDEADBEEF'::blob);[pools.my_pool]
pool_mode = "transaction"
query_parser_enabled = true
query_parser_read_write_splitting = true[pools.my_pool]
pool_mode = "transaction"
query_parser_enabled = true
query_parser_read_write_splitting = true
primary_reads_enabled = true[pools.my_pool]
load_balancing_mode = "random" ## "random", "loc"[pools.my_pool]
pool_mode = "transaction"
prepared_statements_cache_size = 1000OpenSQL의 효율적인 백업 및 복구를 지원하는 Barman 구성 및 실행방법에 대해 설명합니다.
PrimaryReplica[general.virtual_router]
interface = "eno1"
router_id = 50
priority = 150
advert_int = 3
vip_addresses = [ "192.168.0.200/24" ]
pre_promote_script = "/home/opensql/startup.sh"
pre_demote_script = "/home/opensql/cleanup.sh"
unicast_peers = [ "192.168.0.7", "192.168.0.8" ][general]
renew_interval = 5000 ## 설정파일을 읽어 Config을 업데이트하거나, Patroni 서버에 질의하여
## Postgres 서버 Role을 업데이트 할 주기를 설정할 수 있습니다.
## 단위는 밀리초 (milliseconds) 이며 기본값은 5000 입니다.
[pools.my_pool]
[pools.my_pool.shards.0]
servers = [
[
"192.168.0.8", ## Patroni REST API 서버가 구동중인 호스트들의 IPv4 주소를 입력합니다.
5432, ## PostgreSQL 서버의 Port 번호로 Patroni 연동 시에는 무시됩니다.
"Auto", ## PostgreSQL 노드의 Role 값으으로 Patroni 연동 시에는 무시됩니다.
],
[
"192.168.0.9",
5432,
"Auto",
],
[
"192.168.0.10",
5432,
"Auto",
]
]
database = "postgres"
use_patroni = true
patroni_port = "8008" ## Patroni의 HTTP REST API 서버의 Port 번호를 지정합니다.
## 비어있는 경우 기본값 8008 이 사용됩니다.$ sudo setcap 'cap_net_raw=eip cap_net_admin=eip' openproxy[Service]
AmbientCapabilities=CAP_NET_RAW CAP_NET_ADMIN# $OPENSQL_HOME/etc/etcd.env
# mandatory configuration
ETCD_NAME=<ETCD_NODE_NAME>
# Initial cluster configuration
ETCD_INITIAL_CLUSTER=<ETCD_NODE_NAME>=http://<NODE1_IP>:2380,<ETCD_NODE_NAME2>=http://<NODE2_IP>:2380, ...
ETCD_INITIAL_CLUSTER_STATE=new
ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster
# Peer configuration
ETCD_INITIAL_ADVERTISE_PEER_URLS=http://<NODE_IP>:2380
ETCD_LISTEN_PEER_URLS=http://<NODE_IP>:2380
# Client/server configuration
ETCD_ADVERTISE_CLIENT_URLS=http://<NODE_IP>:2379
ETCD_LISTEN_CLIENT_URLS=http://<NODE_IP>:2379,http://127.0.0.1:2379
#data dir
ETCD_DATA_DIR=/opensql/etc/etcd#$OPENSQL_HOME/etc/etcd.env
## 이 서버의 etcd 노드 이름을 node1 로 지정
ETCD_NAME=node1
## 클러스터의 모든 etcd 노드 이름과 접근 가능한 peer url을 설정
ETCD_INITIAL_CLUSTER=node1=http://172.176.0.2:2380,node2=http://172.176.0.3:2380,node3=http://172.176.0.4:2380
ETCD_INITIAL_CLUSTER_TOKEN=etcd-cluster1
## 초기 클러스터 구성 시에는 3 노드 모두 'new' 로 설정하고 동작. 이후 existing으로 수정.
ETCD_INITIAL_CLUSTER_STATE=new
## etcd 노드간 통신하기 위해 사용하는 peer url을 지정. 기본 port는 2380임
ETCD_INITIAL_ADVERTISE_PEER_URLS=http://172.176.0.2:2380
ETCD_LISTEN_PEER_URLS=http://172.176.0.2:2380
# Client/server configuration
ETCD_ADVERTISE_CLIENT_URLS=http://172.176.0.2:2379
ETCD_LISTEN_CLIENT_URLS=http://172.176.0.2:2379,http://127.0.0.1:2379
# data dir
ETCD_DATA_DIR=/opensql/lib/etcd$ sudo vim /usr/lib/systemd/system/etcd.service
[Unit]
Description=etcd
Documentation=https://github.com/coreos/etcd
Conflicts=etcd-member.service
Conflicts=etcd2.service
[Service]
EnvironmentFile=/etc/etcd/etcd.env
ExecStart=/usr/bin/etcd
Type=notify
TimeoutStartSec=0
Restart=on-failure
RestartSec=5s
LimitNOFILE=65536
Nice=-10
IOSchedulingClass=best-effort
IOSchedulingPriority=2
MemoryLow=200M
[Install]
WantedBy=multi-user.target$ sudo systemctl daemon-reload$ sudo systemctl enable etcd.service
Created symlink from /etc/systemd/system/multi-user.target.wants/etcd.service to /usr/lib/systemd/system/etcd.service.$ sudo systemctl start etcd.service
## 서비스를 중지하는 예시
$ sudo systemctl stop etcd.service
## 서비스를 재시작하는 예시
$ sudo systemctl restart etcd.service$ sudo systemctl status -l etcd
● etcd.service - etcd
Loaded: loaded (/usr/lib/systemd/system/etcd.service; enabled; vendor preset: disabled)
Active: active (running) since Mon 2025-03-17 16:49:45 KST; 3 weeks 2 days ago
Docs: https://github.com/coreos/etcd
Main PID: 4763 (etcd)
CGroup: /system.slice/etcd.service
└─4763 /usr/bin/etcd
Apr 09 17:46:30 node2 etcd[4763]: {"level":"warn","ts":"2025-04-09T17:46:30.542+0900","caller":"etcdserver/util.go:170","msg":"apply request took too long","took":"402.056395ms","expected-duration":"100ms","prefix":"read-only range ","request":"key:\"/service/opensql/\" range_end:\"/service/opensql\" ","response":"range_response_count:9 size:6173"}$ etcd --name 'node1' \
--data-dir '/var/lib/etcd' \
--initial-cluster 'node1=http://172.18.0.2:2380,node2=http://172.18.0.3:2380,node3=http://172.18.0.4:2380' \
--initial-cluster-token 'etcd-cluster1'
--initial-cluster-state 'new'$ etcdctl member list -w=table
+------------------+---------+-------+----------------------+-------------------------+------------+
| ID | STATUS | NAME | PEER ADDRS | CLIENT ADDRS | IS LEARNER |
+------------------+---------+-------+----------------------+-------------------------+------------+
| bfac432fd36a61d5 | started | etcd3 | http://opensql3:2380 | http://178.176.0.3:2379 | false |
| c41cad57348d886f | started | etcd2 | http://opensql2:2380 | http://178.176.0.2:2379 | false |
| dc3ff6e1d56a1012 | started | etcd1 | http://opensql1:2380 | http://178.176.0.4:2379 | false |
+------------------+---------+-------+----------------------+-------------------------+------------+name: pg-1 ## Patroni 멤버 이름. Barman 환경구성 파일에 정의한 모델 이름([pg-1], [pg-2], ...)과 일치해야 한다.
bootstrap:
dcs:
slots:
barman:
type: physical
postgresql:
callbacks:
on_role_change: "curl 'http://{barman-host}:8080/renew_config'"$ . ./setenv.sh `pwd`
$ ./install.sh postgresqlsu - barman$ echo 'export PATH=$PATH:$PG_HOME/bin' >> ~/.bashrc
$ source ~/.bashrc; Main configuration file
[barman] # 글로벌 환경 구성, OS 사용자 이름 및 barman 데이터와 로그를 저장할 경로 등을 지정
; System user
barman_user = barman
configuration_files_directory = /etc/barman.d
; Main directory
barman_home = /var/lib/barman
log_file = /var/log/barman/barman.log
log_level = INFO[opensql] # 서버 이름
cluster = opensql # 후술할 모듈들과 같은 구성임을 나타내기 위한 태그
conninfo = host=node1 port=5432 user=opensql dbname=opensql
streaming_conninfo = host=node1 port=5432 user=opensql_streaming dbname=opensql
backup_method = postgres
streaming_archiver = on
slot_name = barman
; conninfo 사용자 권한 요구사항
; user=opensql : pg_monitor 또는 superuser 권한 필요
; user=opensql_streaming: REPLICATION 권한 필요
; pg_hba.conf에서 barman 호스트의 접근을 허용해야 합니다.
[pg-1] # 모델 이름, Patroni REST API에서 제공하는 멤버 이름과 일치해야 함
cluster = opensql # 이 모델이 종속된 서버를 구분하기 위한 태그
model = true # 서버 정의가 아닌, 서버에 종속되어 일부 옵션을 오버라이딩 하는 '모델'임을 명시
conninfo = host=node1 port=5432 user=opensql dbname=opensql
streaming_conninfo = host=node1 port=5432 user=opensql_streaming dbname=opensql
[pg-2] # 모델 이름, Patroni REST API에서 제공하는 멤버 이름과 일치해야 함
cluster = opensql # 이 모델이 종속된 서버를 구분하기 위한 태그
model = true # 서버 정의가 아닌, 서버에 종속되어 일부 옵션을 오버라이딩 하는 '모델'임을 명시
conninfo = host=node2 port=5432 user=opensql dbname=opensql
streaming_conninfo = host=node2 port=5432 user=opensql_streaming dbname=opensql
[pg-3] # 모델 이름, Patroni REST API에서 제공하는 멤버 이름과 일치해야 함
cluster = opensql # 이 모델이 종속된 서버를 구분하기 위한 태그
model = true # 서버 정의가 아닌, 서버에 종속되어 일부 옵션을 오버라이딩 하는 '모델'임을 명시
conninfo = host=node3 port=5432 user=opensql dbname=opensql
streaming_conninfo = host=node3 port=5432 user=opensql_streaming dbname=opensql
$ pip install -r requirements.txt# 셸에서 직접 실행하고자 하는 경우
## Barman을 실행할 수 있는 권한이 있는 사용자여야 한다.
## Barman 기본 환경 설정의 [barman] 섹션 barman_user 필드
$ python3 server.py &
# systemd 서비스로 등록하는 경우
## barman-agent 실행파일과 config.yml 파일의 경로는 systemd 서비스 파일에 정의된 기본값이다.
## 필요에 따라 해당 파일들의 경로 또는 실행할 사용자를 서비스 파일을 수정하여 변경할 수 있다.
$ sudo chmod 755 server.py
$ sudo cp server.py /usr/local/bin/barman-agent
$ sudo cp config.yml /var/lib/barman/config.yml
$ sudo cp barman-agent.service /usr/lib/systemd/system/.
$ sudo systemctl daemon-reload
$ sudo systemctl enable barman-agent
$ sudo systemctl start barman-agent
listen: "192.168.0.100" ## Optional. 바인딩할 인터페이스 주소. 기본값: 0.0.0.0 (모든 인터페이스 허용)
port: 8080 ## Optional. 바인딩할 TCP 포트 번호. 기본값: 8080
cluster: opensql ## 필수. /etc/barman.d/opensql.conf 의 서버 이름([opensql])과 일치해야 합니다.
patroni: ## 필수. Patroni 노드들의 REST API 엔드포인트를 리스트로 입력합니다.
- node1:8008
- node2:8008
- node3:8008$ barman receive-wal opensql ## Foreground 프로세스로 receive-wal 시작
Starting receive-wal for server opensql
$ barman cron ## barman receive-wal 을 실행하는 Cron Job을 등록
Starting WAL archiving for server opensql
Starting streaming archiver for server opensql
$ which barman ## barman 실행 파일 경로 확인
/usr/local/bin/barman
$ crontab -e -u barman
## 아래 내용 추가 (경로는 위 which barman 결과로 대체)
* * * * * /usr/local/bin/barman cron$ barman check opensql#!/bin/bash
CFSSL_VERSION=1.6.5
CFSSL_PATH=/usr/local/bin
ARCH=amd64
curl -L "https://github.com/cloudflare/cfssl/releases/download/v${CFSSL_VERSION}/cfssl_${CFSSL_VERSION}_linux_${ARCH}" -o cfssl
curl -L "https://github.com/cloudflare/cfssl/releases/download/v${CFSSL_VERSION}/cfssljson_${CFSSL_VERSION}_linux_${ARCH}" -o cfssljson
curl -L "https://github.com/cloudflare/cfssl/releases/download/v${CFSSL_VERSION}/cfssl-certinfo_${CFSSL_VERSION}_linux_${ARCH}" -o cfssl-certinfo
chmod +x cfssl cfssljson cfssl-certinfo
sudo cp cfssl cfssljson cfssl-certinfo ${CFSSL_PATH}/ETCD_CLIENT_CERT_AUTH=true# /etc/patroni/patroni.yml
scope: opensql
name: postgresql0
restapi:
listen: 0.0.0.0:8008
connect_address: 192.168.0.1:8008
etcd3:
protocol: http
hosts:
- 192.168.0.1:2379
- 192.168.0.2:2379
- 192.168.0.3:2379
bootstrap:
# This section will be written into Etcd:/<namespace>/<scope>/config after initializing new cluster
# and all other cluster members will use it as a `global configuration`.
# WARNING! If you want to change any of the parameters that were set up
# via `bootstrap.dcs` section, please use `patronictl edit-config`!
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
failsafe_mode: true
postgresql:
use_pg_rewind: true
parameters:
# wal_level: hot_standby
# hot_standby: "on"
max_connections: 100
max_worker_processes: 8
# wal_keep_segments: 8
# max_wal_senders: 10
# max_replication_slots: 10
# max_prepared_transactions: 0
# max_locks_per_transaction: 64
# wal_log_hints: "on"
# track_commit_timestamp: "off"
# archive_mode: "on"
# archive_timeout: 1800s
# archive_command: mkdir -p ../wal_archive && test ! -f ../wal_archive/%f && cp %p ../wal_archive/%f
# recovery_conf:
# restore_command: cp ../wal_archive/%f %p
# some desired options for 'initdb'
initdb: # Note: It needs to be a list (some options need values, others are switches)
- encoding: UTF8
- data-checksums
post_bootstrap: /home/opensql/scripts/post_bootstrap.sh # $OPENSQL_HOME/scripts/post_bootstrap.sh
postgresql:
listen: 0.0.0.0:5432
connect_address: 192.168.0.1:5432
proxy_address: 192.168.0.1:6432 # The address of connection pool (e.g.,openproxy) running next to Patroni/Postgres. Only for service discovery.
data_dir: /home/opensql/data #
bin_dir: /home/opensql/bin #
# config_dir:
pgpass: /tmp/pgpass0
authentication:
replication:
username: patroni_repl
password: patroni_repl
superuser:
username: postgres
password: postgres
rewind: # Has no effect on postgres 10 and lower
username: patroni_rewind
password: patroni_rewind
pg_hba:
- local all all trust
- host replication patroni_repl all md5
- host all all all md5
parameters:
log_line_prefix: '%m [%r] [%u] [%a]'
tags:
noloadbalance: false
clonefrom: false
nostream: false# /etc/patroni/patroni.yml
scope: opensql
name: postgresql0
restapi:
listen: 0.0.0.0:8008
connect_address: 192.168.0.1:8008
etcd3:
protocol: http
hosts:
- 192.168.0.1:2379
- 192.168.0.2:2379
- 192.168.0.3:2379
bootstrap:
# This section will be written into Etcd:/<namespace>/<scope>/config after initializing new cluster
# and all other cluster members will use it as a `global configuration`.
# WARNING! If you want to change any of the parameters that were set up
# via `bootstrap.dcs` section, please use `patronictl edit-config`!
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
failsafe_mode: true
postgresql:
use_pg_rewind: true
parameters:
# wal_level: hot_standby
# hot_standby: "on"
max_connections: 100
max_worker_processes: 8
# wal_keep_segments: 8
# max_wal_senders: 10
# max_replication_slots: 10
# max_prepared_transactions: 0
# max_locks_per_transaction: 64
# wal_log_hints: "on"
# track_commit_timestamp: "off"
# archive_mode: "on"
# archive_timeout: 1800s
# archive_command: mkdir -p ../wal_archive && test ! -f ../wal_archive/%f && cp %p ../wal_archive/%f
# recovery_conf:
# restore_command: cp ../wal_archive/%f %p
# some desired options for 'initdb'
initdb: # Note: It needs to be a list (some options need values, others are switches)
- encoding: UTF8
- data-checksums
post_bootstrap: /home/opensql/scripts/post_bootstrap.sh # $OPENSQL_HOME/scripts/post_bootstrap.sh
postgresql:
listen: 0.0.0.0:5432
connect_address: 192.168.0.1:5432
proxy_address: 192.168.0.1:6432 # The address of connection pool (e.g.,openproxy) running next to Patroni/Postgres. Only for service discovery.
data_dir: /home/opensql/data #
bin_dir: /home/opensql/bin #
# config_dir:
pgpass: /tmp/pgpass0
authentication:
replication:
username: patroni_repl
password: patroni_repl
superuser:
username: postgres
password: postgres
rewind: # Has no effect on postgres 10 and lower
username: patroni_rewind
password: patroni_rewind
pg_hba:
- local all all trust
- host replication patroni_repl all md5
- host all all all md5
parameters:
log_line_prefix: '%m [%r] [%u] [%a]'
tags:
noloadbalance: false
clonefrom: false
nostream: false
$ patroni $OPENSQL_HOME/etc/patroni.ymlpostgres@opensql3:~$ patronictl -c $OPENSQL_HOME/etc/patroni.yml list
+ Cluster: cluster (7488929455988801618) ------+----+-----------+
| Member | Host | Role | State | TL | Lag in MB |
+----------+-------------+---------+-----------+----+-----------+
| patroni1 | 192.168.0.1 | Replica | streaming | 1 | 0 |
| patroni2 | 192.168.0.2 | Replica | streaming | 1 | 0 |
| patroni3 | 192.168.0.3 | Leader | running | 1 | |
+----------+-------------+---------+-----------+----+-----------+$ vim Makefile
.PHONY: cfssl ca req clean
CFSSL = @env PATH=$(GOPATH)/bin:$(PATH) cfssl
JSON = env PATH=$(GOPATH)/bin:$(PATH) cfssljson
all: ca req
cfssl:
HTTPS_PROXY=127.0.0.1:12639 go get -u -tags nopkcs11 github.com/cloudflare/cfssl/cmd/cfssl
HTTPS_PROXY=127.0.0.1:12639 go get -u github.com/cloudflare/cfssl/cmd/cfssljson
HTTPS_PROXY=127.0.0.1:12639 go get -u github.com/mattn/goreman
ca:
mkdir -p certs
$(CFSSL) gencert -initca config/ca-csr.json | $(JSON) -bare certs/etcd-ca
req:
$(CFSSL) gencert \
-ca certs/etcd-ca.pem \
-ca-key certs/etcd-ca-key.pem \
-config config/ca-config.json \
config/req-csr.json | $(JSON) -bare certs/${infra0}
$(CFSSL) gencert \
-ca certs/etcd-ca.pem \
-ca-key certs/etcd-ca-key.pem \
-config config/ca-config.json \
config/req-csr.json | $(JSON) -bare certs/${infra1}
$(CFSSL) gencert \
-ca certs/etcd-ca.pem \
-ca-key certs/etcd-ca-key.pem \
-config config/ca-config.json \
config/req-csr.json | $(JSON) -bare certs/${infra2}
$(CFSSL) gencert \
-ca certs/etcd-ca.pem \
-ca-key certs/etcd-ca-key.pem \
-config config/ca-config.json \
config/req-csr.json | $(JSON) -bare certs/${infra0}-peer
$(CFSSL) gencert \
-ca certs/etcd-ca.pem \
-ca-key certs/etcd-ca-key.pem \
-config config/ca-config.json \
config/req-csr.json | $(JSON) -bare certs/${infra1}-peer
$(CFSSL) gencert \
-ca certs/etcd-ca.pem \
-ca-key certs/etcd-ca-key.pem \
-config config/ca-config.json \
config/req-csr.json | $(JSON) -bare certs/${infra2}-peer
clean:
rm -rf certs$ vim config/req-csr.json
{
"CN": "etcd", # 삭제
"hosts": [
"localhost",
"127.0.0.1",
"node1",
"node2",
"node3",
"172.18.0.2",
"172.18.0.3",
"172.18.0.4"
],
"key": {
"algo": "ecdsa",
"size": 384
},
"names": [
{
"O": "autogenerated",
"OU": "etcd cluster",
"L": "the internet"
}
]
}$ vim config/ca-csr.json
{
"CN": "Autogenerated CA", # 삭제
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"O": "TmaxTibero",
"OU": "OpenSQL",
"L": "Seongnam-si",
"ST": "Gyeonggi-do",
"C": "KR"
}
]
}$ infra0=node1 infra1=node2 infra2=node3 make$ ls -l
total 84
-rw-r--r-- 1 opensql opensql 985 1월 6 18:10 etcd-ca.csr
-rw------- 1 opensql opensql 1679 1월 6 18:10 etcd-ca-key.pem
-rw-rw-r-- 1 opensql opensql 1281 1월 6 18:10 etcd-ca.pem
-rw-r--r-- 1 opensql opensql 623 1월 6 18:10 node1.csr
-rw------- 1 opensql opensql 288 1월 6 18:10 node1-key.pem
-rw-rw-r-- 1 opensql opensql 1196 1월 6 18:10 node1.pem
-rw-r--r-- 1 opensql opensql 623 1월 6 18:10 node2.csr
-rw------- 1 opensql opensql 288 1월 6 18:10 node2-key.pem
-rw-rw-r-- 1 opensql opensql 1196 1월 6 18:10 node2.pem
-rw-r--r-- 1 opensql opensql 623 1월 6 18:10 node3.csr
-rw------- 1 opensql opensql 288 1월 6 18:10 node3-key.pem
-rw-rw-r-- 1 opensql opensql 1196 1월 6 18:10 node3.pem
-rw-r--r-- 1 opensql opensql 623 1월 6 18:10 node1-peer.csr
-rw------- 1 opensql opensql 288 1월 6 18:10 node1-peer-key.pem
-rw-rw-r-- 1 opensql opensql 1196 1월 6 18:10 node1-peer.pem
-rw-r--r-- 1 opensql opensql 623 1월 6 18:10 node2-peer.csr
-rw------- 1 opensql opensql 288 1월 6 18:10 node2-peer-key.pem
-rw-rw-r-- 1 opensql opensql 1196 1월 6 18:10 node2-peer.pem
-rw-r--r-- 1 opensql opensql 623 1월 6 18:10 node3-peer.csr
-rw------- 1 opensql opensql 288 1월 6 18:10 node3-peer-key.pem
-rw-rw-r-- 1 opensql opensql 1196 1월 6 18:10 node3-peer.pem$ vim $OPENSQL_HOME/etc/etcd.env
#$OPENSQL_HOME/etc/etcd.env
## 아래 내용을 추가하여 허용할 인증서의 인증기관과 공개키 - 사설키를 각각 등록합니다.
## 위치한 .pem 인증서는 etcd 프로세스를 시작할 사용자가 읽기 권한을 가진 파일이어야 합니다.
#Cert
ETCD_TRUSTED_CA_FILE=$OPENSQL_HOME/etc/pki/etcd-ca.pem
ETCD_CERT_FILE=$OPENSQL_HOME/etc/pki/node3.pem
ETCD_KEY_FILE=$OPENSQL_HOME/etc/pki/node3-key.pem
ETCD_PEER_TRUSTED_CA_FILE=$OPENSQL_HOME/etc/pki/etcd-ca.pem
ETCD_PEER_CERT_FILE=$OPENSQL_HOME/etc/pki/node3-peer.pem
ETCD_PEER_KEY_FILE=$OPENSQL_HOME/etc/pki/node3-peer-key.pem#$OPENSQL_HOME/etc/etcd.env
# ...
ETCD_ADVERTISE_CLIENT_URLS=https://172.18.0.2:2379
ETCD_LISTEN_CLIENT_URLS=https://172.18.0.2:2379,http://127.0.0.1:2379
# ...
#Certs
ETCD_TRUSTED_CA_FILE=$OPENSQL_HOME/etc/pki/etcd-ca.pem
ETCD_CERT_FILE=$OPENSQL_HOME/etc/pki/node1.pem
ETCD_KEY_FILE=$OPENSQL_HOME/etc/pki/node1-key.pem
ETCD_PEER_TRUSTED_CA_FILE=$OPENSQL_HOME/etc/pki/etcd-ca.pem
ETCD_PEER_CERT_FILE=$OPENSQL_HOME/etc/pki/node1-peer.pem
ETCD_PEER_KEY_FILE=$OPENSQL_HOME/etc/pki/node1-peer-key.pemMakefile, install.sh)들이 제공됩니다.ls -rlta
total 60
drwxr-xr-x 2 root root 4096 Mar 13 05:09 utl_file
drwxr-xr-x 2 root root 4096 Mar 13 05:09 o2views
drwxr-xr-x 2 root root 4096 Mar 13 05:09 o2types
drwxr-xr-x 2 root root 4096 Mar 13 05:09 o2functions
-rw-r--r-- 1 root root 3266 Mar 13 05:09 install.sh # sh 설치용 스크립트
drwxr-xr-x 2 root root 4096 Mar 13 05:09 dbms_sql
drwxr-xr-x 2 root root 4096 Mar 13 05:09 dbms_random
drwxr-xr-x 2 root root 4096 Mar 13 05:09 dbms_pipe
drwxr-xr-x 2 root root 4096 Mar 13 05:09 dbms_output
drwxr-xr-x 2 root root 4096 Mar 13 05:09 dbms_alert
-rw-r--r-- 1 root root 1465 Mar 13 05:09 VERSION.json # o2 extensions 버전 정보
-rw-r--r-- 1 root root 672 Mar 13 05:09 Makefile # make 방식설치용 파일
drwxr-xr-x 12 root root 4096 Mar 13 05:09 .
drwxr-xr-x 6 root root 4096 Mar 13 05:09 ..cd o2
make all # o2 extensions 전체 설치
# 아래는 전체 설치 과정에서 출력되는 예시 로그
make[1]: Entering directory '/home/opensql/o2/build/o2-dist-1.0.1/o2functions'
/usr/bin/mkdir -p '/home/opensql/postgres/build/16/lib'
/usr/bin/mkdir -p '/home/opensql/postgres/build/16/share/extension'
/usr/bin/mkdir -p '/home/opensql/postgres/build/16/share/extension'
/usr/bin/install -c -m 755 o2functions.so '/home/opensql/postgres/build/16/lib/o2functions.so'
/usr/bin/install -c -m 644 .//o2functions.control '/home/opensql/postgres/build/16/share/extension/'
/usr/bin/install -c -m 644 .//VERSION.json .//o2functions--1.0.sql '/home/opensql/postgres/build/16/share/extension/'
make[1]: Leaving directory '/home/opensql/o2/build/o2-dist-1.0.1/o2functions'
...cd o2
# make [ extension1 extension2 ... ]
make o2functions o2types dbms_output
# 아래는 make 수행 시 나오는 예시 로그
make -C o2functions install
make[1]: Entering directory '/home/opensql/o2/build/o2-dist-1.0.1/o2functions'
/usr/bin/mkdir -p '/home/opensql/postgres/build/16/lib'
/usr/bin/mkdir -p '/home/opensql/postgres/build/16/share/extension'
/usr/bin/mkdir -p '/home/opensql/postgres/build/16/share/extension'
/usr/bin/install -c -m 755 o2functions.so '/home/opensql/postgres/build/16/lib/o2functions.so'
/usr/bin/install -c -m 644 .//o2functions.control '/home/opensql/postgres/build/16/share/extension/'
/usr/bin/install -c -m 644 .//VERSION.json .//o2functions--1.0.sql '/home/opensql/postgres/build/16/share/extension/'
make[1]: Leaving directory '/home/opensql/o2/build/o2-dist-1.0.1/o2functions'
...cd scripts
sh ./install.sh o2# sh install.sh [ extension1 extension2 ... ]
sh install.sh o2functions o2types dbms_output
# 아래는 개별 설치 과정에서 출력되는 예시로그
Installing extensions to:
Library directory: /home/opensql/postgres/build/16/lib
Shared extension directory: /home/opensql/postgres/build/16/share/extension
Extensions to install: o2functions o2types dbms_output
Installing extension: o2functions
Copied control file: ./o2functions.control
Copied SQL file: ./o2functions--1.0.sql
Copied shared library: ./extensions/functions/o2functions.so
Installing extension: o2types
Copied control file: ./o2types.control
Copied SQL file: ./o2types--1.0.sql
Copied shared library: ./extensions/types/o2types.so
Installing extension: dbms_output
Copied control file: ./dbms_output.control
Copied SQL file: ./dbms_output--1.0.sql
Copied shared library: ./extensions/dbms_output/dbms_output.so
Copied METADATA: VERSION.json
Installation completed.[root@20fec5585ddd /]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/pgsql-16/bin/
# 현재 접속한 계정의 $PATH에 경로값이 없다면 PG 버전에 알맞은 경로를 $PATH 경로에 추가
[root@20fec5585ddd /]# echo "export PATH=$PATH:/usr/pgsql-16/bin/" >> ~/.bashrc
[root@20fec5585ddd /]# source ~/.bashrcsudo -u {PG경로가 $PATH에 설정된 다른 USER} bash -l -c "{make 또는 shell 설치 명령}"
# 예시)
# postgres 유저의 $PATH에 /usr/pgsql-16/bin/ 경로가 등록되어 있고,
# opensql이라는 유저로 접속하여 make 방식으로 o2 설치하려는 경우
[opensql@20fec5585ddd /]# sudo -u postgres bash -l -c "make all"# postgresql.conf의 shared_preload_libraries의 첫 번째로 opensql_license 추가
shared_preload_libraries = 'opensql_license'
# 라이선스 파일 경로 환경변수 설정
export OPENSQL_LICENSE_PATH="/path/to/license.xml"CREATE EXTENSION {extension name};ALTER EXTENSION {extension name} UPDATE TO {new version};[로컬 설치]
node1에서 직접 실행
python3 opensql_local_installer.py
node2에서 직접 실행
python3 opensql_local_installer.py
node3에서 직접 실행
python3 opensql_local_installer.py
[원격 설치]
python3 opensql_remote_installer.py
│ SSH
├──────▶ node1
├──────▶ node2
└──────▶ node3opensql-installer/
├── opensql_local_installer.py # 로컬 설치 스크립트
├── opensql_remote_installer.py # 원격 설치 스크립트
├── config/ # 설정 디렉토리
│ ├── common.env # 공통 설정 (로컬/원격 공통, 필수 수정)
│ ├── remote.env # 원격 설치 전용 설정 (원격 설치 시 필수 수정)
│ ├── etcd.config.env # etcd 전용 옵션
│ ├── patroni.config.env # Patroni/PostgreSQL 전용 옵션
│ ├── openproxy.config.env # OpenProxy 전용 옵션
│ ├── etcd.env # etcd 환경변수 템플릿
│ ├── etcd.service # etcd 서비스 파일 템플릿
│ ├── patroni.yml # Patroni 설정 템플릿
│ ├── openproxy.toml # OpenProxy 설정 템플릿
│ └── openproxy.service # OpenProxy 서비스 파일 템플릿
├── licenses/ # 노드별 라이선스 XML 배치 디렉토리 (필수 생성)
│ ├── node1_license.xml (예시)
│ └── ...
└── src/ # 공통 모듈 (수정 불필요)
├── config.py
├── functions.py
└── package_requirements.json# Rocky Linux / RHEL 설치 예시
dnf install -y openssh-clients python3 sshpassopensql-installer/
└── licenses/
├── node1_license.xml
├── node2_license.xml (3node, 2node-witness)
└── node3_license.xml (3node)# 예시: Rocky Linux 8.10용 패키지
tar -xzf Tmax_OpenSQL_3.18.1.3_rockylinux8.10_buildtime20260223.tar.gzTmax_OpenSQL_3.18.1.3_rockylinux8.10_buildtime20260223/
└── opensql-installer/
├── opensql_local_installer.py
├── opensql_remote_installer.py
└── config/
├── common.env ← 로컬/원격 공통 설정 (필수 수정)
└── remote.env ← 원격 설치 전용 설정 (원격 설치 시 필수 수정)# 클러스터의 모든 노드 IP (현재 노드 포함)
# 인스톨러가 현재 서버 IP와 비교하여 자신의 노드를 감지합니다.
NODE1_IP="<node1_ip>"
NODE2_IP="<node2_ip>"
NODE3_IP="<node3_ip>"
# 현재 노드의 표시 이름 (로컬 설치 시 로그에 표시됨)
NODE_NAME="<node_name>"
# OpenSQL 홈 디렉토리 (절대 경로)
# 바이너리, 데이터, 설정, 로그가 이 경로 하위에 위치합니다.
# 패키지 설치 경로는 자동으로 $OPENSQL_HOME/install 로 설정됩니다.
OPENSQL_HOME="/path/to/opensql/home"
PG_HOME="/path/to/pg/home"
PG_DATA_DIR="/path/to/pg/data"
# 현재 노드에 적용할 라이선스 파일명 (licenses/ 디렉토리 기준)
# 로컬 설치 시 필수. 원격 설치 시에는 remote.env에서 노드별로 설정합니다.
LICENSE_NAME="<license file>"# 필수 패키지 자동 설치 (기본: false)
# AUTO_INSTALL_PREREQS=false
# OpenSQL 운영 유저/그룹 이름 (기본: opensql)
# OPENSQL_USER=opensql
# OPENSQL_GROUP=opensql
# OpenSQL 패키지 디렉토리 패턴 (기본: Tmax_OpenSQL*)
# OPENSQL_PACKAGE_PATTERN="Tmax_OpenSQL*"
# 2node-witness 모드: witness 노드의 etcd 포트 (필수)
# WITNESS_ETCD_CLIENT_PORT=2379
# WITNESS_ETCD_PEER_PORT=2380# 노드 표시 이름 (로그에 표시됨)
NODE1_NAME="db-node1"
NODE2_NAME="db-node2"
NODE3_NAME="db-node3"
# SSH 접속 유저 (각 노드에 존재해야 함, sudo 권한 필요)
NODE1_SSH_USER="ec2-user"
NODE2_SSH_USER="ec2-user"
NODE3_SSH_USER="ec2-user"
# SSH 포트 (기본 22가 아닌 경우 명시)
NODE1_SSH_PORT="22"
NODE2_SSH_PORT="22"
NODE3_SSH_PORT="22"
# 노드별 OpenSQL 홈 디렉토리 (common.env의 OPENSQL_HOME과 다를 경우)
NODE1_OPENSQL_HOME="/home/opensql"
NODE2_OPENSQL_HOME="/home/opensql"
NODE3_OPENSQL_HOME="/home/opensql"
# 노드별 PG 디렉터리
NODE1_PG_HOME="/path/to/pg/"
NODE2_PG_HOME="/path/to/pg/"
NODE3_PG_HOME="/path/to/pg/"
# 노드별 PG_DATA 위치
NODE1_PG_DATA="/path/to/pg/data"
NODE2_PG_DATA="/path/to/pg/data"
NODE3_PG_DATA="/path/to/pg/data"
# 노드별 라이선스 파일명 (opensql-installer/licenses/ 기준)
# Patroni가 동작하는 노드에만 필요합니다.
# 2node-witness 모드의 witness(node3)는 비워둡니다.
NODE1_LICENSE_NAME="node1_license.xml"
NODE2_LICENSE_NAME="node2_license.xml"
NODE3_LICENSE_NAME="node3_license.xml"노드별 비밀번호 (NODE{n}_PASSWORD)
> 전체 공통 비밀번호 (COMMON_PASSWORD)
> 대화형 입력 (실행 시 프롬프트)python3 opensql_remote_installer.py --password "my_password"
python3 opensql_remote_installer.py --node1-password "pw1" --node2-password "pw2" --node3-password "pw3"# 전체 공통 비밀번호
# COMMON_PASSWORD=""
# 노드별 개별 지정
# NODE1_PASSWORD=""
# NODE2_PASSWORD=""
# NODE3_PASSWORD=""# SSH 키 경로 (기본: ~/.ssh/id_rsa_opensql)
# SSH_KEY="$HOME/.ssh/id_rsa_opensql"
# SSH 추가 옵션 (기본: StrictHostKeyChecking=no, ConnectTimeout=10)
# SSH_OPTS="-o StrictHostKeyChecking=no -o ConnectTimeout=10"# 2node-witness 모드에서 클러스터 식별자 (기본: c1)
# CLUSTER_ID=c1
# etcd 포트 (기본: 2379/2380)
# ETCD_CLIENT_PORT=2379
# ETCD_PEER_PORT=2380
# etcd 데이터/환경 파일 경로 (비워두면 자동 설정)
# ETCD_DATA_DIR=/etc/opensql/etcd_data
# ETCD_ENV_FILE=/etc/opensql/etcd.env# Patroni 인스턴스 이름 (기본: postgresql1/2/3)
# NODE1_PATRONI_NAME=postgresql1
# NODE2_PATRONI_NAME=postgresql2
# NODE3_PATRONI_NAME=postgresql3
# Patroni 설정 (기본값)
# PATRONI_SCOPE_BASE=opensql
# PATRONI_API_PORT=8008
# PATRONI_TTL=30
# PATRONI_LOOP_WAIT=10
# PATRONI_RETRY_TIMEOUT=10
# PostgreSQL 포트/계정 (기본값)
# PG_PORT=5432
# PG_SUPERUSER=postgres
# PG_SUPERUSER_PASSWORD=postgres
# PG_REPLICATION_USER=patroni_repl
# PG_REPLICATION_PASSWORD=patroni_repl
# PG_REWIND_USER=patroni_rewind
# PG_REWIND_PASSWORD=patroni_rewind# OpenProxy 포트 (기본: 6432/6433)
# OPENPROXY_PORT=6432
# OPENPROXY_ADMIN_PORT=6433
# OpenProxy 동작 설정 (기본값)
# OPENPROXY_CONNECT_TIMEOUT=10000 # 클라이언트 연결 타임아웃 (밀리초)
# OPENPROXY_POOL_MODE=session # 풀 모드: session / transaction
# OPENPROXY_DEFAULT_ROLE=primary # 기본 라우팅: primary / replica
# OPENPROXY_QUERY_PARSER_ENABLED=false
# OPENPROXY_POOL_SIZE=10 # 풀당 최대 서버 연결 수
# OPENPROXY_DATABASE=postgres # 연결 대상 데이터베이스명WITNESS_ETCD_CLIENT_PORT=2379
WITNESS_ETCD_PEER_PORT=2380NODE1_IP="192.168.1.10"
NODE2_IP=""
NODE3_IP=""
NODE_NAME="db-single"
OPENSQL_HOME="/home/opensql"
LICENSE_NAME="node1_license.xml"NODE1_NAME="db-single"
NODE1_SSH_USER="ec2-user"
NODE1_SSH_PORT="22"
NODE1_OPENSQL_HOME="/home/opensql"
NODE1_LICENSE_NAME="node1_license.xml"# 로컬 설치 (node1에서 직접)
cd opensql-installer
python3 opensql_local_installer.py --mode single
# 원격 설치 (제어 서버에서)
cd opensql-installer
python3 opensql_remote_installer.py --mode singlenode1: Primary PostgreSQL + Patroni + etcd
node2: Standby PostgreSQL + Patroni + etcd + OpenProxy
node3: Standby PostgreSQL + Patroni + etcd + OpenProxy# 모든 노드에서 공통
NODE1_IP="192.168.1.10"
NODE2_IP="192.168.1.11"
NODE3_IP="192.168.1.12"
OPENSQL_HOME="/home/opensql"
# node1에서 실행 시
NODE_NAME="db-primary"
LICENSE_NAME="node1_license.xml"
# node2에서 실행 시 → NODE_NAME="db-standby1", LICENSE_NAME="node2_license.xml"
# node3에서 실행 시 → NODE_NAME="db-standby2", LICENSE_NAME="node3_license.xml"NODE1_NAME="db-primary"
NODE1_SSH_USER="ec2-user"
NODE1_SSH_PORT="22"
NODE1_OPENSQL_HOME="/home/opensql"
NODE1_LICENSE_NAME="node1_license.xml"
NODE2_NAME="db-standby1"
NODE2_SSH_USER="ec2-user"
NODE2_SSH_PORT="22"
NODE2_OPENSQL_HOME="/home/opensql"
NODE2_LICENSE_NAME="node2_license.xml"
NODE3_NAME="db-standby2"
NODE3_SSH_USER="ec2-user"
NODE3_SSH_PORT="22"
NODE3_OPENSQL_HOME="/home/opensql"
NODE3_LICENSE_NAME="node3_license.xml"# 로컬 설치 (각 노드에서 NODE_NAME/LICENSE_NAME 변경 후 실행)
cd opensql-installer
python3 opensql_local_installer.py --mode 3node
# 원격 설치 (제어 서버에서 한 번에 실행)
cd opensql-installer
python3 opensql_remote_installer.py --mode 3nodenode1: PostgreSQL + Patroni + etcd + OpenProxy
node2: PostgreSQL + Patroni + etcd + OpenProxy
node3: etcd (witness only)# 모든 노드에서 공통
NODE1_IP="192.168.1.10"
NODE2_IP="192.168.1.11"
NODE3_IP="192.168.1.12"
OPENSQL_HOME="/home/opensql"
# witness etcd 포트 (필수 — 모든 노드에서 동일하게 설정)
WITNESS_ETCD_CLIENT_PORT=2379
WITNESS_ETCD_PEER_PORT=2380
# node1에서 실행 시
NODE_NAME="db-primary"
LICENSE_NAME="node1_license.xml"
# node2에서 실행 시 → NODE_NAME="db-standby", LICENSE_NAME="node2_license.xml"
# node3(witness)에서 실행 시 → NODE_NAME="witness", LICENSE_NAME=""CLUSTER_ID=c1NODE1_NAME="db-primary"
NODE1_SSH_USER="ec2-user"
NODE1_SSH_PORT="22"
NODE1_OPENSQL_HOME="/home/opensql"
NODE1_LICENSE_NAME="node1_license.xml"
NODE2_NAME="db-standby"
NODE2_SSH_USER="ec2-user"
NODE2_SSH_PORT="22"
NODE2_OPENSQL_HOME="/home/opensql"
NODE2_LICENSE_NAME="node2_license.xml"
NODE3_NAME="witness"
NODE3_SSH_USER="ec2-user"
NODE3_SSH_PORT="22"
NODE3_OPENSQL_HOME="/home/opensql"
# witness(node3)는 Patroni 없음 → LICENSE_NAME 비워둡니다.
NODE3_LICENSE_NAME=""# 로컬 설치 (각 노드에서 NODE_NAME/LICENSE_NAME 변경 후 실행)
cd opensql-installer
python3 opensql_local_installer.py --mode 2node-witness
# 원격 설치 (제어 서버에서 한 번에 실행)
cd opensql-installer
python3 opensql_remote_installer.py --mode 2node-witnesscd opensql-installer
python3 opensql_local_installer.py --mode 3node
python3 opensql_local_installer.py --mode single
python3 opensql_local_installer.py --mode 2node-witnesscd opensql-installer
# 기본 실행 (3node, 대화형 sudo 비밀번호 입력)
python3 opensql_remote_installer.py --mode 3node
# 공통 비밀번호 지정
python3 opensql_remote_installer.py --mode 3node --password "my_password"
# 노드별 비밀번호
python3 opensql_remote_installer.py --mode 3node \
--node1-password "pw1" \
--node2-password "pw2" \
--node3-password "pw3"export OPENSQL_HOME=/home/opensql
export PATH=/home/opensql/bin:$PATH
export LD_LIBRARY_PATH=/home/opensql/lib:$LD_LIBRARY_PATH
export PGHOST=/home/opensql/tmp
export PGDATA=/home/opensql/data
export OPENSQL_LICENSE_PATH=/home/opensql/license/node1_license.xmlvi /home/opensql/.opensqlrc
# 파일 끝에 추가
export PGOPTIONS="-c log_min_duration_statement=1000"
export PGTZ="Asia/Seoul"source ~/.opensqlrc# etcd 서비스 상태
sudo systemctl status opensql-etcd
# Patroni 프로세스
ps aux | grep patroni
# OpenProxy 프로세스
pgrep -f openproxy
# 클러스터 상태 (opensql 유저로)
patronictl -c /home/opensql/etc/patroni.yml listss -tunlp | grep -E "5432|6432|6433|2379|2380|8008"# opensql 유저로
psql -h 127.0.0.1 -p 5432 -U postgres
# OpenProxy를 통한 접속
psql -h 127.0.0.1 -p 6432 -U postgresRuntimeError: 현재 서버 IP(x.x.x.x)가 설정된 노드 IP와 일치하지 않습니다.ERROR: 키 등록 실패ssh-copy-id -i ~/.ssh/id_rsa_opensql ec2-user@192.168.1.10ERROR: 필수 패키지 요건을 충족하지 않습니다.
ERROR: 누락된 필수 패키지: python3-psycopg2ERROR: 라이선스 디렉토리를 찾을 수 없습니다: .../licenses
ERROR: 라이선스 파일을 찾을 수 없습니다: .../licenses/node1_license.xmlERROR: 라이선스 edition을 확인할 수 없습니다.ERROR: 라이선스 signature가 중복됩니다.ERROR: OPENSQL_LICENSE_PATH 미설정
ERROR: OPENSQL_LICENSE_PATH 불일치 (expected=..., actual=...)ERROR: etcd 시작 실패sudo journalctl -u opensql-etcd -n 100 --no-pagerss -tunlp | grep 2379ERROR: OpenProxy 프로세스가 실행되지 않았습니다.cat /home/opensql/logs/openproxy.log | tail -50ss -tunlp | grep 6432WARN: Patroni 상태 확인 필요cat /home/opensql/logs/patroni.log | tail -50curl http://192.168.1.10:8008/healthetcdctlETCDCTL_API23$ etcdctl member list
Error: dial tcp 127.0.0.1:2379: connect: connection refused$ which etcdctl
/usr/local/bin/etcdctl
$ etcdctl version
etcdctl version: 3.5.6
API version: 3.5$ ETCDCTL_API=3 etcdctl --endpoints="https://192.168.0.10:2379,https://192.168.0.11:2379" \
--key="./etcd-client-key.pem" \
--cert="./etcd-client-crt.pem" \
--cacert="./etcd-ca-crt.pem" \
member list$ etcdctl member list
670b863301943618, started, node1, http://192.168.0.10:2380, http://192.168.0.10:2379, false
7825d7b04510b842, started, node3, http://192.168.0.11:2380, http://192.168.0.11:2379, false
c8245114d55ec576, started, node2, http://192.168.0.12:2380, http://192.168.0.12:2379, false
$ etcdctl member list -w table
+------------------+---------+-------+--------------------------+--------------------------+------------+
| ID | STATUS | NAME | PEER ADDRS | CLIENT ADDRS | IS LEARNER |
+------------------+---------+-------+----------------------------+------------------------+------------+
| 670b863301943618 | started | node1 | http://192.168.0.10:2380 | http://192.168.0.10:2379 | false |
| 7825d7b04510b842 | started | node3 | http://192.168.0.11:2380 | http://192.168.0.11:2379 | false |
| c8245114d55ec576 | started | node2 | http://192.168.0.12:2380 | http://192.168.0.12:2379 | false |
+------------------+---------+-------+----------------------------+------------------------+------------+$ etcdctl endpoint status -w table
+--------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
+--------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
| http://192.168.0.10:2379 | 670b863301943618 | 3.5.21 | 168 kB | true | false | 6 | 520 | 520 | |
| http://192.168.0.11:2379 | c8245114d55ec576 | 3.5.21 | 168 kB | false | false | 6 | 520 | 520 | |
| http://192.168.0.12:2379 | 7825d7b04510b842 | 3.5.21 | 168 kB | false | false | 6 | 520 | 520 | |
+--------------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+$ etcdctl get --prefix "/opensql/opensql/members" -w simple
/opensql/opensql/members/pg-1
{"conn_url":"postgres://192.168.131.12:5432/postgres","api_url":"http://192.168.131.12:8008/patroni","state":"running","role":"replica","version":"4.0.5","proxy_url":"postgres://192.168.131.15:6432/postgres","xlog_location":223510016,"replication_state":"streaming","timeline":3}
/opensql/opensql/members/pg-2
{"conn_url":"postgres://192.168.131.13:5432/postgres","api_url":"http://192.168.131.13:8008/patroni","state":"running","role":"primary","version":"4.0.5","proxy_url":"postgres://192.168.131.15:6432/postgres","xlog_location":223510016,"timeline":3}
/opensql/opensql/members/pg-3
{"conn_url":"postgres://192.168.131.14:5432/postgres","api_url":"http://192.168.131.14:8008/patroni","state":"running","role":"replica","version":"4.0.5","proxy_url":"postgres://192.168.131.15:6432/postgres","xlog_location":223510016,"replication_state":"streaming","timeline":3}$ etcdctl get "/opensql/opensql/members/pg-1" "/opensql/opensql/members/pg-3"
/opensql/opensql/members/pg-1
{"conn_url":"postgres://192.168.131.12:5432/postgres","api_url":"http://192.168.131.12:8008/patroni","state":"running","role":"replica","version":"4.0.5","proxy_url":"postgres://192.168.131.15:6432/postgres","xlog_location":223510016,"replication_state":"streaming","timeline":3}
/opensql/opensql/members/pg-2
{"conn_url":"postgres://192.168.131.13:5432/postgres","api_url":"http://192.168.131.13:8008/patroni","state":"running","role":"primary","version":"4.0.5","proxy_url":"postgres://192.168.131.15:6432/postgres","xlog_location":223510016,"timeline":3}
$ etcdctl get "/opensql/opensql/failover" "/opensql/opensql/historz"
/opensql/opensql/failover
{}
/opensql/opensql/history
[[1,223438192,"no recovery target specified","2025-04-18T14:27:03.269756+09:00","pg-1"],[2,223438824,"no recovery target specified","2025-04-21T15:13:37.632010+09:00","pg-2"]]## Endpoint Status를 확인해 각 노드에서 유지하고 있는 가장 최신 Revision 정보를 가져온다.
$ etcdctl endpoint status -w json | jq | grep 'revision'
"revision": 447871,
"revision": 447871,
"revision": 447871,
## 해당 Revision 이전 시점의 Revision들을 더 이상 참조되지 않는 상태로 지정한다.
$ rev=447871
$ etcdctl compact $rev
compacted revision 447871$ etcdctl defrag --endpoints "http://192.168.0.10:2379,http://192.168.0.11:2379,http://192.168.0.12:2379"
Finished defragmenting etcd member[http://192.168.0.10:2379]
Finished defragmenting etcd member[http://192.168.0.11:2379]
Finished defragmenting etcd member[http://192.168.0.12:2379]
$ etcdctl endpoint status --endpoints "..."
http://192.168.0.10:2379, 670b863301943618, 3.5.21, 25 kB, true, false, 8, 448000, 448000,
http://192.168.0.11:2379, c8245114d55ec576, 3.5.21, 25 kB, false, false, 8, 448000, 448000,
http://192.168.0.12:2379, 7825d7b04510b842, 3.5.21, 25 kB, false, false, 8, 448000, 448000,$ etcdctl check perf
60 / 60 Booooooooooooooooooooooooooooooooooooooooooooooooooooooom! 100.00% 1m0s
PASS: Throughput is 150 writes/s
PASS: Slowest request took 0.291186s
PASS: Stddev is 0.029467s
PASS$ etcdctl check perf
60 / 60 Booooooooooooooooooooooooooooooooooooooooooooooooooooooom! 100.00% 1m0s
PASS: Throughput is 150 writes/s
Slowest request took too long: 0.535645s
PASS: Stddev is 0.079037s
FAIL
$ etcdctl check perf --load="xl"
60 / 60 Booooooooooooooooooooooooooooooooooooooooooooooooooooooom! 100.00% 1m0s
FAIL: Throughput too low: 3668 writes/s
Slowest request took too long: 0.645609s
Stddev too high: 0.105516s
FAIL$ ls -l $ETCD_DATA_DIR/member/snap/
total 168
-rw-------. 1 opensql opensql 16805888 Apr 18 14:29 db
$ cp $ETCD_DATA_DIR/member/snap/db ./mysnapshot.db$ ETCDCTL_API=3 etcdctl --endpoints=${ENDPOINT} snapshot save mysnapshot.db
{"level":"info","ts":"2025-04-21T12:18:30.406283+0900","caller":"snapshot/v3_snapshot.go:65","msg":"created temporary db file","path":"mysnapshot.db.part"}
{"level":"info","ts":"2025-04-21T12:18:30.407142+0900","logger":"client","caller":"v3@v3.5.21/maintenance.go:212","msg":"opened snapshot stream; downloading"}
{"level":"info","ts":"2025-04-21T12:18:30.407162+0900","caller":"snapshot/v3_snapshot.go:73","msg":"fetching snapshot","endpoint":"192.168.131.12:2379"}
{"level":"info","ts":"2025-04-21T12:18:30.432538+0900","logger":"client","caller":"v3@v3.5.21/maintenance.go:220","msg":"completed snapshot read; closing"}
{"level":"info","ts":"2025-04-21T12:18:30.480983+0900","caller":"snapshot/v3_snapshot.go:88","msg":"fetched snapshot","endpoint":"192.168.131.12:2379","size":"168 kB","took":"now"}
{"level":"info","ts":"2025-04-21T12:18:30.481039+0900","caller":"snapshot/v3_snapshot.go:97","msg":"saved","path":"mysnapshot.db"}
Snapshot saved at mysnapshot.db$ ETCDCTL_API=3 etcdctl snapshot restore ./mysnapshot.db \
--name node3 \
--initial-cluster node1=http://192.168.0.8:2380,node2=http://192.168.0.9:2380,node3=http://192.168.0.10:2380 \
--initial-cluster-token new-etcd-cluster \
--initial-advertise-peer-urls http://192.168.0.10:2380 \
--skip-hash-check \
# ...
Deprecated: Use `etcdutl snapshot restore` instead.
snapshot/v3_snapshot.go:248 restoring snapshot {"path": "member/snap/db", "wal-dir": "node3.etcd/member/wal", "data-dir": "node3.etcd", "snap-dir": "node3.etcd/member/snap", "stack": "go.etcd.io/..." }
membership/store.go:141 Trimming membership information from the backend...
membership/cluster.go:421 added member {"cluster-id": "154dfe96307df6f0", "local-member-id": "0", "added-peer-id": "3dfe6fc7fff49d22", "added-peer-peer-urls": ["http://192.168.0.8:2380"]}
membership/cluster.go:421 added member {"cluster-id": "154dfe96307df6f0", "local-member-id": "0", "added-peer-id": "7f846315e3b9872d", "added-peer-peer-urls": ["http://192.168.0.9:2380"]}
membership/cluster.go:421 added member {"cluster-id": "154dfe96307df6f0", "local-member-id": "0", "added-peer-id": "c0ea9022befd3eaa", "added-peer-peer-urls": ["http://192.168.0.10:2380"]}
snapshot/v3_snapshot.go:269 restored snapshot {"path": "member/snap/db", "wal-dir": "node3.etcd/member/wal", "data-dir": "node3.etcd", "snap-dir": "node3.etcd/member/snap"}$ ls -l
total 0
drwx------. 3 root root 20 Mar 17 14:48 node1.etcd
$ ls -l node1.etcd/
drwx------. 2 root root 246 Mar 17 14:41 snap
drwx------. 2 root root 257 Mar 17 14:41 wal$ rm -rf $ETCD_DATA_DIR/member
$ cp -r node1.etcd $ETCD_DATA_DIR/member
## Service 정의에 참조된 etcd.env 파일 내용 확인
$ vi $OPENSQL_HOME/etc/etcd/etcd.env
ETCD_NAME=node1
ETCD_INITIAL_CLUSTER=node1=http://192.168.0.8:2380,node2=http://192.168.0.9:2380,node3=http://192.168.0.10:2380
ETCD_INITIAL_CLUSTER_TOKEN=new-etcd-cluster
ETCD_INITIAL_CLUSTER_STATE=new
--initial-cluster-token new-etcd-cluster \
--initial-advertise-peer-urls http://192.168.0.8:2380 \
$ systemctl restart etcd.service--skip-hash-checkscope: batman
#namespace: /service/
name: postgresql0log:
type: plain
format: "[%(asctime)s] [%(module)s] [%(levelname)s]: %(message)s"
dir: /etc/patroni/logsrestapi:
listen: 0.0.0.0:8008
connect_address: 192.168.0.100:8008etcd3:
protocol: http
# host: 192.168.0.100:2379
hosts:
- 192.168.0.1:2379
- 192.168.0.2:2379
- 192.168.0.3:2379bootstrap:
# This section will be written into Etcd:/<namespace>/<scope>/config after initializing new cluster
# and all other cluster members will use it as a `global configuration`.
# WARNING! If you want to change any of the parameters that were set up
# via `bootstrap.dcs` section, please use `patronictl edit-config`!
dcs:
ttl: 30
loop_wait: 10
retry_timeout: 10
maximum_lag_on_failover: 1048576
# primary_start_timeout: 300
# synchronous_mode: false
#standby_cluster:
#host: 127.0.0.1
#port: 1111
#primary_slot_name: patroni
slots:
barman:
type: physical
postgresql:
use_pg_rewind: true
use_slots: true
parameters:
# wal_level: hot_standby
# hot_standby: "on"
max_connections: 100
max_worker_processes: 8
# wal_keep_segments: 8
# max_wal_senders: 10
# max_replication_slots: 10
# max_prepared_transactions: 0
# max_locks_per_transaction: 64
# wal_log_hints: "on"
# track_commit_timestamp: "off"
# archive_mode: "on"
# archive_timeout: 1800s
# archive_command: mkdir -p ../wal_archive && test ! -f ../wal_archive/%f && cp %p ../wal_archive/%f
# recovery_conf:
# restore_command: cp ../wal_archive/%f %p
# some desired options for 'initdb'
initdb: # Note: It needs to be a list (some options need values, others are switches)
- encoding: UTF8
- data-checksumspostgresql:
listen: 0.0.0.0:5432
connect_address: 192.168.0.100:5432
proxy_address: 127.0.0.1:6432 # The address of connection pool (e.g., pgbouncer) running next to Patroni/Postgres. Only for service discovery.
#data_dir: data/postgresql0
data_dir: /var/lib/pgsql/16/data
bin_dir: /usr/pgsql-16/bin
# config_dir:
pgpass: /tmp/pgpass0
authentication:
replication:
username: patroni_repl
password: patroni_repl
superuser:
username: postgres
password: zalando
rewind: # Has no effect on postgres 10 and lower
username: patroni_rewind
password: patroni_rewind
pg_hba:
# For kerberos gss based connectivity (discard @.*$)
- local all all trust
- host replication patroni_repl 192.168.0.0/24 trust
- host replication patroni_repl 127.0.0.1/32 trust
- host all all 0.0.0.0/0 md5
- host all barman 192.168.0.0/24 trust
- host replication streaming_barman 192.168.0.0/24 trust
parameters:
log_line_prefix: '%m [%r] [%u] [%a]'
archive_command: 'barman-wal-archive node4 pg %p'
archive_mode: 'true'
wal_level: 'replica'$ patronictl list
2024-10-29 17:20:56,603 - WARNING - Listing members: No cluster names were provided
$ patronictl list opensql
Error: Can not find suitable configuration of distributed configuration store
Available implementations: etcd, etcd3, kubernetes$ patronictl -c $OPENSQL_HOME/etc/patroni.yml list
+ Cluster: opensql (7364637789542980847) ----------+----+-----------+------------------------+
| Member | Host | Role | State | TL | Lag in MB | Tags |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
| postgresql0 | 192.1.1.218 | Replica | streaming | 16 | 0 | |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
| postgresql1 | 192.1.1.236 | Replica | streaming | 16 | 0 | failover_priority: 150 |
| | | | | | | nofailover: false |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
| postgresql2 | 192.1.1.238 | Leader | running | 16 | | |
+-------------+-------------+---------+-----------+----+-----------+------------------------+$ alias pctl='patronictl -c $OPENSQL_HOME/etc/patroni.yml'
$ echo 'alias pctl="patronictl -c $OPENSQL_HOME/etc/patroni.yml"' >> ~/.bashrc
$ pctl list
+ Cluster: opensql (7364637789542980847) ----------+----+-----------+------------------------+
| Member | Host | Role | State | TL | Lag in MB | Tags |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
| postgresql0 | 192.1.1.218 | Replica | streaming | 16 | 0 | |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
| postgresql1 | 192.1.1.236 | Replica | streaming | 16 | 0 | failover_priority: 150 |
| | | | | | | nofailover: false |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
| postgresql2 | 192.1.1.238 | Leader | running | 16 | | |
+-------------+-------------+---------+-----------+----+-----------+------------------------+$ patronictl list
2024-10-29 15:36:15,282 - WARNING - Listing members: No cluster names were provided
## 테이블 형태로 조회 (기본 옵션)
$ patronictl -c $OPENSQL_HOME/etc/patroni.yml list
+ Cluster: opensql (7364637789542980847) ----------+----+-----------+------------------------+
| Member | Host | Role | State | TL | Lag in MB | Tags |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
| postgresql0 | 192.1.1.218 | Replica | streaming | 16 | 0 | |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
| postgresql1 | 192.1.1.236 | Replica | streaming | 16 | 0 | failover_priority: 150 |
| | | | | | | nofailover: false |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
| postgresql2 | 192.1.1.238 | Leader | running | 16 | | |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
## JSON 형태로 조회
$ patronictl -c $OPENSQL_HOME/etc/patroni.yml list -f json
[{"Cluster": "opensql", "Member": "postgresql0", "Host": "192.1.1.218", "Role": "Leader", "State": "running", "TL": 17}, {"Cluster": "opensql", "Member": "postgresql1", "Host": "192.1.1.236", "Role": "Replica", "State": "streaming", "TL": 17, "Lag in MB": 0, "Tags": {"nofailover": false, "failover_priority": 150}}, {"Cluster": "opensql", "Member": "postgresql2", "Host": "192.1.1.238", "Role": "Replica", "State": "streaming", "TL": 17, "Lag in MB": 0}]$ patronictl -c $OPENSQL_HOME/etc/patroni.yml topology
+ Cluster: opensql (7364637789542980847) +-----------+----+-----------+---------------------------------------------+
| Member | Host | Role | State | TL | Lag in MB | Tags |
+---------------+-------------+---------+-----------+----+-----------+---------------------------------------------+
| postgresql2 | 192.1.1.238 | Leader | running | 21 | | |
| + postgresql0 | 192.1.1.218 | Replica | streaming | 21 | 0 | |
| + postgresql1 | 192.1.1.236 | Replica | streaming | 21 | 0 | {failover_priority: 150, nofailover: false} |
+---------------+-------------+---------+-----------+----+-----------+---------------------------------------------+$ patronictl -c $OPENSQL_HOME/etc/patroni.yml dsn
host=192.1.1.238 port=5432$ patronictl -c $OPENSQL_HOME/etc/patroni.yml dsn -r replica
host=192.1.1.218 port=5432
$ patronictl -c $OPENSQL_HOME/etc/patroni.yml dsn -m postgresql1
host=192.1.1.236 port=5432$ pctl restart <cluster_name>$ pctl restart opensql postgresql0
+ Cluster: opensql (7364637789542980847) ----------+----+-----------+------------------------+
| Member | Host | Role | State | TL | Lag in MB | Tags |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
| postgresql0 | 192.1.1.218 | Replica | streaming | 16 | 0 | |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
| postgresql1 | 192.1.1.236 | Replica | streaming | 16 | 0 | failover_priority: 150 |
| | | | | | | nofailover: false |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
| postgresql2 | 192.1.1.238 | Leader | running | 16 | | |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
When should the restart take place (e.g. 2024-10-31T12:16) [now]:
## now를 입력하면 바로 재시작
Are you sure you want to restart members postgresql0? [y/N]:
Restart if the PostgreSQL version is less than provided (e.g. 9.5.2) []:
Success: restart on member postgresql0$ pctl reload <cluster_name>$ pctl reload opensql
+ Cluster: opensql (7364637789542980847) ----------+----+-----------+------------------------+
| Member | Host | Role | State | TL | Lag in MB | Tags |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
| postgresql0 | 192.1.1.218 | Replica | streaming | 16 | 0 | |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
| postgresql1 | 192.1.1.236 | Replica | streaming | 16 | 0 | failover_priority: 150 |
| | | | | | | nofailover: false |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
| postgresql2 | 192.1.1.238 | Leader | running | 16 | | |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
Are you sure you want to reload members postgresql0, postgresql1, postgresql2? [y/N]:
Reload request received for member postgresql0 and will be processed within 10 seconds
Reload request received for member postgresql1 and will be processed within 10 seconds
Reload request received for member postgresql2 and will be processed within 10 seconds$ pctl history
+----+------------+------------------------------+----------------------------------+-------------+
| TL | LSN | Reason | Timestamp | New Leader |
+----+------------+------------------------------+----------------------------------+-------------+
| 1 | 26875256 | no recovery target specified | 2024-05-03T14:20:28.841738+09:00 | postgresql2 |
| 2 | 213072680 | no recovery target specified | 2024-05-03T14:45:37.945208+09:00 | postgresql1 |
| 3 | 213101064 | no recovery target specified | 2024-05-03T14:46:14.686504+09:00 | postgresql2 |
| 4 | 805306528 | no recovery target specified | 2024-05-28T17:44:02.808722+09:00 | postgresql1 |
| 5 | 855638176 | no recovery target specified | 2024-05-28T17:54:12.358175+09:00 | postgresql2 |
| 6 | 1879048352 | no recovery target specified | 2024-07-30T15:58:10.527327+09:00 | postgresql0 |
| 7 | 1895825568 | no recovery target specified | 2024-07-30T15:58:52.408275+09:00 | postgresql2 |
| 8 | 2013266080 | no recovery target specified | 2024-08-12T10:00:38.641449+09:00 | postgresql2 |
| 9 | 2030043296 | no recovery target specified | 2024-08-12T10:04:16.370771+09:00 | postgresql2 |
| 10 | 2046820512 | no recovery target specified | 2024-08-12T10:05:07.178679+09:00 | postgresql2 |
| 11 | 2063597728 | no recovery target specified | 2024-08-12T10:47:06.368795+09:00 | postgresql2 |
| 12 | 2080374944 | no recovery target specified | 2024-08-12T10:50:59.596850+09:00 | postgresql2 |
| 13 | 2332033184 | no recovery target specified | 2024-10-28T13:41:28.936064+09:00 | postgresql1 |
| 14 | 2348810400 | no recovery target specified | 2024-10-28T16:04:27.587725+09:00 | postgresql0 |
| 15 | 2365587616 | no recovery target specified | 2024-10-28T16:16:32.842442+09:00 | postgresql2 |
+----+------------+------------------------------+----------------------------------+-------------+$ patronictl -c $OPENSQL_HOME/etc/patroni.yml query -U postgres --password -c "SELECT VERSION();"
Password:
version
PostgreSQL 14.13 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44), 64-bit$ patronictl -c $OPENSQL_HOME/etc/patroni.yml failover
Current cluster topology
+ Cluster: opensql (7364637789542980847) ----------+----+-----------+------------------------+
| Member | Host | Role | State | TL | Lag in MB | Tags |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
| postgresql0 | 192.1.1.218 | Replica | streaming | 20 | 0 | |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
| postgresql1 | 192.1.1.236 | Leader | running | 20 | | failover_priority: 150 |
| | | | | | | nofailover: false |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
| postgresql2 | 192.1.1.238 | Replica | streaming | 20 | 0 | |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
Candidate ['postgresql0', 'postgresql2'] []: postgresql2
Are you sure you want to failover cluster opensql, demoting current leader postgresql1? [y/N]: y
2024-11-04 16:36:12.20700 Successfully failed over to "postgresql2"
+ Cluster: opensql (7364637789542980847) --------+----+-----------+------------------------+
| Member | Host | Role | State | TL | Lag in MB | Tags |
+-------------+-------------+---------+---------+----+-----------+------------------------+
| postgresql0 | 192.1.1.218 | Replica | running | 20 | 0 | |
+-------------+-------------+---------+---------+----+-----------+------------------------+
| postgresql1 | 192.1.1.236 | Replica | stopped | | unknown | failover_priority: 150 |
| | | | | | | nofailover: false |
+-------------+-------------+---------+---------+----+-----------+------------------------+
| postgresql2 | 192.1.1.238 | Leader | running | 20 | | |
+-------------+-------------+---------+---------+----+-----------+------------------------+$ patronictl -c $OPENSQL_HOME/etc/patroni.yml switchover
Current cluster topology
+ Cluster: opensql (7364637789542980847) ----------+----+-----------+------------------------+
| Member | Host | Role | State | TL | Lag in MB | Tags |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
| postgresql0 | 192.1.1.218 | Leader | running | 19 | | |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
| postgresql1 | 192.1.1.236 | Replica | streaming | 19 | 0 | failover_priority: 150 |
| | | | | | | nofailover: false |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
| postgresql2 | 192.1.1.238 | Replica | streaming | 19 | 0 | |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
Primary [postgresql0]: postgresql0
Candidate ['postgresql1', 'postgresql2'] []: postgresql1
When should the switchover take place (e.g. 2024-11-04T17:34 ) [now]: now
Are you sure you want to switchover cluster opensql, demoting current leader postgresql0? [y/N]: y
2024-11-04 16:35:07.34291 Successfully switched over to "postgresql1"
+ Cluster: opensql (7364637789542980847) --------+----+-----------+------------------------+
| Member | Host | Role | State | TL | Lag in MB | Tags |
+-------------+-------------+---------+---------+----+-----------+------------------------+
| postgresql0 | 192.1.1.218 | Replica | stopped | | unknown | |
+-------------+-------------+---------+---------+----+-----------+------------------------+
| postgresql1 | 192.1.1.236 | Leader | running | 19 | | failover_priority: 150 |
| | | | | | | nofailover: false |
+-------------+-------------+---------+---------+----+-----------+------------------------+
| postgresql2 | 192.1.1.238 | Replica | running | 19 | 0 | |
+-------------+-------------+---------+---------+----+-----------+------------------------+$ patronictl -c $OPENSQL_HOME/etc/patroni.yml pause
Success: cluster management is paused
$ patronictl -c $OPENSQL_HOME/etc/patroni.yml list
+ Cluster: opensql (7364637789542980847) ----------+----+-----------+------------------------+
| Member | Host | Role | State | TL | Lag in MB | Tags |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
| postgresql0 | 192.1.1.218 | Replica | streaming | 25 | 0 | |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
| postgresql1 | 192.1.1.236 | Replica | streaming | 25 | 0 | failover_priority: 150 |
| | | | | | | nofailover: false |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
| postgresql2 | 192.1.1.238 | Leader | running | 25 | | |
+-------------+-------------+---------+-----------+----+-----------+------------------------+
Maintenance mode: on$ patronictl -c $OPENSQL_HOME/etc/patroni.yml resume
Success: cluster management is resumed$ patronictl -c $OPENSQL_HOME/etc/patroni.yml show-config
loop_wait: 10
maximum_lag_on_failover: 1048576
postgresql:
parameters:
archive_command: barman-wal-archive node4 pg %p
archive_mode: 'true'
authentication_timeout: '200'
log_line_prefix: '%m [%r] [%u] [%a]'
max_connections: '250'
wal_level: replica
wal_receiver_timeout: '30000'
pg_hba:
- local all all trust
- host replication patroni_repl 192.1.1.218/26 trust
- host replication patroni_repl 127.0.0.1/32 trust
- host all all 0.0.0.0/0 md5
- host all barman 192.1.1.218/26 trust
- host replication streaming_barman 192.1.1.218/26 trust
use_pg_rewind: true
use_slots: true
retry_timeout: 10
slots:
barman:
type: physical
ttl: 30$ pctl edit-configloop_wait: 10
maximum_lag_on_failover: 1048576
postgresql:
parameters:
archive_command: barman-wal-archive node4 pg %p
archive_mode: 'false'
authentication_timeout: '500'
log_line_prefix: '%m [%r] [%u] [%a]'
max_connections: 500
wal_level: replica
wal_receiver_timeout: '30000'
pg_hba:
- local all all trust
- host replication patroni_repl 192.1.1.218/26 trust
- host replication patroni_repl 127.0.0.1/32 trust
- host all all 0.0.0.0/0 md5
- host all barman 192.1.1.218/26 trust
- host replication streaming_barman 192.1.1.218/26 trust
use_pg_rewind: true
use_slots: true
retry_timeout: 10
slots:
barman:
type: physical
ttl: 45
~
~
~
~
"/tmp/opensql-config-m332oce3.yaml" 25L, 683CDBMS_JOB, DBMS_SCHEDULER 패키지 사용을 위한 필수 프레임워크 o2 scheduler에 대한 스케쥴러(scheduler) 참조서입니다.
CPU 코어 수 + 약간의 여유postgresql.conf 파일 내부 내용 중
...
#shared_preload_libraries = '' # (change requires restart) <= 이 라인을 아래와 같이 수정합니다.
shared_preload_libraries = 'o2scheduler'
(이때, 라인의 맨 앞 '#' 문자도 반드시 제거해줍니다.)shared_preload_libraries = 'a,b' <- 이미 a,b extension들이 추가되어있을 경우, 이어서 o2scheduler를 추가합니다.
=> shared_preload_libraries = 'a,b,o2scheduler'postgresql.conf 파일 내부 내용 중
...
#max_worker_processes = 8 # (change requires restart) <= 이 라인을 아래와 같이 수정합니다.
max_worker_processes = {원하는 숫자}
(이때, 라인의 맨 앞 '#' 문자도 반드시 제거해줍니다)create extension o2scheduler;root=# create extension o2scheduler;
CREATE EXTENSION
root=# \dx
List of installed extensions
Name | Version | Schema | Description
-------------+---------+------------+--------------------------------------------------------------
o2scheduler | 1.0 | public | Provides scheduler functions compatible with Oracle database
plpgsql | 1.0 | pg_catalog | PL/pgSQL procedural language
(2 rows)postgresCONNECTWARNINFODEBUGTRACE[general]
port = 6432
admin_username = "postgres"
admin_password = "postgres"
worker_threads = 3
[pools.postgres]
pool_mode = "transaction"
query_parser_enabled = true
query_parser_read_write_splitting = true
[pools.postgres.users.0]
username = "postgres"
password = "postgres"
server_username = "postgres"
server_password = "postgres"
pool_size = 10
statement_timeout = 0
[pools.postgres.shards.0]
database = "postgres"
servers = [
["172.176.0.2", 5432, "auto"],
["172.176.0.3", 5432, "auto"],
["172.176.0.4", 5432, "auto"]
]
use_patroni = true
## virtual-ip
[general.virtual_router]
interface = "eth0"
router_id = 50
priority = 50
advert_int = 3
vip_addresses = ["178.176.0.200/24"]$ ./openproxy /home/myUser/openproxy.toml$ openproxy --help
OpenProxy: PostgreSQL pooler for OpenSQL - fork of pgCat
Usage: openproxy [OPTIONS] [CONFIG_FILE] [COMMAND]
Commands:
show Print current config and exit (loads config from file/etcd same as normal startup)
edit Edit config and save. Without --set: interactive (open in $EDITOR). With --set: non-interactive
encode Encode user password into SCRAM-SHA-256 compatible password that can be used for "password" in config
stop Stop a running openproxy instance via the admin console
help Print this message or the help of the given subcommand(s)
Arguments:
[CONFIG_FILE] Path to a configuration TOML file [env: CONFIG_FILE=] [default: openproxy.toml]
Options:
--force-config-file
Load config only from file; ignore etcd even if enabled in config
--log-target <LOG_TARGET>
Where to emit logs: file only, stdout only, or both [env: LOG_TARGET=] [default: both] [possible values: file, stdout, both]
-l, --log-level <LOG_LEVEL>
Logging level (trace, debug, info, warn, error) [env: LOG_LEVEL=] [default: INFO]
--max-logfile-num <MAX_LOGFILE_NUM>
Maximum number of log files to keep when rotating [env: MAX_LOGFILE_NUM=] [default: 5]
--log-dir <LOG_DIR>
Directory for log files (used when log_target is file or both) [env: LOG_DIR=/home/opensql/logs/openproxy] [default: logs]
--revision
Print revision number
-F, --log-format <LOG_FORMAT>
Log output format: text (human-readable), structured (e.g. JSON), or debug [env: LOG_FORMAT=] [default: text] [possible values: text, structured, debug]
-h, --help
Print help
-V, --version
Print version$ openproxy --help
$ openproxy --version
openproxy 1.1.0
$ openproxy --revision
revision number: 681[Unit]
Description=OpenProxy connection pooler - fork of postgresml's pgcat
After=network.target
StartLimitIntervalSec=0
[Service]
User=opensql
Type=simple
Restart=always
RestartSec=1
Environment=LOG_LEVEL=info
LimitNOFILE=65536
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW
ExecStart=/usr/bin/openproxy /etc/openproxy.toml
[Install]
WantedBy=multi-user.target$ psql -h 127.0.0.1 -p 6432 -d openproxy -U postgres
openproxy=> SHOW HELP;
NOTICE: Console usage
DETAIL:
SHOW HELP|CONFIG|DATABASES|POOLS|CLIENTS|SERVERS|USERS|VERSION
SHOW LISTS
SHOW STATS
SET key = arg
RELOAD
PAUSE [<db>, <user>]
RESUME [<db>, <user>]
SHUTDOWNopenproxy=> SHOW VERSION;
version
-------------------------
OpenProxy 1.1.0
(1 row)openproxy=> SHOW CONFIG;
key | value | default | changeable
--------------------------------------------------+----------------+---------+------------
idle_client_in_transaction_timeout | 30000 | - | yes
pools."postgres".users | postgres | - | yes
prometheus_exporter_port | 9930 | - | yes
pools.postgres.query_parser_max_length | unlimited | - | yes
pools.postgres.load_balancing_mode | random | - | yes
pools."postgres".shard_count | 1 | - | yes
port | 6432 | - | no
connect_timeout | 1000 | - | no
healthcheck_timeout | 1000 | - | yes
pools.postgres.default_role | any | - | yes
healthcheck_delay | 30000 | - | yes
pools.postgres.query_parser_read_write_splitting | true | - | yes
pools.postgres.sharding_function | pg_bigint_hash | - | yes
ban_time | 60 | - | yes
pools.postgres.pool_mode | transaction | - | yes
shutdown_timeout | 60000 | - | yes
host | 0.0.0.0 | - | no
pools.postgres.primary_reads_enabled | false | - | yes
idle_timeout | 600000 | - | yes
pools.postgres.query_parser_enabled | true | - | yes
(20 rows)openproxy=> SHOW DATABASES;
name | host | port | database | force_user | pool_size | min_pool_size | reserve_pool | pool_mode | max_connections | current_connections | paused | disabled
----------------------------+----------------+------+----------+------------+-----------+---------------+--------------+-------------+-----------------+---------------------+--------+----------
postgres_shard_0_primary | 192.168.131.12 | 5432 | postgres | postgres | 1100 | 0 | 0 | transaction | 1100 | 0 | 0 | 0
postgres_shard_0_replica_0 | 192.168.131.13 | 5432 | postgres | postgres | 1100 | 0 | 0 | transaction | 1100 | 0 | 0 | 0
postgres_shard_0_replica_1 | 192.168.131.14 | 5432 | postgres | postgres | 1100 | 0 | 0 | transaction | 1100 | 0 | 0 | 0
(3 rows)openproxy=> SHOW POOLS;
database | user | pool_mode | cl_idle | cl_active | cl_waiting | cl_cancel_req | sv_active | sv_idle | sv_used | sv_tested | sv_login | maxwait | maxwait_us
-----------+-------------+-------------+---------+-----------+------------+---------------+-----------+---------+---------+-----------+----------+---------+------------
simple_db | simple_user | session | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
postgres | postgres | transaction | 0 | 0 | 0 | 0 | 0 | 3 | 0 | 0 | 0 | 0 | 0
(2 rows)openproxy=> SHOW CLIENTS;
client_id | database | user | application_name | state | transaction_count | query_count | error_count | age_seconds | maxwait | maxwait_us
------------+----------+----------+------------------+-------+-------------------+-------------+-------------+-------------+---------+------------
0x43332945 | postgres | postgres | openproxy | idle | 8 | 8 | 0 | 9 | 0 | 8
0x993A6EA2 | postgres | postgres | openproxy | idle | 10 | 10 | 0 | 9 | 0 | 8
0x09CFDA65 | pgcat | postgres | psql | idle | 0 | 0 | 0 | 208 | 0 | 0
0x1E5A084D | postgres | postgres | openproxy | idle | 10 | 10 | 0 | 4 | 0 | 9
(4 rows)openproxy=> SHOW SERVERS;
server_id | database_name | user | address_id | application_name | state | transaction_count | query_count | bytes_sent | bytes_received | age_seconds | prepare_cache_hit | prepare_cache_miss | prepare_cache_eviction | prepare_cache_size
------------+---------------+----------+--------------------------+--------------------------------------+-------+-------------------+-------------+------------+----------------+-------------+-------------------+--------------------+------------------------+--------------------
0x342F491B | postgres | postgres | postgres_shard_0_primary | DBeaver 22.3.4 - SQLEditor <Console> | idle | 41 | 41 | 18760 | 302727 | 25 | 123 | 82 | 0 | 41
(1 row)openproxy=> SHOW USERS;
name | pool_mode
----------+-------------
postgres | transaction
(1 row)openproxy=> SHOW LISTS;
list | items
---------------+-------
databases | 4
users | 2
pools | 4
free_clients | 4
used_clients | 0
login_clients | 0
free_servers | 1
used_servers | 0
dns_names | 0
dns_zones | 0
dns_queries | 0
dns_pending | 0
(12 rows)openproxy=> SHOW STATS;
instance | database | user | total_xact_count | total_query_count | total_received | total_sent | total_xact_time | total_query_time | total_wait_time | total_errors | avg_xact_count | avg_query_count | avg_recv | avg_sent | avg_errors | avg_xact_time | avg_query_time | avg_wait_time
----------------------------+----------+----------+------------------+-------------------+----------------+------------+-----------------+------------------+-----------------+--------------+----------------+-----------------+----------+----------+------------+---------------+----------------+---------------
postgres_shard_0_primary | postgres | postgres | 41 | 41 | 302727 | 18760 | 0 | 39 | 14152 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
postgres_shard_0_replica_0 | postgres | postgres | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
postgres_shard_0_replica_1 | postgres | postgres | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0
(3 rows)sudo systemctl enable --now chronydtimedatectl status
chronyc sources -v
date

뷰에 대한 참조 안내서입니다.
{schema_name}.{view_name}
-- 예시) o2views extension 설치 후, 새로 추가된 dba_tab_columns라는 뷰 사용합니다.
-- select * from oracle.dba_tab_columns;
-- 현재 접속 세션에서 스미카 'oracle'를 가장 우선순위 높은 search_path로 설정합니다.
set search_path to oracle, public;
{view_name}
-- 예시) o2views extension 설치 후, 새로 추가된 dba_tab_columns라는 뷰 사용합니다.
-- select * from dba_tab_columns;