MongoDB의 TTL(Time-To-Live) Index는 일정 시간이 expired Document를 자동으로 삭제하는 기능이며
로그, 세션, 캐시 데이터 등등 기간이 있는 데이터에 사용됩니다.

OS환경 : Centos Linux 7.9 (64bit)
DB 환경 : MongoDB 6.0.19

 

 

🤔 TTL Index란?

TTL 인덱스는 문서에 있는 Date 타입 필드를 기준으로 일정 시간이 지나면

MongoDB가 백그라운드 작업으로 해당 Document를 삭제합니다.

삭제는 실시간이 아니라 약 60초 간격의 백그라운드 스케줄러가 수행됨

 

 

✅ TTL INDEX 만드는 방법

db.logs.createIndex({ "createdAt": 1 }, { expireAfterSeconds: 3600 })
  • createdAt: Date 필드
  • expireAfterSeconds: 생성된 시간 기준으로 3600초(=1시간) 후 삭제


TTL 인덱스의 특징과 주의사항

  • TTL 인덱스는 단일 필드만 허용되며, 복합 인덱스로는 설정 불가
  • 기준 필드는 Date 타입이어야 하며, 문자열 또는 숫자는 동작 불가 
※ update()를 통해 Date 필드를 갱신하면 TTL 타이머가 초기화됩니다.



🧪 TTL INDEX 테스트 시나리오

1. 테스트 환경 초기화

TTL 인덱스를 실험하기 위해 사용할 ttl_test 데이터베이스와 sessions 컬렉션을 정리합니다.
MongoDB는 Document를 insert하면 Collection이 자동으로 생성되기 때문에, 따로 createCollection() 명령은 생략해도 됩니다.

use ttl_test
db.sessions.drop() // 이전 테스트가 남아있을 수 있으므로 기존 컬렉션을 삭제
※ 참고 db.sessions.drop()은 기존 컬렉션 및 인덱스를 삭제하는 명령입니다. 테스트 전 초기화 하기 위한 작업

 

2. TTL 인덱스 생성

createdAt필드를 기준으로, Document가 삽입된 후 30초가 지나면 자동으로 삭제되도록 설정합니다.

db.sessions.createIndex(
  { "createdAt": 1 },
  { expireAfterSeconds: 30 }
)

 

3. 테스트 데이터 Insert

현재 시간 기준으로 createdAt 필드를 포함하여 session collection에 Document를 Insert 합니다.

db.sessions.insertOne({
  userId: "korea123",
  createdAt: new Date()
})

 

4. Document 확인 및 삭제 확인

Document 가 잘 Insert되었는지 확인한 후, 30~90초 정도 기다렸다가 데이터 삭제 여부를 다시 확인합니다.

// 삽입 직후 확인
db.sessions.find()
TestReplSet [direct: primary] ttl_test> db.sessions.find()
[
  {
    _id: ObjectId('682a93668711c6afa4625e60'),
    userId: 'korea123',
    createdAt: ISODate('2025-05-19T02:11:50.933Z')
  }
]


// 약 1분 후 재확인 (자동 삭제됨)
db.sessions.find()
※참고: MongoDB는 TTL 삭제를 실시간으로 수행하지 않습니다.
내부 TTL Monitor가 약 60초 간격으로 동작하기 때문에, 삭제 시점은 약간의 지연이 있을 수 있습니다.

 

TTL 인덱스는 세션, 로그, 인증 데이터처럼 시간이 지나면 자연스럽게 삭제되어야 하는 데이터에 매우 유용하면서 중요한 기능입니다. 불필요한 공간 낭비를 최소화 하기 위해 필요하며, 애플리케이션에서 별도의 삭제 로직을 구현하지 않아도 되므로 개발 효율성과 시스템 자원 관리를 동시에 잡을 수 있습니다.



🙌 댓글, 공감, 공유는 큰 힘이 됩니다! 😄

 

참조 : https://www.mongodb.com/ko-kr/docs/manual/core/index-ttl/

https://www.mongodb.com/ko-kr/docs/manual/tutorial/expire-data/

 

✅ 테이블별 I/U/D 건수 측정 쿼리

SELECT 
  relname AS table_name,
  n_tup_ins AS inserts,
  n_tup_upd AS updates,
  n_tup_del AS deletes,
  n_live_tup AS live_rows,
  n_dead_tup AS dead_rows,
  round((n_tup_upd + n_tup_del)::numeric / NULLIF(n_live_tup, 0), 3) AS churn_ratio
