Redis 데몬의 쿼리 증가에 따른 응답 지연에 대한 원인 분석
문제 발생 서버 정보
Date
2013/11/29
Server
Physical server
OS 정보
CentOS 6.4 | x86_86 | 2.6.32-358.23.2.el6.x86_64
CPU 정보
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Byte Order: Little Endian
CPU(s): 8
On-line CPU(s) list: 0-7
Thread(s) per core: 2
Core(s) per socket: 4
Socket(s): 1
NUMA node(s): 1
Vendor ID: GenuineIntel
CPU family: 6
Model: 44
Stepping: 2
CPU MHz: 2399.951
BogoMIPS: 4799.90
Virtualization: VT-x
L1d cache: 32K
L1i cache: 32K
L2 cache: 256K
L3 cache: 12288K
NUMA node0 CPU(s): 0-7
Memory 정보
49381524KB(47G)
문제 분석 필요 사항
- Redis 데몬 설정
- Hardware 구성
- OS 커널 설정
- Network 구성
문제의 현상
redis 데몬으로 쿼리 증가시 redis 데몬에서 쿼리에 대한 응답 지연 발생.
문제의 원인
해당 현상 발생시 물리적 자원 사용량은 한계점에 이르지 않았다고 판단됨.
[1]
번의 배제로 OS, SW 상의 구성을 확인.Redis 에 질의되는 쿼리 값들을 확인 결과 특정쿼리(keys *)실행시에 다른 쿼리(get)들이 지연되는 현상 확인.
[3]
번의 문제(redis 자체 설계 문제)는 현재 해당 문제 발생 시간과 관련 없음을 확인.Redis 데몬의 source 확인시 listen() 함수의 backlog 는 고정값 511 이지만 문제 발생시 처리에는 충분하다고 판단됨.
$ vi redis/src/anet.c
if (listen(s, 511) == -1) {
실제 SW 상의 backlog 가 적용 되었는지 커널 설정 확인 결과 한가지 설정(net.core.somaxconn)이 누락 된 것을 확인.(man 2 listen)
[6]
번의 문제로 인하여 기본값(128)으로 backlog 설정이 적용되는 것을 커널 소스를 통해 확인.
$ vi kernel/net/socket.c
1470 SYSCALL_DEFINE2(listen, int, fd, int, backlog) 1471 { 1472 struct socket *sock; 1473 int err, fput_needed; 1474 int somaxconn; 1475 1476 sock = sockfd_lookup_light(fd, &err, &fput_needed); 1477 if (sock) { 1478 somaxconn = sock_net(sock->sk)->core.sysctl_somaxconn; 1479 if ((unsigned)backlog > somaxconn) 1480 backlog = somaxconn; 1481 1482 err = security_socket_listen(sock, backlog); 1483 if (!err) 1484 err = sock->ops->listen(sock, backlog); 1485 1486 fput_light(sock->file, fput_needed); 1487 } 1488 return err; 1489 }
[7]
번으로 kernel의 backlog 수가 너무 낮다는 결론 유추
문제의 재현
재현 코드 작성
$ vi redis_connect_thread.c
OS kernel backlog 감소후 테스트
$ redis_connect {redis_server} {requests} {thread}
문제의 해결
Redis backlog 관련부분 source 수정후 재배포
$ diff -urNp redis.org/src/anet.c redis/src/anet.c
- if (listen(s, 511) == -1) { /* the magic 511 constant is from nginx */ + if (listen(s, 30000) == -1) { /* the magic 511 constant is from nginx */
OS kernel 설정 수정후 재배포
$ diff -urNp /etc/sysctl.conf.org /etc/sysctl.conf
+ net.core.somaxconn = 30000
모니터링 프로그램 코드 등록(slowlog get 등등 이용한 코드 작성)
$ vi redis-slowlog-to-syslog.pl
[1-3]
적용후 문제 해결 확인
기타
Linux kernel 버전 2.6.14 이후로 socket 함수에 NETLINK_INET_DIAG 옵션으로 소켓 모니터링이 가능하다. 그래서 listen 된 port 의 backlog 가 실시간 확인 가능하다. ss 명령어에 해당 기능이 구현 되어 있다.
$ vi iproute2-2.6.31/misc/ss.c
static int tcp_show_netlink(struct filter *f, FILE *dump_fp, int socktype)
.
.
if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_INET_DIAG)) < 0)
.
.
Redis 다중 포트 사용시 MemoryCache Dump file 의 복구 문제
내용
재시작시 마지막 높은 포트의 메모리 DB로 복구되는 현상
원인
Redis의 메모리 Dump는 dbfilename 설정으로 dir 설정 위치에 저장되는데 dbfilename 이 겹치면 포트를 여러개로 올려도 마지막 높은포트 번호의 파일로 복구 되기 때문이다.
해결
해결법은 다수의 포트로 구동시 dbfilename 이름을 아래처럼 개별 포트 이름으로 구동 하면된다.
$ vi /etc/redis/reids-6379.conf
dbfilename dump-6379.rdb
$ vi /etc/redis/reids-6380.conf
dbfilename dump-6380.rdb
$ redis-cli
redis 127.0.0.1:6379> SET key "values"
OK
redis 127.0.0.1:6379> get key
"values"
redis 127.0.0.1:6379>
$ service redis restart
Stopping redis-server with /etc/redis/redis-6379.conf: [ OK ]
Stopping redis-server with /etc/redis/redis-6380.conf: [ OK ]
Starting redis-server with /etc/redis/redis-6379.conf: [ OK ]
Starting redis-server with /etc/redis/redis-6380.conf: [ OK ]
$ redis-cli
redis 127.0.0.1:6379> get key
"values"
redis 127.0.0.1:6379>
$ (echo -en "PING\r\nPING\r\nPING\r\n"; sleep 1) | nc localhost 6379
+PONG
+PONG
+PONG
Post a Comment