1. 미들웨어이야기/06. redis

redis 대량 데이터 입력

ioseph 2018. 10. 17. 15:10


redis 대량 데이터 입력


이 글은

https://gist.github.com/Squab/52d42652719cc28451d7

코드의 사용법에 대한 이야기입니다.


1. redis-cli --pipe 이야기


redis에서 자료를 입력하는 방법은 여러가지가 있습니다.


가장 간단하게,

일반 텍스트 파일에 redis-cli 에서 사용하는 명령 구문 형태로 자료 입력 명령을 쭉 입력하고, OS 파이프 기능을 이용해서, 표준 출력 내용을 redis-cli 쪽 표준 입력으로 보내서 자료를 입력하는 방법입니다.



$ cat medi_code.txt
HSET medi_code 100 의료보험
HSET medi_code 110 직장
HSET medi_code 120 지역
HSET medi_code 130 "공무원 및 사립학교 교원"
HSET medi_code 200 의료보호
HSET medi_code 210 1종보호
HSET medi_code 211 거택보호자
HSET medi_code 212 시설보호자
HSET medi_code 213 국가유공자
HSET medi_code 214 월남귀순자
HSET medi_code 215 인간문화재
HSET medi_code 216 성병감염자
HSET medi_code 217 의사상자
HSET medi_code 218 이재자
HSET medi_code 220 2종보호
HSET medi_code 221 자활보호자
HSET medi_code 230 의료부조
HSET medi_code 231 기타보호자
$ time redis-cli  < medi_code.txt
(integer) 1
(integer) 1
(integer) 1
(integer) 1
(integer) 1
(integer) 1
(integer) 1
(integer) 1
(integer) 1
(integer) 1
(integer) 1
(integer) 1
(integer) 1
(integer) 1
(integer) 1
(integer) 1
(integer) 1
(integer) 1

real    0m0.005s
user    0m0.000s
sys    0m0.004s

5ms 걸렸네요.


여기서 하나 기억해야 할 것은 redis-cli 명령에서 하나의 속성 값 안에 공백 문자가 있다면,

"공무원 및 사립학교 교원" 처럼 큰 따옴표로 둘러싸 이것이 하나의 속성 값으로 처리하도록 해야 한다는 점입니다.


문제는 이렇게 입력해야 할 자료가 100만 건 경우, 이 방법은 그 다지 좋은 방법이 아닙니다.


공동데이터포털 상가 정보 자료 (https://www.data.go.kr/dataset/15012005/fileData.do)를 대상으로

상점 고유 번호와 상점명만을 추출 해서 100만 건 자료를 만들고 자료를 위와 같은 방법으로 넣어보면,


$ wc -l kostore01.txt
1000000 kostore01.txt
$ tail kostore01.txt
HSET kostore 25779768 "청산전통시장"
HSET kostore 25612795 "원주옻진액"
HSET kostore 25619783 "일영첨성대불한증막"
HSET kostore 25673160 "호곡리손칼국수"
HSET kostore 25681491 "대광기계"
HSET kostore 25757971 "해뜨는집"
HSET kostore 25757966 "부자세탁소"
HSET kostore 25723808 "새한태권도"
HSET kostore 25773734 "선화공주"
HSET kostore 25786315 "대동설렁탕"
$ time redis-cli < kostore01.txt

...

(integer) 1

(integer) 1

real    0m48.909s
user    0m10.349s
sys    0m20.190s
$ redis-cli HLEN kostore
(integer) 1000000

49초 걸렸습니다. 초당 약 2만 건 정도의 자료가 들어갑니다. 뭐 나쁜 속도는 아니지만, 이 정도 성능을 쓰려고 redis를 사용하는 것은 아닙니다. 왜냐 하면, PostgreSQL에서도 이런 자료라면, 2초면 입력할 수 있기 때문입니다. (OS 디스크 캐시에 해당 자료가 있다고 가정 했을 때)


redis-cli 명령은 --pipe 옵션으로 이 한계를 극복합니다.

기본 개념은 입력되는 자료는 이미 redis 클라이언트-서버간 프로토콜을 저수준 양식에 맞춰있고,

client를 그냥 서버로 보내고, 서버는 받으면 그냥 저장하는 식입니다.



2. redis 자료 입력 저수순 양식


이 내용은

https://redis.io/topics/mass-insert

페이지에서 자세히 다루고 있습니다.


이것 기반으로

https://gist.github.com/Squab/52d42652719cc28451d7

페이지에서 python 코드 하나가 만들어졌고,

이것을 사용하면 됩니다.


단, python 3.x 버전에는 멀티바이트 문자 처리가 기본 유니코드로 바뀌어, 손을 좀 봐야합니다.

OS 기본 내장된 2.x 버전에서 코드 수정 없이 바로 쓸 수 있습니다.


하지만, 위에 큰 따옴표로 둘러싸는 경우 처럼 한 속성에 공백 문자가 있는 경우는


맨 마지막 줄에 있는

print proto(line.rstrip().split(' ')),

부분을

print proto(line.rstrip().split('\t')),

로 바꿔서 각 명령 속성은 탭문자로 분리한다고 변경 해서 사용하는 것이 편합니다.



자료 준비를 다시 합니다. 이번에는 tab 구분으로.


$ wc -l kostore02.txt
1000000 kostore02.txt
$ tail kostore02.txt
HSET    kostore    25008500    에코맘에프에스
HSET    kostore    24902357    햇살홈케어
HSET    kostore    24882499    이리온샵
HSET    kostore    25036790    터울림
HSET    kostore    24987409    테라아로마
HSET    kostore    20768375    강일렌트카
HSET    kostore    22079059    지에스카넷
HSET    kostore    20507522    애플빈
HSET    kostore    24995995    코리아세븐청원오송생명점
HSET    kostore    25000634    에스에이치종합상사
$ wc -l kostore02.txt
1000000 kostore02.txt
$ time python redis-mass.py /tmp/kostore02.txt | tail
*4
$4
HSET
$7
kostore
$8
25000634
$27
에스에이치종합상사

real    0m4.471s
user    0m4.519s
sys    0m0.119s
$ time python redis-mass.py /tmp/kostore02.txt | redis-cli --pipe
All data transferred. Waiting for the last reply...
Last reply received from server.
errors: 0, replies: 1000000

real    0m5.054s
user    0m5.117s
sys    0m0.411s


탭 문자로 분리된 자료를 redis 저수준 명령 구문으로 변환하는데, 약 4.6초, 전체 처리가 5초, 즉, redis 작업은 0.5초에 끝납니다.  놀랄만한 속도입니다.



3. 마치며

실무 안에서 원본 자료는 다양하게 있을 수 있을 수 있습니다.
이 경우 적당히 redis-mass.py 파일을 수정해서 redis-cli --pipe 명령이 사용할 수 있는 형태로만 만들어 낸다면,  그 나머지 처리는 엄청난 속도로 진행됩니다.