FROM pg_stat_user_tables
ORDER BY churn_ratio DESC NULLS LAST;
컬럼 설명
n_tup_ins 총 insert 횟수
n_tup_upd 총 update 횟수
n_tup_del 총 delete 횟수
n_live_tup 현재 살아 있는 row
n_dead_tup 현재 vacuum 안된 죽은 row
churn_ratio (update + delete) / live_row → 변동성 비율

 

 

 

 

🙌 댓글, 공감, 공유는 큰 힘이 됩니다! 😄

 

 

🔒 PostgreSQL Lock 조회 및 Session  Kill 처리 방법


 

OS환경 : Linux Rocky 8.10 (64bit)
DB 환경 : PostgreSQL 17.4

 

 

PostgreSQL을 운영하다 보면 종종 테이블, 행, 인덱스 등에 걸려 있는 잠금(Lock) 때문에 트랜잭션 지연이나 데드락이 발생하는 경우가 있습니다.  Lock 조회하고, 필요 시 Session을 종료하는 방법까지 안내합니다.

1️⃣ 현재 Lock 조회(대상 DB 접속 후 조회)

# 해당 DB접속 후 조회
SELECT 
    a.pid,
    a.usename,
    a.datname,
    a.state,
    a.query,
    a.query_start,
    l.locktype,
    l.mode,
    l.granted,
    l.relation::regclass AS locked_relation
FROM pg_locks l
JOIN pg_stat_activity a ON l.pid = a.pid
WHERE a.state != 'idle';
  • locktype: 어떤 종류의 락인지 (relation, tuple 등)
  • mode: ShareLock, ExclusiveLock 등 락 강도
  • granted: true면 락이 잡힌 상태, false면 대기 중

2️⃣ 현재 대기 중인 Lock (Blocking/Waiting) 확인

SELECT 
    blocked.pid AS blocked_pid,
    blocked.query AS blocked_query,
    blocked.query_start AS blocked_since,
    blocking.pid AS blocking_pid,
    blocking.query AS blocking_query,
    blocking.query_start AS blocking_since
FROM pg_locks bl
JOIN pg_stat_activity blocked ON blocked.pid = bl.pid
JOIN pg_locks kl ON bl.locktype = kl.locktype
    AND bl.database IS NOT DISTINCT FROM kl.database
    AND bl.relation IS NOT DISTINCT FROM kl.relation
    AND bl.page IS NOT DISTINCT FROM kl.page
    AND bl.tuple IS NOT DISTINCT FROM kl.tuple
    AND bl.virtualxid IS NOT DISTINCT FROM kl.virtualxid
    AND bl.transactionid IS NOT DISTINCT FROM kl.transactionid
    AND bl.classid IS NOT DISTINCT FROM kl.classid
    AND bl.objid IS NOT DISTINCT FROM kl.objid
    AND bl.objsubid IS NOT DISTINCT FROM kl.objsubid
    AND bl.pid != kl.pid
JOIN pg_stat_activity blocking ON blocking.pid = kl.pid
WHERE NOT bl.granted;

현재 어떤 세션이 다른 세션에 의해 Lock 을 기다리고 있는지를 보여줍니다.

3️⃣ 세션 강제 종료 (Session Kill)

락을 오래 잡고 있거나 시스템에 영향을 주는 세션을 종료할 수 있습니다.

# 특정 세션 강제 종료 (pg_terminate_backend())
SELECT pg_terminate_backend(3456);  -- 특정 PID 종료
📌 Deadlock 해결 시 사용 가능하지만, 강제 종료 주의!

# 트랜잭션 롤백 (pg_cancel_backend())
SELECT pg_cancel_backend(3456);
📌 현재 실행 중인 트랜잭션을 중단하지만 세션은 유지됨

주의: 종료 시 트랜잭션 롤백이 발생하며, 중요 작업이 중단될 수 있으므로 신중히 사용하시길...

✅ 참고: PostgreSQL Lock 종류 요약

Lock Mode 설명
AccessShareLock SELECT 등 읽기 전용 작업
RowExclusiveLock INSERT, UPDATE, DELETE 시 사용
ShareLock Foreign Key 참조 시
ExclusiveLock ALTER TABLE 등 구조 변경
AccessExclusiveLock VACUUM FULL, DROP TABLE 등 전체 차단

 

🧪 실습: PostgreSQL에서 직접 락 걸고 조회해보기

아래 예제는 두 개의 세션을 사용해 락이 걸리는 상황을 인위적으로 만들어보고, pg_lockspg_stat_activity를 통해 확인하는 실습입니다.

