- 코드를 버전관리함 으로써 배포 후 Major 버그 발생시 빠르게 Rollback을 하거나 수정된 코드만 파악하여, 버그를 빠르게 찾거나 한 프로젝트의 코드를 여러 사람이 함께 작업할 수 있도록 도와주는 이점이 있음
- git의 저장소는 3가지 단계로 나누어 짐
커밋한 소스가 보관되는 저장소
현재 프로젝트 파일들이 있는 작업트리
저장소와 작업트리사이의 버퍼영역으로 커밋될 대상이 저장되는 스테이징 영역
- git은 빈 디렉토리는 추적하지 않음
- 형상관리를 하지 않을 파일은 .gitignore 파일에 추가
- HEAD는 현재 브랜치의 가장 최신커밋을 의미
- 기본 원격 저장소를 origin이라고 부름
형상관리란?
- 소프트웨어에서 형상 관리는 개발 중 발생하는 산출물들이 변경됨으로써 점차 변해가는 소프트웨어 형상을 체계적으로 관리하고 유지하는 기법
- 소프트웨어 개발 생명주기 전반에 걸쳐 생성되는 모든 산출물의 종합 및 변경 광정을 체계적으로 관리하고 유지하는 일련의 개발 관리 활동으로, 소프트웨어에 가시성과 추적 가능성을 부여하여 제품의 품질과 안정성을 높임
- 기본 용어
Repository : 저장소
Checkout : Repository에서 로컬로 프로젝트를 복사함
Update : 로컬에서 작업중인 코드를 Repository에 등록
Trunk : Root 프로젝트
Branch : Root 프로젝트로부터 파생된 프로젝트 (Branch를 생성하여 버전 관리가 가능 - 특정 커스터마이징, 미확인된 새로운 기능 구현중일때 등)
Merge : Branch에서 진행하던 작업을 Root 프로젝트와 합침
Git 명령어 리스트
환경 설정
# git config --global --list
현재 설정정보 조회할 수 있습니다. --global옵션은 전역설정에 대한 옵션이며 현재 프로젝트에만 적용할때는 주지 않습니다.
# git config --global user.name "사용자명"
사용자명을 등록합니다 (필수)
# git config --global user.email "이메일주소"
이메일 주소를 등록합니다. (필수)
# git config --global color.ui “auto”
터미널에 표시되는 메시지에 칼라를 표시해줌
기본적인 명령어
# git --version
현재 git의 버전을 확인합니다.
# git init
현재 디렉토리에 git 저장소를 생성합니다.
# git add 파일명
git add는 2가지를 하는데 untracked files의 파일들을 git가 추적하도록 하거나 파일은 수정했지만 아직 스테이징 영역에 올라가지 않은(Changed but not updated) 파일들을 스테이징 영역에 올립니다. -i 옵션을 주면 대화형모드가 시작되며 파일의 일부분만 선택해서 스테이징하는 것이 가능합니다. -p 옵션을 사용하면 -i 대화형모드없이 바로 패치모드를 사용할 수 있습니다.
# git commit -m "커밋메시지"
스테이징 영역에 올라가 있는 파일들을 커밋합니다. -m 은 커밋메시지를 주는 옵션으로 여러 줄의 커밋메시지를 쓸 경우 -m 을 여러개 사용할 수 있습니다. -a 옵션을 사용하면 스테이징에 올리는 작업과 커밋을 동시에 할 수 있습니다.(추적되지 않는 파일은 추가하지 않습니다.) -m을 사용하지 않을때 -v옵션을 사용하면 편집기에 커밋하려는 변경사항의 다른점을 보여줍니다. 특정파일만 커밋하려면 마지막에 파일명을 추가해주면 됩니다.
# git commit -C HEAD -a --amend
지정한 커밋의 로그메시지를 다시 사용하여 기존커밋을 수정합니다. -c를 사용하면 기존메시지를 수정할 수 있는 편집기를 실행해 줍니다.
# git status
커밋되지 않은 변경사항을 조회합니다.
# git diff
스테이징영역과 현재 작업트리의 차이점을 보여줍니다. --cached 옵션을 추가하면 스테이징영역과 저장소의 차이점을 볼 수 있다. git diff HEAD를 입력하면 저장소, 스테이징영역, 작업트리의 차이점을 모두 볼 수 있다. 파라미터로 log와 동일하게 범위를 지정할 수 있으며 --stat를 추가하면 변경사항에 대한 통계를 볼 수 있습니다.
# git mv 파일명 새파일명
기존에 존재하는 파일을 새파일로 이동합니다. 변경이력은 그대로 유지합니다.
# git checkout -- 파일명
아직 스테이징이나 커밋을 하지 않은 파일의 변경내용을 취소하고 이전 커밋상태로 돌립니다. svn에서 revert와 동일합니다.
Branch와 Tag
# git branch
현재 존재하는 브랜치를 조회합니다. -r 옵션을 사용하면 원격저장소의 브랜치를 확인할 수 있습니다.
# git branch 브랜치명B 브랜치명A
브랜치명A에서 새로운 브랜치 브랜치명B를 만듭니다. (git에서 기본 브랜치는 master라는 이름을 사용합니다.)
# git branch 브랜치명
브랜치명의 새로운 브랜치를 만듭니다.(체크아웃은 하지 않습니다.)
# git branch -d 브랜치명
브랜치를 삭제합니다.
# git branch -m 존재하는브랜치명 새로운브랜치명
존재하는 브랜치를 새로운브랜치로 변경합니다. 이미 존재하는 브랜치명이 있을 경우에는 에러가 나는데 -M 옵션을 사용하면 이미 있는 브랜치의 경우에도 덮어씁니다.
# git tag 태그명 브랜치명
브랜치명의 현재시점에 태그명으로 된 태그를 붙힙니다. git tag만 입력하면 현재 존재하는 태그 목록을 볼 수 있습니다.
# git checkout 브랜치명/태그명
해당 브랜치나 태그로 작업트리를 변경합니다.
# git checkout -b 브랜치명B 브랜치명A
브랜치명A에서 브랜치명B라는 새로운 브랜치를 만들면서 체크아웃을 합니다.
# git rebase 브랜치명
브랜치명의 변경사항을 현재 브랜치에 적용합니다.
# git merge 브랜치명
브랜치명의 브랜치를 현재 브랜치로 합칩니다. --squash 옵션을 주면 브랜치명의 모든 커밋을 하나의 커밋으로 만듭니다.
# git cherry-pick 커밋명
커밋명의 특정 커밋만을 선택해서 현재 브랜치에 커밋으로 만듭니다. -n 옵션을 주면 작업트리에 합치지만 커밋은 하지 않기 때문에 여러개의 커밋을 합쳐서 커밋할 수 있습니다.
로그 관리
# git log
커밋로그들을 볼 수 있으면 -1나 -2같은 옵션을 주어 출력할 커밋로그의 갯수를 지정할 수 있습니다. --pretty=oneline 옵션을 주면 한줄로 간단히 보여주고 --pretty=format:"%h %s"처럼 형식을 정해줄 수 있습니다. -p 옵션을 사용하면 변경된 내용을 같이 보여줍니다. --since="5 hours" 이나 --before="5 hours"같은 옵션도 사용가능합니다. --graph 옵션을 주면 브랜치 트리를 볼 수 있습니다.
# git log 커밋명
해당 커밋명의 로그를 볼 수 있습니다. 커밋명A..커밋명B (마침표2개)와 같이 입력하면 커밋명A이후부터 커밋명B까지의 로그를 볼 수 있습니다. ^은 -1과 동일해서 HEAD^라고 하면 최신바로 이전 커밋이고 HEAD^^^와 같이 쓸 수 있으며 HEAD~3을 하면 HEAD의 3개 이전의 커밋을 뜻합니다.
# git blame 파일명
갈 줄 앞에 커밋명과 커밋한 사람등의 정보를 볼 수 있습니다.
# git blame -L 10,15 파일명
-L 옵션을 사용하면 10줄부터 15줄로 범위를 지정해서 볼수 있고 15대신 +5와 같이 사용할 수 있습니다. 숫자의 범위 대신 정규식도 사용이 가능합니다.
# git blame -M 파일명
-M 옵션을 사용하면 반복되는 패턴을 찾아서 복사하거나 이동된 내용을 찾아줍니다. -C -C 옵션을 사용하면 파일간의 복사한 경우를 찾아줍니다. -C -C는 git log에서도 사용가능하며 내용의 복사를 찾을때는 git log에서 -p옵션을 사용합니다.
# git revert 커밋명
기존의 커밋에서 변경한 내용을 취소해서 새로운 커밋을 만듭니다. -n옵션을 사용하면 바로 커밋하지 않기 때문에 revert를 여러번한 다음에 커밋할 수 있습니다.(항상 최신의 커밋부터 revert해야 합니다.)
# git reset 커밋명
이전 커밋을 수정하기 위해서 사용합니다. --soft 옵션을 사용하면 이전 커밋을 스테이징하고 커밋은 하지 않으며 --hard옵션은 저장소와 작업트리에서 커밋을 제거합니다. git reset HEAD^와 같이 입력하면 최근 1개의 커밋을 취소할 수 있습니다.
# git rebase -i 커밋범위
-i옵션으로 대화형모드로 커밋 순서를 변경하거나 합치는 등의 작업을 할 수 있습니다.
원격저장소
# git clone 저장소주소 폴더명
원격저장소를 복제하여 저장소를 생성합니다. 폴더명을 생략가능합니다.
# git fetch
원격저장소의 변경사항 가져와서 원격브랜치를 갱신합니다.
# git pull
git fetch에서 하는 원격저장소의 변경사항을 가져와서 지역브랙치에 합치는 작업을 한꺼번에 합니다. 파라미터로 풀링할 원격저장소와 반영할 지역브랜치를 줄 수 있습니다.
# git push
파라미터를 주지 않으면 origin 저장소에 푸싱하며 현재 지역브랜치와 같은 이름의 브랜치에 푸싱합니다. --dry-run 옵션을 사용하면 푸싱된 변경사항을 확인할 수 있습니다. 로컬에서 tag를 달았을 경우에 기본적으로 푸싱하지 않기 때문에 git push origin 태그명이나 모든 태그를 올리기 위해서 git push origin --tags를 사용해야 합니다.
# git remote add 이름 저장소주소
새로운 원격 저장소를 추가합니다.
# git remote
추가한 원격저장소의 목록을 확인할 수 있습니다.
# git remote show 이름
해당 원격저장소의 정보를 볼 수 있습니다.
# git remote rm 이름
원격저장소를 제거합니다.
서브모듈
# git submodule
연관된 하위모듈을 확인할 수 있습니다.
# git submodule add 저장소주소 서브모듈경로
새로운 하위모듈을 해당경로에 추가합니다. 추가만하고 초기화 하지는 않으며 커밋해쉬앞에 마이나스(-) 표시가 나타납니다.
- DB나 API 호출 또는 Rendering 등으로부터 받아오는 결과 데이터를 작은 Key-Value 형태로 메모리에 저장하는 방식
- Memcached는 필요량보다 많은 메모리를 가졌을때, 시스템으로부터 메모리를 사용하고 필요로 하는 메모리가 부족한 경우 이를 더 쉽게 가져다 사용할 수 있도록 함
메모리 운영 방식
- Memcached를 사용하지 않을 경우 분리되어 있는 메모리에 대해 각각의 서버에서 사용할 수 있는 것은 할당된 메모리의 크기만큼인데 Memcached를 적용할 경우 논리적으로 결합되어 있기 때문에 각 웹서버는 전체 메모리 캐시만큼의 용량을 사용할 수 있음 (효율성있게 메모리 운영이 가능해진다는 것)
Memcached를 사용하지 않을 경우
- 각 노드는 완벽하게 독립적
- 고전적으로 사용되던 방식으로 총 캐시 크기가 Web Farm (여러대를 사용해서 웹 사이트를 구축한 형태)의 실제 용량의 일부분으로만 사용이 가능하다는 점에서 낭비가 심함
- 각각의 서버에 할당된 캐시 크기만큼 사용할 수 있으므로 Web Farm의 캐시 사이즈는 128MB이지만 각 서버에서 사용할 수 있는 사이즈는 64MB
(그림 상 Web Farm의 용량은 64MB * 2 = 128MB 이지만 실제 캐시의 크기는 64MB)
Memcached를 사용할 경우
- Memcached로 묶인 모든 서버는 동일한 가상 메모리 풀을 공유 (특정한 항목이 주어졌을 때 전체 웹 클러스터에서 항상 동일한 위치에 저장되고 검색되어짐을 의미)
- 분산 메모리 캐시를 적용하게 되는 것이므로 캐싱을 통해 DB나 API 호출에 대한 횟수를 줄이고 이로 인해 응용프로그램의 수요나 DB 데이터 접근에 대한 부하를 줄여 성능 향상
웹 어플리케이션 적용 법
- TCP 스펙상 접속을 끊은 후 TIME_WAIT가 발생할 수 있음 (TIME_WAIT의 갯수는 netstat 명령을 통해 확인 가능 - # netstat -na | grep -i time_wait | wc -l)
- TIME_WAIT가 발생하는 시간은 30-240초로 설정할 수 있는데 대부분의 운영체제에서는 240초가 기본 값
- 기본 값을 사용시 Memcached를 운영하는 환경에서는 너무 길고, 트래픽이 많은 곳에서 Memcached와 빈번하게 통신을 하다보면 수만개의 TIME_WAIT가 발생하는 경우가 생김
(Memcached에 접속이 안되는 현상이 발생하는 경우가 생김)
- Memcached를 실행한 서버는 TIME_WAIT 발생 시간을 30초로 설정 (일반적인 상황에서는 최소 60초 이상으로 설정할 것을 권장
- 데이터를 구간별로 쪼개어 나눔으로써 노드에 무겁게 가지고 있던 데이터를 빠르게 검증할 수 있어 빠른 트랜잭션 속드를 가질 수 있게 됨
- 샤드란 샤딩을 통해 나누어진 블록들의 구간을 샤드라 함 (각각의 샤드는 데이터의 복사본이 아니라 데이터 그 자체)
- Elasticsearch는 분산 데이터베이스(분산 검색엔진)이기때문에 이렇게 데이터를 나누어 저장하는 방식으로 대용량 데이터에 대한 분산처리를 가능하게 함
샤딩의 종류
네트워크 샤딩
- 임의로 네트워크가 무작위로 노드를 샘플링하여 블록 단위로 샤드를 형성
- 하지만 네트워크가 샤드의 구성원에 대한 동의를 구하지 않아 구성원들이 원하는 방향으로 가지 않는 경우, 구성원들의 불만을 해결하지 못하는 단점을 가지고 있음
트랜잭션 샤딩
- 트랙잭션 해시의 마지막 몇 비트를 기반으로 샤드를 결정하고 트랙잭션의 유효성을 확인
- 하지만 사용자가 악의적인 경우 동일한 두 입력이지만 출력이 다른 트랜잭션을 생성할 수 있음
- 또한 이중 지출을 방지하기 위해 유효기간이 진행되는 동안에 샤딩이 된 조각의 노드들은 서로간에 통신이 필요 (통신 비용 발생)
스테이트 샤딩
- Account-Based Model로 상태가 지정된 블록체인에서 이 특정 샤드는 상태의 일부만을 유지
- 하지만 교차분할 트랜잭션을 수행하지 못하도록 제한이 되어 있음
- 또한 시스템의 상태가 모든 샤드에 복제되어 있지 않기 때문에 네트워크는 더 이상 오프라인 샤드에 대한 트랙재션의 유효성을 검사하지 못함
- 오프라인 샤드를 유지하기 위해 백업 노드를 갖게된다면 중앙집중식이 되어 보안성에 위협
- 네트워크가 한 번씩 재편성될 때 한번에 네트워크를 전환하게 되면 일부 동기화가 완료될때 까지 전체 시스템을 사용할 수 없게 될 수도 있음
샤딩의 문제점
- 중앙화의 문제와 보안성의 문제를 가지게 됨
- 보안의 문제는 1% Attack의 문제가 생길 수 있음
- 100개의 샤드 시스템에서는 오직 1%의 Hash Rate로 샤드를 지배할 수 있음
- 샤드간의 커뮤니케이션이 너무 빈번하게 일어난다면 커뮤니케이션으로 인한 지연시간의 문제가 발생
샤드와 파티셔닝의 차이 (트랜잭션 샤딩)
- 파티셔닝이란 퍼포먼스(Performance), 가용성(Availability), 또는 정비용이성(Maintainability)를 목적으로 논리적인 데이터 엘리먼트들을 다수의 엔티티(Table)로 쪼개는 행위를 의미
샤딩
- 수평 파티셔닝과 동일
- 데이터 베이스를 샤딩하게되면 기존에 하나로 구성될 스키마를 다수의 복제본으로 구성하고 각각의 샤드에 어떤 데이터가 저장될지를 샤드키를 기준으로 분리
- 예를 들어 0~10번 고객의 정보는 하나의 샤드에 저장하고 11~20번 고객의 정보는 다른 샤드에 저장하고 하였을때 DBA는 데이터 엑세스 패턴과 저장 공간 이슈(로드의 적절한 분산, 데이터의 균등한 저장)를 고려하여 적절한 샤드키를 결정
파티셔닝
- 수직 파티셔닝과 동일
- 하나의 엔티티에 저장된 데이터들을 다수의 엔티티들로 분리하는 것을 의미
- 예를 들어 한 고객은 하나의 청구 주소를 가지고 있을 수 있는데 DBA는 데이터의 유연성을 위해 다른 데이터베이스로 정보를 이동하거나 보안의 이슈등을 이유로 Customerld를 참조하도록 하고 청구 주소 정보를 다른 테이블로 분리할 수 있음 (퍼포먼스나 공간적인 이유로 인해)
정리
- 파티셔닝은 퍼포먼스, 가용성, 정비용이성등의 목적을 위해 논리적인 엔티티들을 다른 물리적인 엔티티들로 나누는 것을 의미
- 수평 파티셔닝 또는 샤딩은 스키마 복제 후 샤드키를 기준으로 데이터키를 나누는 것을 의미
- 수직 파티셔닝은 스키마를 나누고 데이터가 따라 옮겨가는 것을 의미
Replica
- 또 다른 형태의 샤드
- Elasticsearch에서 Replica의 기본값은 1인데 이때 값이 1이라는 것은 Primary Shard가 1개라는 것을 의미하지 않고 Primary Shard와 동일한 복제복이 1개 있다는 것을 의미
- 오픈소스로서 데이터베이스(NoSQL DBMS - Key/Value 형식으로 동작)로 분류되기도 하고 Memcached와 같이 인메모리 솔루션으로 분류되기도 하는데 메모리 기반으로 구성됨 (여러대의 서버로 구성 가능)
- 성능은 Memcached에 버금가면서 다양한 데이터 구조체를 지원함으로써 Message Queue, Shared Memory, Remote Dictionary 용도로 사용될 수 있음 (대규모 메세지를 실시간으로 처리하기 위해 사용)
- 디스크가 아닌 메모리 기반 데이터 저장소 (In-Memory data Structure Store)로 데이터 베이스로도 사용될 수 있으며 Cache로도 사용될 수 있는 기술임
- 안전한 데이터의 보관과 백업을 위해 두 가지 방법을 제공 (메모리를 활용하면서 데이터 보존)
다른 서버의 메모리에 실시간으로 복사본 남김
디스크에 직접 저장하는 방법
- 레디스의 NoSQL 특징
데이터 저장소로 I/O가 가장 빠른 메모리 채택
단순한 구조의 데이터 모델인 Key-Value 방식을 통해 빠른 속도
캐시 및 데이터 스토어에 유리
다양한 API 지원
- 인메모리 캐시
캐시 방식을 통해 DB Read의 부하를 감소
서비스 요청이 증가하여 DB 요청이 많아지면 DB 서버 부하가 증가하는데 메모리 캐시가 적용되면 성능 및 처리 속도가 향상
- 레디스는 인메모리 캐시방식 중 Global Cache 방식을 사용
Global Cache 방식은 네트워크 트래픽이 발생하기 때문에 java heap 영역에서 조회되는 local cache의 성능이 더 낫지만 WAS 인스턴스가 증가할 경우엔 캐시에 저장되는 데이터 크기가 커질수록 레디스 방식이 더 유리
급격한 사용자가 집중되는 상황이나 대규모의 확장이 예정되어 있는 환경에 적합
Global Cache 방식이 적용되어 WAS 인스턴스 확장에는 유리하지만 Cache 및 Redis Session 등 관리 포인트가 늘어난다는 단점이 있음
- Key / Value 저장소
레디스는 기본적으로 Key-Value 저장소이며 특정 키 값에 값을 저장하는 구조로 되어 있고 기본적인 PUT/GET Operation을 지원
모든 데이터는 메모리에 저장되고 이로 인해 매우 빠른 Read/Write 속도를 보장
전체 저장 가능한 데이터 용량은 물리적인 메모리 크기를 넘을 수 있음 (OS 영역의 Swap을 사용하는 것인데 성능이 급격히 떨어지기 때문에 의미 없음)
데이터 액세스는 메모리에서 일어나지만 서버 재부팅 상황에서 메모리에 있는 데이터가 모두 지워지기 때문에 이런 상황에서 데이터 저장을 보호하기 위해 Disk를 Persistence Store로 사용
- Reids는 여러 프로세스에서 동시에 같은 Key에 대한 갱신을 요청할 경우 Atomic한 처리로 데이터 부정합 방지 Atomic 처리 함수를 제공함
- 리스트 배열형식의 데이터 처리에 특화되어 있으며 리스트형 데이터의 입력과 삭제가 mysql에 비하여 10배정도 빠름
- 여러대의 서버 구성이 가능한데 Consistent Hashing 혹은 Master-Slave 형식으로 구성 가능
사용 가능한 데이터형
- 단순하게 Key-Value 타입기반이라면 이미 Memcached가 존재한다. Redis는 Key-Value Store이기는 하지만 저장되는 Value가 단순한 Object가 아니라 자료 구조를 갖기 때문에 큰 차이를 보인다.
1. String (일반적인 Key-Vaule)
- 일반적인 문자열로 최대 512MByte 길이까지 지원
- Text 문자열 뿐만 아니라 Integer와 같은 숫자나 JPEG같은 Binary File까지도 저장할 수 있음
- 데이터형의 값은 정수인 경우 int로 아니면 raw로 encoding 됨
2. Lists (Array 형태로 Key 1개에 N개의 값을 가짐, 중복 값 가능)
- List는 String들의 집합으로 저장되는 데이터 형태는 Set과 유사하지만 일종의 양방향 Linked List라고 생각하면 됨
- List 앞과 뒤에서 PUSH/POP 연산을 이용해서 데이터를 넣거나 뺄 수 있고 지정된 Index 값을 이용하여 지정된 위치에 데이터를 넣거나 뺄 수 있음
- 배열이라고 생각해도 되며 한 Key에 넣을 수 있는 요소의 최대 개수는 4,294,967,295개
- 데이터형의 값은 설정파일에서 정해준 조건보다 큰 경우 Linkedlist 아니면 Ziplist 로 Encoding 됨
3. Sets (Group 형태로 Key 1개에 N개의 중복되지 않은 값을 가짐)
- Set은 String의 집합
- 여러개의 값을 하나의 Value 내에 넣을 수 있다고 생각하면 되며 블로그 포스트의 태깅(Tag)등에 사용될 수 있음
- Set 간의 연산을 지원하는데 집합인 만큼 교집합, 합집합, 차이(Differences)를 매우 빠른 시간내에 추출할 수 있음
- 정렬되지 않은 집합형으로 Key에 중복된 데이터는 존재하지 않음
- 추가, 제거 및 존재 체크 시 소모되는 시간이 Sets에 포함된 요소의 수에 관계없이 일정함
- 한 Key에 넣을 수 있는 요소의 최대 개수는 4,294,967,295개
- 데이터형의 값은 설정파일에서 정해준 조건보다 큰 경우 Hashtable 아니면 intset로 Encoding 됨
4. Sorted Set (Group 형태이나 각 Member에 score 값을 가짐, Key-Member-Score)
- Set에 “score”라는 필드가 추가된 데이터형으로 score는 일종의 가중치 정도로 생각하면 됨
- Sorted Set에서 데이터는 오름차순으로 내부 정렬되며 정렬이 되어 있는 만큼 score 값 범위에 따른 쿼리(Range Query), Top Rank에 따른 Query 등이 가능
- 가장 진보한 Redis 데이터형이라 불리며 랭킹 시스템 등에서 사용하기 좋음
- 요소의 추가, 제거, 업데이트는 매우 빠른 방법으로 진행되는데 이는 요소 갯수의 로그에 비례하는 시간이 사용
- Key에 중복된 데이터는 존재하지 않지만 score 값은 중복 가능
- 데이터형의 값은 설정파일에서 정해준 조건보다 큰 경우 skiplist 아니면 ziplist로 Encoding 됨
5. Hashs (Object 형태의 Key-Field-Value)
- Value 내에 Field/String Value 쌍으로 이루어진 테이블을 저장하는 데이터 구조체
- RDBMS에서 PK 1개와 String 필드 하나로 이루어진 테이블이라고 이해하면 됨
- List와 비슷한데 “필드명”, “필드값”의 연속으로 이루어져 있음
- 한 Key에 포함할 수 있는 Field-Value 쌍의 최대 개수는 4,294,967,295개
6. 데이터 구조체 정리
- Value가 일반적인 String뿐만 아니라 Set, List, Hash와 같은 집합형 데이터 구조를 지원
- 저장된 데이터에 대한 연산이나 추가 작업 가능 (합집합, 교집합, Range Query 등)
- Set은 일종의 집합, Sorted Set은 오름차순으로 정렬된 집합, hash는 키 기반의 테이블, List는 일종의 링크드 리스트와 같은 특성을 가짐
- 이러한 집합형 데이터 구조(Set, List, Hash) 등은 Redis에서 하나의 키당 총 2^32개의 데이터를 이론적으로 저장할 수 있으나 최적의 성능을 낼 수 있는 것은 일반적으로 1000-5000개 사이로 알려져 있음
- 데이터 구조에 따른 저장 구조의 정리
데이터 관리
1. Persistence
- Redis는 데이터를 디스크에 저장할 수 있는데 Memcached의 경우 메모리에만 데이터를 저장하기 때문에 서버가 종료된 후에는 데이터가 삭제되지만 Redis는 서버가 리부팅 되더라도 디스크에 저장해놓은 데이터를 다시 읽어서 메모리에 Loading하기 때문에 데이터가 유실되지 않음
- Redis에는 데이터를 저장하는 방법이 Snapshotting 방식과 AOF(Append on file) 두가지가 있음
1-1) Snapshotting (RDB) 방식
- 순간적으로 메모리에 있는 내용을 Disk에 전체를 옮겨 담는 방식
- 저장파일은 보통 .rdb 확장자 사용
- Save와 BGSave 두가지 방식이 있음
Save (동기적) : Blocking 방식으로 순간적으로 Redis의 모든 동작을 정지시키고 그때의 Snapshot을 디스크에 저장
BGSave (비동기적) : Non-Blocking 방식으로 별도의 Process를 띄운 후, 명령어 수행 당시의 메모리 Snapshot을 디스크에 저장하며 저장 순간에 Redis는 동작을 멈추지 않고 정상 동작
- 장단점
장점
메모리의 Snapshot을 그대로 뜬 것이기 때문에 서버 재부팅시 Snapshot만 Load하면 되므로 재부팅이 빠름
Redis-Server 디스크에 저장하는 시점까지 Disk I/O가 일어나지 않으므로 성능 극대화
단점
Snapshot을 추출하는데 시간이 오래걸리며 Snapshot 추출된 후 서버가 다운되면 Snapshot 추출 이후 데이터는 유실 (백업 시점의 데이터만 유지)
백업시 Fork()로 자식 프로세스를 생성해서 백업 작업을 수행하는데 이때 데이터가 크다면 순간적으로 CPU 부하가 발생
- BGSave 프로세스
Redis는 Fork로 자식 프로세스 생성
자식 프로세스는 임시 rdb 파일에 data를 씀
자식 프로세스가 임시 rdb 파일에 data 쓰기를 마치면, 임시 rdb 파일로 옛날 rdb파일을 덮어 씌움
- 명령어로는 save와 bgsave를 실행할 수 있음
1-2) AOF 방식
- Redis의 모든 Write/Update 연산 자체를 모두 Log 파일에 기록하는 형태 (Mysql의 바이너리 로그와 비슷)
- 서버가 재시작될때 기록된 Write/Update Operation을 순차적으로 재실행하여 데이터를 복구
- Operation이 발생할 때마다 매번 기록하기 때문에 RDB 방식과는 달리 특정 시점이 아니라 항상 현재 시점까지의 Log를 기록할 수 있으며 기본적으로 Non-Blocking Call
- 장단점
장점
Log file에 대해서 Append만 하기 때문에 Log Write 속도가 빠르며 어느 시점에 Server가 다운되더라도 데이터 유실이 발생하지 않음
AOF파일은 포맷이 단순하며 문제가 있는 쿼리만 삭제하고 복구에 사용하는 작업이 가능
단점
모든 Write/Update Operation에 대해서 Log를 남기기 때문에 Log 데이터 양이 RDB 방식에 비해서 거대하게 큼
복구시 저장된 Write/Update Operation을 다시 Replay하기 때문에 재부팅 속도가 느림 (fsync 정책)
- 명령어로는 bgrewriteaof를 실행할 수 있음 (쓰기 내용이 많아져서 불필요할 정도로 AOF 파일이 커진 경우 해당 명령의 실행에 의해 데이터 내용을 살릴 수 있는 짧은 명령을 쓰게 됨)
- AOF 손상 확인 방법 (AOF 파일을 쓰는 중 정전등의 문제로 파일이 손상될 수 있음, 이 경우 redis-check-aof 툴로 복구가 가능)
AOF 파일을 복사
redis-check-aof —fix <AOF 복사본 파일> 을 실행해 복사본 파일을 복구
diff -u 명령으로 두 파일을 비교
수정된 파일을 이용해 Redis-Server를 다시 시작
2. Expriation
- Redis는 데이터에 대해 생명주기를 정해서 일정 시간이 지나면 자동으로 삭제될 수 있게 하는데 Redis가 Expire된 데이터를 삭제하는 정책은 내부적으로 Active와 Passive 두 가지 방법을 사용
Active : Client가 Expired 된 데이터에 접근하려고 했을 때 그때 체크해서 지우는 방법
Passive : 주기적으로 Key들을 Random으로 100개만 스캔해서 지우는 방식
- Expired Time이 지난 후 Client에 의해서 접근되지 않은 데이터는 Active 방식으로 인해서 지워지지 않고 Passvie 방식으로 지워져야 하는데 Passive 방식의 경우 전체 데이터를 스캔하는 것이 아니기 때문에 Redis에는 항상 Expired 되었으나 지워지지 않은 쓰레기 데이터가 존재할 수도 있음
- 메모리가 Full 상태에서 Limits 설정에서 선택한 정책에 따라 Expired가 지정되지 않거나 남은 Key라도 삭제될 수 있음
Pub/Sub Model
- Redis는 JMS나 IBM MQ 같은 메세징에 활용할 수 있는데 1:1 형태의 Queue 뿐만 아니라 1:N 형태의 Publish/Subscribe 메시징도 지원 (Publish/Subscribe 구조에서 사용되는 Queue를 일반적으로 Topic이라 함)
- 하나의 Client가 메시지를 Publish하면 이 Topic에 연결되어 있는 다수의 Client가 메세지를 받을 수 있는 구조
- 일반적인 Pub/Sub (게시/구독) 시스템의 경우 Subscribe하는 하나의 Topic에서만 Subscribe 하는데 반해서 Redis에서는 pattern matchng을 통해서 다수 Topic에 메시지를 subscribe할 수 있음
(Ex. Topic 이름이 music.pop, music.classic 라는 두개의 Topic이 있을때 PSUBSCRIBE.music.* 라고 하면 두개의 Topic에서 동시에 메시지를 subscribe할 수 있음)
Replication Topology
Master/Slave Replication
- Redis의 Master Node에 Write된 내용을 복제를 통해 Slave Node에 복제하는 것을 정의
- 1개의 Master Node는 N개의 Slave Node를 가질 수 있으며 각 Slave Node도 그에 대한 Slave Node를 가질 수 있음
- Master/Slave 간의 복제는 Non-Blocking 상태로 이루어짐 (즉 Master Node에서 Write나 Query 연산을 하고 있을 때도 Background로 Slave Node에 데이터를 복사 중)
- 이 방식은 Node간의 데이터 불일치성을 유발할 수 있는데 Master Node에 Write한 데이터가 Slave Node에 복제중이라면 Slave Node에서 데이터를 조회할 경우 이전의 데이터가 조회될 수 있음
Query Off Loading을 통한 성능 향상
- 데이터 저장 용량을 늘릴 수 없어도 동시접속자 수나 처리 속도를 늘릴 수 있도록 Query Off Loading이라는 기법을 사용
- Master Node는 Write only, Slave Node는 Read only로 사용하는 기법 (Redis 뿐만아니라 Orcle, Mysql과 같은 RDBMS에서도 많이 사용하는 아키텍쳐 패턴)
- 대부분의 DB 트랜잭션은 웹 시스템의 경우 Write가 10-20%, Read가 70-90%선이기 때문에 Read 트랜잭션을 분산 시킨다면 처리시간과 속도를 비약적으로 증가시킬 수 있음
- Redis의 경우 Value에 대한 여러가지 연산 등을 수행하기 때문에 단순 Put/Get만 하는 NoSQL이나 Memcached에 비해서 Read에 사용되는 Resource의 양이 상대적으로 높기때문에 Redis의 성능을 높이기위해서 효과적인 방법
Redis 설정 옵션
Memory
- maxclients 128
Redis 서버에서 클라이언트의 접속을 동시에 몇개까지 받아들일지 설정하는 부분
0으로 설정할 경우 무제한으로 접속을 받아들임
설정된 수를 초과하여 클라이언트 접속이 시도되는 경우 에러를 반환
- maxmemory 1gb
서버에서 사용할 물리적 메모리 양을 결정
이 메모리양에는 실제 데이터는 물론 각종 설정 상태를 기억하는 부분까지 포함
그냥 숫자만 쓰면 바이트단위로 표기
- maxmemory-policy volatile-lru
volatile-lru : 기본값으로 만기 시각이 설정된 Key들 중에서 LRU 알고리즘에 의해 Key를 골라 삭제