📌 준비: 테스트 테이블 생성

CREATE TABLE lock_test (
    id SERIAL PRIMARY KEY,
    data TEXT
);

INSERT INTO lock_test (data) VALUES ('A'), ('B'), ('C');

💻Session 1: 트랜잭션 열고 SELECT FOR UPDATE

BEGIN;

SELECT * FROM lock_test WHERE id = 1 FOR UPDATE;
-- 이 상태로 커밋하지 말고 대기

이 쿼리는 id = 1RowExclusiveLock을 걸어 다른 트랜잭션의 변경을 막습니다.

💻 Session 2: 같은 row에 UPDATE 시도

UPDATE lock_test SET data = 'Z' WHERE id = 1;
-- 🔄 무한 대기 상태가 됨 (락 대기)

세션 1이 커밋되지 않은 상태에서는 세션 2가 해당 row를 수정할 수 없습니다.

🔍 락 상태 확인(해당 DB 접속 필수)

# 해당 DB 접속 필수
\c mydb

SELECT 
    a.pid,
    a.usename,
    a.query,
    a.state,
    a.query_start,
    l.locktype,
    l.mode,
    l.granted
FROM pg_locks l
JOIN pg_stat_activity a ON l.pid = a.pid
WHERE a.datname = current_database()
  AND l.locktype = 'tuple';

   pid   | usename  |                     query                     | state  |          query_start          | locktype |     mode      | granted
---------+----------+-----------------------------------------------+--------+-------------------------------+----------+---------------+---------
 3197567 | postgres | UPDATE lock_test SET data = 'Z' WHERE id = 1; | active | 2025-05-14 02:26:11.125353+00 | tuple    | ExclusiveLock | t
(1 row)

granted = false 인 경우는 대기 중인 락을 의미하며, 실제 블로킹 상태를 확인할 수 있습니다.

💻 Session 1 Commit 후 Session 2 진행됨

-- Session 1
COMMIT;

세션 1이 COMMIT되면 세션 2가 대기 상태에서 깨어나 UPDATE를 실행하게 됩니다.

 

 

 


🙌 댓글, 공감, 공유는 큰 힘이 됩니다! 😄

 

실수로 백업을 포그라운드에서 실행해버린 프로세스 백그라운드로 전환하기
예) 실수로 nohub으로 수행하지 못한 백업 명령어(포그라운드)를 백그라운드로 전환  

OS환경 : Centos Linux 7.8 (64bit)

 

✅ 아래 다음과 같이 수행

 

  • 포그라운드 프로세스 중지
    → Ctrl + Z
  • job 리스트 확인(그럼 stopped 되어있는 job이 확인 됨) 
    → jobs
  • 백그라운드 재시작
    → bg
  • 쉘과 연결 해제(필수) -  열려있는 콘솔이 닫히면 백그라운드 도는것도 멈추기 때문에 필수로 수행 
    → disown %1
  • job 리스트 확인(목록이 없으면 정상) 
    → jobs

 

 

 

 

 

🙌 댓글, 공감, 공유는 큰 힘이 됩니다! 😄

 

Replication Slot 조회 및 삭제


OS환경 : CentOS 7.4 (64bit)
DB 환경 : PostgreSQL 11.10

 

 

PostgreSQL 복제 슬롯을 삭제하려면 pg_drop_replication_slot() 함수를 사용하면 됩니다. 

# Replication slots조회
SELECT * FROM pg_replication_slots;

 
 slot_name | plugin | slot_type | datoid | database | temporary | active | active_pid | xmin | catalog_xmin |  restart_lsn  | confirmed_flush_lsn
-----------+--------+-----------+--------+----------+-----------+--------+------------+------+--------------+---------------+---------------------
 slot_test |        | physical  |        |          | f         | f      |            |      |              | 29F0/93000000 |
(1 row)



# 해당 slot 삭제
SELECT pg_drop_replication_slot('slot_test');
 
 

❗ 주의:

  • 복제 슬롯을 삭제하기 전에 해당 슬롯을 사용하는 복제 연결이 없는지 확인해야 합니다.
    → active 컬럼이 t 이면 사용중이므로 삭제❌
  • 복제 슬롯을 삭제하면 복제본이 복제된 데이터의 최신 상태를 유지할 수 없으므로 주의해야 합니다.
 

 

 

 

 

🙌 댓글, 공감, 공유는 큰 힘이 됩니다! 😄

 

 

+ Recent posts