확장성 전략 입문: 데이터베이스 샤딩

http://blog.maxindelicato.com/2008/12/scalability-strategies-primer-database-sharding.html

위의 링크의 문서를 간략하게 정리한 자료입니다.

확장성 전략 입문서 : 데이터베이스 샤딩

데이터 베이스 확장성

기본 용어 정리

  • 성능 – 한 시스템에서 트랜젝션 하나를 서비스할 수 있게 하는 스피드
  • 확장성 – 전체 시스템의 부하증가시에도 서비스의 품질을 유지시키는 시스템의 기능
  • 수직 확장 – 시스템을 수직으로 확장하는 것은 각각의 컴포넌트의 자원을 늘려서 확장성을 증가시키는 것
  • 수평 확장 – 수평으로 확장하는 것은 각각의 컴포넌트들을 늘려서 확장성을 증가시키는 것
  • 수직 데이터셋 파티셔닝 – 데이터 세트(테이블)을 테이블의 컬럼 단위로 쪼개는것
  • 수평 데이터셋 파티셔닝 – 데이터 세트(테이블)을 테이블의 행단위로 쪼개는 것
  • 시스템 – 소프트웨어와 하드웨어가 상호 연결된 컴포넌트들의 집합
  • 샤드 – 데이터베이스의 인스턴스 한개. 전체 데이터 세트의 부분집합. 각각의 샤드에 있는 데이터는 유니크하지만, 같은 스키마를 공유한다.

당신의 데이터를 파티셔닝하라

왜 우리는 데이터를 파티셔닝 해야하는가? 그리고 그것은 우리 어플리케이션의 확장성에 어떻게 도움이 되나?

가능한한 최고 사양의 머신을 구해서 수직적으로 확장을 할 수는 있겠지만, 결국에는 벽에 부딪힌 자신을 발견할 것이다. 하드웨어를 수직적으로 확장하는 것은 한계가 있다.

알고리즘적 색인(Algorithmic Lookups)

날짜 시간 파티셔닝

파티셔닝 날짜와 시간으로 데이터를 파티셔닝 하는 가장 단순한 알고리즘적 방법

Row Count 파티셔닝

날짜와 시간 파티셔닝의 또다른 대안은 Row Count파티셔닝이다. Row Count파티셔닝은 날짜 시간 파티셔닝과 기본적인 개념을 같이한다.

“우리의 시스템에는 하나의 DB서버가 있다. 그 데이터베이스는 지금 사용량 초과이고 가끔 실행되는 오랫동안 실행되는 쿼리로 인해 장애가 발생직전의 상태이다. 데이터셋의 거의 가득 차오른 용량이 주된 이슈이다. 좀 더 상세히 말하자면, 거의 2천 5백만개의 송장이 5년이란 기간동안 더해졌다.”

위의 주어진 시나리오대로라면, 우리는 아래와 같이 말할 수 있다.

  • 낮은 볼륨의 쓰기/읽기
  • 리소스 집중적인 읽기 – 오래 실행되는 쿼리는 CPU와 Disk 리소스를 집중적으로 사용한다.
  • 큰 용량의 데이터 – 큰 볼륨의 데이터를 다루고 있다.
  • 데이터의 균등한 분배 – 데이터 셋이 크지만 5년동안 거의 1년에 500만개가 증가했다. 어느정도 증가할지는 장담할 수 없다.

더 이상 예측 가능한 데이터셋을 다루어야 한다고 고민할 필요는 없다. 역사적인 관례로 보면 – 장담할 수 있는건 아니지만 – 데이터셋은 1년에 500만개정도가 계속해서 증가했다. 보통의 서버는 하나의 테이블에 500만개의 읽기 처리를 별다른 노력없이 할 수 있다. 그러므로 우리는 간단히 2천5백만개의 레코드를 분리된 각각의 5개의 데이터 샤드로 재배치 할 수 있다.

몇년이 지난후, 우리는 또다른 샤드를 우리 시스템에 추가 할 수도 있다. 우리는 균등한 데이터의 분배에 대한 유지 관리를 걱정하지 않아도 된다.

새로운 데이터를 어디에 넣을지 결정하는 것은 간단하다. 간단히 우리의 어플리케이션에 설정을 할수 있고 우리의 샤드는 현재 활성상태의 샤드가 무엇인지 찾아낸다. 액티브 샤드가 최대 레코드의 수용치에 이르렀을 때에, 어플리케이션에는 간단히 준비된 다음 샤드에 데이터를 넣도록 설정을 추가하거나 변경하면 된다.

이제 유연성면에서는 약간 어려워지지만, 작년의 데이터가 어디있는지 결정하기 위해 럭셔리 해질 필요는 없는데, 일년전의 데이터를 쿼리할 경우에 모든 샤드를 검색하면 된다. 이건 생각보다 나쁘진 않다. 우리 시스템은 이미 병렬화(parallelized)되었기 때문이다. 이제 하나의 서버에서 찾고자 하는 데이터가 어디 있는지 찾는 대신에 각각의 서버에 찾고자 하는 쿼리를 날리고 결과들을 합치면 된다.

마스터 인덱스 색인

마스터 인덱스 색인을 사용하는 것은 알고리즘적 색인을 사용하는 것과 거의 비슷하게 간단하지만, 특정 데이터 셋이 연속적으로 정렬되어 있지 않은 경우에 필요하다.

도메인 파티셔닝

좀 더 복잡한 파티셔닝 방법중 도메인 파티셔닝은 최고의 유연성을 준다.

파티셔닝의 규모를 결정하는 것은 해당 데이터 베이스의 스키마의 성격에 강하게 의존한다.

특정 사이즈로 파티셔닝이 쉽도록 잘 정리된 스키마는 아래의 성질들이 있다.

  • 스키마들의 테이블이 상호 관계가 없이 자연적으로 원칙적으로 격리되어 있다. 예를 들면, 대부분의 테이블은 유저테이블과 관계가 있다. 그리고 포함된 열들은 특히 단순한 한명의 유저의 데이터이다.
  • 스키마의 가장 중요한 테이블은 많은 조인을 필요로 하지 않아야 한다. 예를 들면, 유저테이블을 파티셔닝하고자 할 때, 여러유저에 대한 쿼리가 각각의 다른 샤드에 대한 조인이 필요 없어야 한다.
  • 위성테이블의 수, 포함된 데이터, 충분히 작은 사이즈의 1단 계층의 테이블, 그리고 계속 작은 사이즈를 유지하는것, 그리고 성능의 병목지점이 되지 않는것.

도메인 파티셔닝은 두개의 메인 서버타입으로 구성된다. 하나의 인덱스 샤드 그리고 하나이상의 도메인 샤드.

인덱스 샤드는 검색 메커니즘을 서비스한다. 최소로, 데이터셋의 파티셔닝된 규모와 그 도메인 샤드의 위치를 포함한다. 처음에 인덱스 샤드에 쿼리를 날려서 어느 도메인 서버에 데이터가 있는 지 얻어오고 도메인 샤드에 대한 다른 컨넥션이 저장된 데이터를 요청한다.

인덱스샤드에 과부하가 걸리는 거 아니냐고 궁금해 할 수 있을 것 같은데, 약간의 과부하가 걸리긴 하지만, 전체시스템에 영향을 자주, 많이 줄 정도는 아니다. 인덱스 샤드의 데이터는 검색하는 데이터에 비해 작은 용량이기 때문에 데이터 전체를 메모리에 올리기도 한다.

“우리의 시스템에는 하나의 DB서버가 있다. 그 데이터베이스는 지금 사용량 초과이고 가끔 실행되는 오랫동안 실행되는 쿼리로 인해 장애가 발생직전의 상태이다. 데이터셋의 거의 가득 차오른 용량이 주된 이슈이다. 좀 더 자세히 말하면, 거의 500만개의 비선형적인 자료를 지난 2년동안 쌓아왔다. 각가의 유저는 user테이블, user_profile테이블, user_blog테이블, user_blog_engty테이블로 되어있다. user_profile 테이블의 각각의 열은 user테이블과 관련되어 있다. 각각의 user_blog테이블의 열은 user테이블과 관련되어 있다. 각각의 user_blog_entry테이블의 열은 user_blog의 열과 관련이 있다.”

위의 시나리오를 보고 파티셔닝 규모를 정해보자. 직접적이든 간접적이든 user라는 하난의 엔트리에 모든 데이터가 관련이 있는것을 알고 있다. 그리고 시스템이 매우 커지는 주된 요인이 유저가 추가되는 것이라는 것을 알고 있다. 유저는 유저테이블에 저장되는 것을 알고 있기 때문에 우리는 확신을 가지고 유저 테이블을 여러개의 샤드로 파티셔닝함으로써 부하를 분산시킬 수 있다고 말 할 수 있다.

** 인덱스 샤드 스키마 정의하기 **

우리가 파티셔닝 해야되는 건 user라는 건 알았는데, 각각의 user를 검색을 위해, 유저에 대한 유니크한 식별자가 필요하다. 이건 간단하게 userId 키 컬럼을 조합함으로써 만들 수 있다.userId키를 가지고 있는 것은 중요하지만, 검색에 매우 유용하지많은 않다. 대부분의 유저들은 username으로 검색을 하기때문에 그들의 username으로 인증하는 것은 중요하다. 유저의 인증에는 username과 password둘다 필요하다.

인덱스 샤드를 위한 명백하게 가장 필요한 데이터들은 아래의 컬럼이 필요하다.

  • shardId – 샤드를 위한 식별자
  • connectionString – 연결된 샤들에 대한 컨넥션 스트링
  • status – 샤드의 상태를 나타내는데 사용
  • createdDate – 데이터가 해당 샤드에 추가된 시간
  • userId – 유저에 대한 유일한 식별자
  • username
  • password

** 핫스팟과 샤드의 재조정 다루기 **

불가피하게도 확장성 전략에는 데이터가 하나의 서버에 몰리는 것에 의해 발생하는 성능 저하를 방지하기 위해 재분배가 필요하다.

Chef의 테스트 환경을 만드는데 매우 적합한 툴 – Vagrant

Vagrant : 가상머신을 간단히 만들고, 부수고 할 수 있는 VirtualBox의 프론트 엔드툴.

Chef Solo로 만든 레시피를 실험해보기엔 최적이다.

공식 사이트

http://www.vagrantup.com/

문서

  • 당연한 말이지만, 문서에 읽어볼 만한게 많다. 기본적인건 아래의 글을 참고하고, 좀 더 추가적인 기능들은 문서를 참고하길!

http://docs.vagrantup.com/v2/

Vagrant 도입하기

http://downloads.vagrantup.com/ 에서 다운 받을 수 있는데, 나는
http://downloads.vagrantup.com/tags/v1.2.7 에서 Mac용 dmg파일을 받아서 설치했다. 설치는 매우 쉬우니 생략.

가상서버 올리기

서버 올리는거는 커맨드라인에서 vagrant명령어를 실행하는 걸로 됨. 처음에는 Vagrant Box라는 OS 이미지를 다운로드 해야함.

http://www.vagrantbox.es 에 Vagrant용 OS이미지가 종류별로 공개되어 있음.

vagrant box add {title} {url}

요거 실행하면, ~/.vagrant.d/boxes라는 디렉토리아래에 {title}이라는 디렉토리가 생기고,
그 아래에 virtualbox라는 폴더 아래에 버추얼 머신 관련 파일이 다 들어 있음.

을 실행하는 것으로 가능.

적당한 디렉토리를 만들고 거기에 들어간다음

$ vagrant init {title}

을 실행하면 해당 디렉토리 내에 Vagrantfile이라는 ruby로 된 설정파일이 만들어진다.

그리고 나서 기동

$ vagrant up

실제로 내가 테스트해본 커맨드는 아래와 같다.

$ vagrant box add ubuntu http://dl.dropbox.com/u/1537815/precise64.box
(실행후 이미지 다운받느라 시간 좀 걸림)
$ mkdir virtualEnv
$ cd virtualEnv
$ vagrant init ubuntu
$ vagrant up

ssh로 로그인 하려면(1)

$ vagrant ssh

와 같은 명령어를 실행해 주면 된다.

vagrant ssh말고 ssh 커맨드로 가상머신에 들어가고 싶을 때에는 Vagrantfile의 네트워크 설정을 조금 수정해야한다.

아래와 같은 코드가 주석 처리 되어 있는데, 주석을 풀어주면 된다.
config.vm.network :private_network, ip: "192.168.33.10"

그러면 ssh로도 들어갈 수는 있지만, 암호를 물어보는데, 이렇게 말고 Vagrant의 비밀키를 디폴트로 사용하게끔 설정 가능하다.

ssh로 로그인 하려면(2)

$ vagrant ssh-config --host [호스트 명]
이렇게 하면, 가상머신 서버에 관한 ssh설정이 나오는데,

$ vagrant ssh-config --host [호스트 명] >> ~/.ssh/config
이렇게 해두면

$ ssh [호스트 명]
으로 접속 가능하다.

※ ssh 커맨드는 knife-solo같은 툴에서 기본적으로 사용하니 ssh로 로그인 할 수 있게 해두는게 좋다.

정지 / 부수기

$ vagrant halt #정지
$ vagrant destory #부수기

일단 이렇게 해서 한번 설정을 해두면, 2번째 부터는 VagrantFile이 있는 디렉토리에 들어가서 vagrant up만 해주면 된다.

다른 가상 머신을 만들어 보려면

  1. 임의로 폴더를 만들고
  2. vagrant init를 실행하고
  3. Vagrantfile의 네트워크 설정을 변경해주고
  4. vagrant up
  5. vagrant ssh-config --host [별칭] >> ~/.ssh/config 로 ssh설정해주기
  6. vagrant sshssh [별칭]으로 게스트OS에 접속 가능.

$ mkdir sandbox
$ cd sandbox
$ vagrant init
$ vi Vagrantfile #네트워크 쪽 설정 수정하기.
$ vagrant up
$ vagrant ssh-config --host box >> ~/.ssh/config

레디스 Persistance

레디스에서 AOF랑 RDB를 동시에 사용하고 싶은데, 잘 안되서 공식 사이트를 열심히 보면서 정리하다가 보니 번역을 하고 있더군요. 허헛..;;

첨에는 혼자 정리하는거라 마구 적다가, 후반부에는 지쳐서 대충 한부분도 없지않은것 같습니다. 혼자 보는 것도 좋은데 누군가에겐 도움이 되지 싶어 올립니다.

의견이 있으시면 알려주시어요~^^

Redis Persistance

  • 모드가 2개 존재함
  • RDB / AOF
    1. RDB는 특정한 시점의 데이터베이스의 스냅샷.
    2. AOF는 모든 쓰기 명령에 대한 로그를 남김.
  • 영속성 옵션을 모두 꺼도됨. 근데 나 처럼 redis를 디비 대용으로 쓰는 사람들은 그렇게 안하것지.ㅋ
  • AOF랑 RDB를 섞어서 사용하는 것도 가능. 근데 주의해야될게, 레디스가 AOF로 재시작 되면 원본 데이터 셋을 다시 구축함. 왜냐하면 AOF는 거의 완벽한 백업을 보장해야 하니까.
  • RDB랑 AOF는 트레이드 오프가 있다.

RDB 좋은점.

  • 컴팩트사이즈의 파일 한개로 된 레디스 데이터. RDB파일은 백업에 완벽히 적합함. 24시간 마다 백업해서 매일 매일의 스냅샷을 30일 동안 저장하거나 할수 있고, 장애/재해시 복구하기 편함.
  • 재해복구에 베리굿. 파일 사이즈가 컴팩트하니깐 데이터 센터나 Amazon S3같은데 전송하기에 적합.
  • RDB는 레디스의 성능을 최대화함. (이유는 생략. ㅋ )
  • RDB는 데이터가 클때에 재시작시 AOF보다 빠르게 재시작 가능.

RDB 나쁜점.

  • 데이터 유실을 최소화 하는데에는 좋지않아.
  • RDB는 자식 프로세스를 사용해서 디스크에 백업하기 위해서 fork()를 사용해야됨. Fork()는 데이터가 크면 시간을 잡아먹음. 그래서 몇 밀리세컨드에서 일초가 넘게 클라이언트의 지연이 있을 수 있음. (데이터는 큰데 CPU가 그레이트하게 좋지는 않을 때), AOF도 fork()를 사용함. 근데 얼마나 자주 로그를 남길지 니가 조절가능 – 안정성에 대해서는 아무런 트레이드 오프없음. (그러니깐 지연이 안일어난다는 의미)

AOF 좋은점

  • 매우 많이 안정적이다. : 다양한 fsync정책을 사용가능. fsync 안하기. 매초마다 fsync하기.(디폴트) 모든 쿼리마다 fsync 하기. (별로 안다양한데..ㅋ) 디폴트만 사용해도 성능은 그레잇함. (fsync는 백그라운드 스레드로 실행됨. 메인쓰레드가 무거워지면, no fsync가 작동. ) 그렇지만, 일초동안 쌓인 양의 데이터 유실이 있을 수 있음.
  • AOF로그는 append only임, 그러니깐 피씨의 전원이 나가서 꺼지더라도 나중에 파일 탐색이나, 충돌 같은 문제가 안생김. 만약에 로그를 쓰다가 반만 써졌다고 해도(디스크가 꽉차거나 이런저런 이유들로) redis-check-aof 툴로 쉽게 고칠 수 있음.
  • 로그가 너무 많을 때에 자동적으로 백그라운드에서 AOF 다시 쓰기 가능. rewrite는 완전히 안전함.
  • AOF는 모든 명령이 로그로 남고, 알아보기 쉬운 포맷으로 되어 있음. 만약에 잘못해서 flushall로 데이터를 다 날렸으면. aof파일에서 그부분만 지우고 서버를 재시작하면 다시 살아남!! (@charsyam님께서 알려주신 바로는 이게 가능한 것은 다음 번 rewrite가 일어나기 전 까지임. 왜냐면 rewrite가 일어나면 AOF를 최적화 하기 때문.)

AOF 나쁜점.

  • AOF파일은 RDB보다 파일 용량이 크다.
  • AOF는 RDB보다 느려질 수 있다. 그렇지만 fsync를 꺼버리면 높은 부하에서도 RDB보다 빠르긴 함. 그렇긴해도 RDB는 엄청난 부하에도 맥시멈 latency를 보장해줌.
  • 과거에 특정 명령어에서 버그가 있었음. (BRPOPLPUSH 같은 블러킹 명령어였음) 자기네들이 테스트할때는 OK였다고함. 고칠려고 많은 노력을 햇음. 그리고 실제 세계에서는 본적없다고 함.

오케이, 그럼 나는 뭘 쓰면 돼?

PostgreSQL같은 데이터 안정성을 원한다면 말야. 둘 다 쓰는거임. ㅎㅎㅎ 너가 데이터에 신경을 곤두세우고는 있지만, 그냥 단순히 RDB만 쓰고 있으면, 재난이든 머든 단 몇분일지 몰라도 데이터가 날아가는 걸 볼 수 있을 꺼야. OTL 그리고 AOF만 쓰는 유저들도 많은데, 우리는 이것을 권장하지 않아. 왜냐면 데이터 베이스 백업으로는 RDB만한게 없으니깐.

노트 : 머 이런 이유들로 나중에 우리는 AOF랑 RDB랑 합칠꺼야(롱~~~~텀 플랜임.)

스냅샷찍기 (Snapshotting)

디폴트로 레디스는 데이터 셋의 스냅샷을 디스크로 남겨. dump.rdb라는 바이너리 파일로 말이지. 이건 설정 파일에서 설정 가능해. 데이터셋의 최소 N초동안 최소 M의 변화가 있을 때 저장하도록 말야. 물론 수동으로 SAVE 나 BGSAVE 명령어를 날려서 저장하는 것도 가능.

save 60 1000

이 전략은 스냅샷찍기라고 알려져 있어.

어떻게 작동하나?

레디스가 데이터셋을 디스크로 덤프해야할 필요가 있을 때, 무슨일이 일어나냐면:

  • 레디스가 fork함. 그럼 이제 부모랑 자식 프로세스가 있는거지.
  • 자식프로세스가 데이터 셋을 임시 RDB파일에다 쓰기 시작해
  • 자식프로세스가 새로운 RDB파일을 다쓰면 옛날꺼랑 교체!

이 방법은 copy-on-write semantics 에서 가져왔는데 redis가 득 좀 봤지.ㅋ

Append-only File

스냅샷만 찍는건 매우 베리 안정적이지 않아. Redis를 정지 시켜버리거나, 파워 라인이 끊어지거나, 니가 실수로 kill -9 를 사용하거나 해서 최신의 데이터가 그대로 날아가 버리고 말지. 이런 상황이 별거 아닌 어플리케이션이 있는 반면, 100% 안정적이어야 하는 경우도 있지. 근데 100% 안정적인 옵션은 레디스에 없어.

append-only file은 최대-안정화 전력을 위한 레디스의 대안이야. 1.1버전부터 있었지. 설정 파일에서 AOF를 켤 수 있어.

appendonly yes

이제부터, 데이터 셋을 바꾸는 모든 명령어를 AOF에 붙이게 될꺼야. 만약에 니가 재시작을 하게되면, Redis는 AOF를 다시 실행해 볼꺼고 상태를 재조정 하게 될꺼야.

로그 rewriting

아마도 예측이 되겠지만, 많은 명령이 수행 되면 될수록 AOF도 점점 커질꺼야. 너가 하나의 카운트를 100번 증가시키면, 너는 데이터 셋의 단지 하나의 키만 데이터 셋에 유지하는 것이지만, 너의 AOF에는 100개의 엔트리가 들어가게 되지. 99개의 엔트리는 필요 없는것이야. 현재의 상태로 다시 되돌릴때에는 말이지.

그래서 레디스는 재밌는 기능을 제공해주고 있는데, AOF를 클라이언트에 대한 서비스의 중지없이 백그라운드로 재구축할 수 있어. 너가 BGREWRITEAOF를 실행하면, 레디스는 현재의 메모리에 있는 데이터셋으로 재구축 할 수 있게끔하는 최단의 명령어열을 AOF에 쓰게 될거야. 만약에 니가 redis2.2버전에서 AOF를 사용하고 있다면 BGREWRITEAOF를 시시때때로 사용해야돼. 2.4부터는 트리거를 걸 수 있어서 자동으로 할 수 있어.

append only file은 얼마나 안정적임?

얼마나 자주 fsync를 할지 설정할 수 있어. 여기에는 3가지 옵션이 있지.

  • 매번 fsync하기 – 커맨드가 실행될 때마다 AOF에 추가. 겁나, 매우, 베리 베리 느림. 겁나 안전함.
  • 1초 마다 fsync 하기 – 충분히 빠르다. (2.4에서는 스냅샷 만큼 빠름), 그래도 재난일 일어나면 1초만큼의 데이터는 날라감.
  • fsync안함. – 그냥 데이터를 넣기만 함. 가장 빠르지만 덜 안전한 방법.

추천 하는 정책은(디폴트) 1초마다 fsysnc하는거야. 빠르기도하고 꽤 안전하지. 매번 fsync하는 건 실제사용하기엔 너무 느려. (2.0에서 개선되긴 했지만 말여.) – fsync보다 빠르거나 그걸 빠르게 하는 방법은 없더라고.

내 AOF가 망가졌는데 우짜면 되노?!

AOF파일에 쓰는중에 서버에서 문제가 생기면, 파일이 깨지고 그건 redis에서 읽을 수 가 없지. 그 때는 아래에 나와 있는대로 하면 고칠 수 있을 거야.

  • AOF파일의 백업본을 만든다.
  • redis-check-aof(레디스의 bin 폴더에 있음) 툴로 원본파일을 고친다.

    $ redis-check-aof --fix

  • 옵션으로 diff -u 를 사용해서 어디가 잘 못된건지 찾아본다.

  • 고쳐진 파일로 서버를 재시작한다.

어떻게 작동하나?

로그 덧붙여 쓰기(log rewriting)는 스냅샷찍기에서 사용한 copy-on-write 트릭을 동일하게 사용함.

  • 레디스가 포크함. 그럼 이제 부모와 자식 프로세스가 생긴다.
  • 자식 프로세스는 새로운 AOF의 임시파일을 만든다.
  • 부모는 새로들어오는 명령들을 메모리 버퍼에 계속 쌓는다.(근데 동시에 원본 AOF파일에 계속 쓴다. 그러니 rewriting이 실패해도 안심하시요.)
  • 자식 프로세스가 rewriting을 끝내면, 부모 프로세스에서 신호를 보내고, 메모리 버퍼에 있던 것들을 자녀 프로세스가 생성한 파일에 모두 더한다.
  • 오호! 이제 레디스가 자동적으로 이전 파일하고 새로운 파일의 이름을 바꿔 치기한다. 그리고 새로운 파일에 새로운 데이터를 덧쓰기 시작한다.

나는 지금 dump.rdb 스냅샷을 쓰고 있는데 AOF로 어떻게 바꿈?

2.0하고 2.2가 해야하는 절차가 다르다. 니가 생각한대로 2.2가 좀 더 간단하고 재시작이 필요읍따.

Redis >= 2.2

  • dump.rdb를 백업한다.
  • 백업한 파일을 안전한 곳으로 이동/전송 시킨다.
  • 2개의 커맨드를 실행 시킨다.
  • redis-cli config set appendonly yes
  • redis-cli config set save ""
  • 니 데이터베이스가 같은 수의 키를 유지하고 있는지 확인한다. (확인은 알아서…ㅎㅎ)
  • 새로 들어오는 데이터들이 append-only-file에 추가되는지 확인한다.

첫번째 CONFIG 명령어는 Append Only File을 사용가능하게 해줌. 그리고 AOF를 사용하기 위해 Redis는 dump를 초기화 시키는 것을 막을 것이다. 그리고 나서 파일을 열고 들어오는 쿼리들을 기록할 것이다.

두번째 CONFIG 명령어는 스냅샷을 찍는것을 끄는 명령이다. 이것은 옵션으로서, 원한다면 둘다 켜놓을 수 있다.

중요 redis.conf를 수정해야 된다는걸 꼭 기억해라. 안그러면 서버를 재시작 했을 때 원래의 설정으로 대돌아간다.

Redis 2.0은 생략합니다.

AOF와 RDB의 상호작용.(interaction)

Redis >= 2.4 에서는 RDB 스냅샷이 작동 중일때 또는 BGSSAVE가 작동 중일때 에는 AOF rewrite 트리거를 피하도록 했다. 2개의 무거운 백드라운드가 동시에 실행되는 것을 막기 위함임. 스냅샷을 남기는 도중에 유저가 BGREWRITEAOF커맨드를 실행했을 때 서버는 OK라는 상태코드-작업이 스케줄링 되었다는 뜻-로 응답할것이고, rewrite는 스냅샷 찍는게 완료된후 실행될 것이다. AOF랑 RDB둘다 유효로 되어 있는 경우, 레디스가 재시작되면 AOF파일이 재구축 된다.

데이터 백업하기

이 섹션을 시작하기 전에, 다음의 문장을 정확히 읽고 확인해보라.

너의 데이터 베이스를 확실히 백업해라

디스크가 깨지거나, 클라우드에 있는 인스턴스가 없어지거나, 기타등등..: 백업이 없다는게 의미하는건 데이터가 /dev/null 로 사라지게 될 큰 위험을 지고 있다는 것이야! 레디스는 데이터 백업에 베리 친절해. 데이터 베이스가 작동중에도 너는 RDB로 스냅샷을 뜰 수 있지:RDB는 한번 만들어지면 절대 수정되지 않아, 그리고 만드는 중에는 임의의 이름을 사용하다가 스냅샷이 끝나고 나서야 마침내 이름을 변경하지!

이것이 의미하는것은 이거야. RDB파일을 카피하는 것은 완전 안전하다는 것이지. 서버가 운용중일 때에도 말이지! 다음에 나오는 건 우리가 추천하는 것들이야:

  • 너의 서버에 하나의 디렉토리에 매시간동안 스냅샷을 만드는 Cron을 만들고 잡을 돌려라, 그리고 일별 스냅샷은 다른 디렉토리에 저장해.
  • 매시간 Cron 잡 스크립트를 실행시키고, find 커맨드를 사용해서 오래된 스냅샷을 지워버려. 예를 들자면 이런거야. 48시간 동안 시간별 스냅샷을 만들고, 그리고 일별 스냅샷을 한두달 정도 만드는거지. 스냅샷의 이름은 시간, 날짜 정보를 넣어서 시간대별로 알 수 있게 해둬.
  • 최소한 매일 한번정도는 RDB스냅샷을 외부의 너의 데이터 센터로 전송시켜 아니면 최소한 다른 물리적인 redis머신으로 이동시켜.

재해 복구

재해 복구는 레디스에서는 기본적으로 백업이랑 같은 스토리야. 여기서 플러스로 각각의 백업들을 많은 다른 외부 데이터 센터로 전송시키는 것이 필요하지. 이 방법을 사용하면 대재앙이 일어나서 레디스가 돌고 있는 메인 데이터 센터에 영향이 갈때에도 안전하다고! 스타트업에 있거나 돈이 별로 없는 수많은 레디스 유저들을 위해서 우리는 매우 흥미로운 재해 복구 테크닉을 알려줄거야. 그건 돈 별로 안들어..ㅋ

  • Amazon S3나 비스무리한 서비스는 재해 복구 시스템으로 제격이지. 간단히 매일/매시 마다 RDB스냅샷을 S3로 보내는거야.(암호화된 폼으로). gpg -c 를 쓰면 암호화 시킬 수 있어. 데이터 안정성을 올리기 위해서 멀티로 스토리지 서비스를 사용하는 것도 추천이야.

  • 너의 스냅샷을 SCP로 멀리있는 서버로 전송해. 이건 진짜 간단하고 안전한방식이야: 작은 VPS를 얻어서 – 좀 멀리 있는 놈으로 – 거기에 ssh를 설치하고, ssh 클라이언트 키를 설정하는거지 암호없이, 그리고 나서 authorized_keys파일에 추가해. 너는 이제 백업파일을 전송할수 있어. 최소한 2개의 VPS를 얻는게 베스트야!

시스템은 쉽게 고장난 다는것을 이해는건 참으로 중요해. 최소한 전송이 끝났는지는 파일 사이즈를 체크하던지 해서 절대적으로 확인해야해! 그리고 가능하다면 SHA1암호화 방식을 사용해 너의 VPS에 말이지. 너는 독립된 경고 시스템이 필요할 지도 모르겠어. 어떤 이유로 최신 백업이 제대로 동작 하지 않을 때를 위해서 말이지.

워드프레스 3.5.1로 업그레이드~

블로그를 워드프레스로 옮기고 나서, 티스토리를 사용할 때보다 더 글을 안쓰게 되어서 고민을 많이 했습니다. 파이썬의 펠리칸이라는 정적페이지 생성툴을 알아보기도 하고, 다시 티스토리로 돌아갈까. 텍스트 큐브를 써볼까라는 고민을 하기도 했는데요.

그 이유는 티스토리를 쓰는 것보다 생각만큼 워드프레스가 만족스럽지 못했기 때문입니다.

가장 큰건..아무래도 테마 때문이지 싶습니다.

마음에 드는 테마를 도통 발견하기가 힘들어서 말이죠.

제가 좋아하는 테마는 가로사이즈가 길어서 코드보기에 편하고 깔끔한 테마였는데, 그런 테마를 찾기가 정말 무척이나 힘들었습니다. 그냥 기본 테마가 젤 낫더군요..그래서 기본테마로 되돌렸습니다.

속도도 약간 느린것 같아 신경이 쓰였습니다. 저는 cafe24의 가상서버를 사용하고 있습니다만, 생각보다 워드프레스가 무겁더군요.

그리고, 티스토리에 너무 적응되어 있어서 새로운 워드프레스라는 녀석에게 적응하기도 사실 쉽지 않았습니다.

사실 처음에 구축할때부터 LAMP환경 처음부터 구축하느라 시간을 좀 보내다 보니, 이거 워드프레스도 새로 알아가야하는게 쉽지 않더군요. 거기다 이것 저것 거의다 커스터마이징 가능한 기능이며……..OTL

블로깅을 잘하기 위해 너무도 많은 기능과 좋은 옵션들이 있었지만, 정작 그것이 부담으로 다가 올줄이야. 생각도 못했네요.

아무튼 이리저리 하여 고민하다가 3.5.1이 나왔길래 업그레이드를 했더니 웬걸 빨라졌군요.

그리고 테마도 워드프레스 기존 테마로 돌리고, 스마트폰에서도 되도록 플러그인을 설정했어요.

아직 코드를 보여주는 부분이 핸드폰에서 무진장 크게 나오거나 레이아웃이 좀 깨지거나 하는 부분이 있지만, 이 부분은 차차 해결해야 될 것 같아요.

많은 기능들은 제껴 두더라도 꾸준히 글을 쓰다 보면 언젠가는 적응이 될려나요~~~ 쉽지 않군요~~^^

암튼 결론은 3.5.1로 업그레이드 했더니 좀 빨라졌다. 스마트폰에서도 글 읽을 때 잘보이게 설정했다. 기능을 잘 몰라서 그냥 아는만큼 쓸려고 한다.

정도 되겠네요..^^;

그동안 배운것을 여기에 어서 공유해야할텐데……

[python] private / public아이피 구분하는 스크립트

아이피가 퍼블릭인지 사설아이피인지
구분해야할 필요가 있어서, 쉘스크립트로 만들려고 찾아보다가
포기하고 쉘에서 스크립트언어를 불러오는 방법으로 변경했다.

요즘 루비를 공부중인지라 루비로 만들고 싶었지만,
회사의 서버에는 루비가 거의 설치가 안되어 있는지라

회사의 서버에 대부분 설치 되어 있는 파이썬으로 만들었다.

첨에는 어떻게 해야되는지 좀 막막했는데,
아래 링크의 소스를 보니 그렇게 어렵지 않았다.
파이썬의 소스도 아래링크의 php소스를 파이썬으로 변경한것이다.

Check private IP function PHP

그리고 스택오버플로우에 무지하게 간단한 방법이 있긴했는데,
뭔가 모듈을 설치해야되는것 같았다.
http://stackoverflow.com/questions/691045/how-do-you-determine-if-an-ip-address-is-private-in-python

그래서 그냥 php소스를 python으로 변경하는것으로 최종 결정했다.

아래는 포팅한 소스이다.
파이썬을 잘하는 편이 아닌지라 되도록 간단히 만들려고 노력했다.

원리는 ip를 long타입으로 변환해서 privateip구간에 있는지 체크하는 원리이다.
뭔가 더 좋은게 있을것 같긴한데…(아시는분은 코멘트 좀 부탁드려요.^^)

isPrivateIp.py

import sys
from struct import *
from socket import *

if len(sys.argv) != 2:
    print "input just one parameter."
    sys.exit()

input_ip = sys.argv[1]

private_addrs = ['10.0.0.0|10.255.255.255',
                 '172.16.0.0|172.31.255.255',
                 '192.168.0.0|192.168.255.255',
                 '169.254.0.0|169.254.255.255',
                 '127.0.0.0|127.255.255.255'
                 ]

def ip2long(ip_addr):
    ip_packed = inet_aton(ip_addr)
    ip = unpack("!L", ip_packed)[0]
    return ip

def isPrivateIP(ip_addr):
    long_ip = ip2long(ip_addr)
    if long_ip != -1:
        for private_addr in private_addrs:
            start, end = private_addr.split("|")

            if long_ip >= ip2long(start) and long_ip <= ip2long(end):
                return 'PRIVATE'

    return 'PUBLIC'

print(isPrivateIP(input_ip))

쉘에서 사용하는 경우

IP_TYPE="`python ${DEPLOY_HOME}/isPrivateIp.py $IPADDR`"
echo "IP type is $IP_TYPE"

if [ "$IP_TYPE" == "PRIVATE" ];then
	echo "PIVATE IP!"

fi

맥에서 쟝고개발환경 만들기 (Django, pip, virtualenv and homebrew)

이번에 맥북을 사면서 파이썬 개발환경을 구축했습니다.
구축하는 중에 정리한 내용을 공유합니다.

아래 링크에서 거의 대부분 참고 했습니다.
http://www.tlswebsolutions.com/mac-os-x-lion-setting-up-django-pip-virtualenv-and-homebrew/
따라하는 겸 저도 따로 정리했습니다.(대부분 비슷한데 약간 다릅니다.)
위 링크에는 xcode대신에 gcc를 설치하는데요, 저는 xcode가 설치된 상태였기에 gcc를 설치하지 않았습니다.
xcode를 설치하지 않으신 분들중에 제대로 안되시는 분들은 알려주시면 감사드리겠습니다~

업데이트가 필요해진 부분들도 새로 정리했으니 영어가 귀찮은신분들은 참고하시면 좋을것 같아요.
설치하게 될 라이브러리, 프레임웤은 아래와 같습니다.

  • Pyhon2.7
  • Django1.3
  • Git
  • Homebrew > 맥 OSX의 패키지 관리자
  • xcode Command Line Tools
  • Pip -> package install for python
  • PIL -> python imaging library
  • Virtualenv -> 파이썬의 버추얼 환경을 위한 프로그램

homebrew 설치하기

homebrew설치는 아래 사이트에서 확인가능하십니다.
http://mxcl.github.com/homebrew/

아래와 같이 쉡에 입력하시면 homebrew의 설치는 끝납니다.
매우 간단하죠? ^^

$ ruby -e “$(curl -fsSkL raw.github.com/mxcl/homebrew/go)”

설치중 아래와 같은 경고가 떠서
Warning: Install the “Command Line Tools for Xcode”: http://connect.apple.com

애플 디벨로퍼 사이트에 가서 Command Line Tools 를 다운로드 받았습니다.  (용량이 110메가!)

https://developer.apple.com/downloads/index.action

다운로드 하는 동안 brew가 잘 되는지 확인 해보죠.

아래와 같이 입력합니다.

$ brew

터미널에 사용법이 찍혀 나온다면 성공한것입니다.

git인스톨하기

이제 본젹적으로 brew를 이용해서 인스톨을 해보아요.
먼저 git을 설치해보겠습니다.

$ brew install git

인스톨하는데 아래와 같은 에러가 떳습니다.

Warning: You have not agreed to the Xcode license.

xcode를 한번도 실행하지 않아서 뜨는 에러인것 같아서
xcode를 실행하니 라이센스에 동의하라고 나옴니다.
이거구나 싶군요!
‘동의’를 누르니 개발자 툴 다운받을래? 라고 뜹니다.
받는다고 설정하고 다운로드를 완료했습니다.
xcode설정하는 중에 git도 설치가 완료 됐군요!

git도 테스트 해보겠습니다.

$ git help

해서 사용법이 주르륵~~ 나오면 잘 되는 것입니다.

이제 파이썬을 설치해 봅시다.
아래 커맨드는 파이썬에서 필요한 라이브러리들을 설치하는 커맨드입니다.

$ brew install readline sqlite gdbm

이제 파이썬을 설치해보아요.

$ brew install python –universal –framework

–universal과 –framework 옵션은 제가 대충만 찾아봐서 확실히 알지는 못하오니 궁금하시다면,

homebrew python formula로 구글에서 검색해보시길 바랍니다.

그 와중에 xcode Command Line Tools의 다운로드가 끝났네요.

xcode Command Line Tools를 설치해보죠~

xcode Command Line Tools를 설치

다운로드 받으신 파일(아래와 같은 파일이요.)을 더블클릭하시면 창이뜹니다.

그리고, 아래와 같은 화면에서 ‘계속’등등을 누르셔서 그저 다음으로 넘어가시기만 하면 됩니다.

너무 간단하네요. ^^;

이제 파이썬의 패키지 관리를 해야하니 pip를 설치해봐요.

$ easy_install pip

실행중에 에러가 났습니다. 권한이 없다고 나오는군요.
[Errno 13] Permission denied: ‘/Library/Python/2.7/site-packages/test-easy-install-42582.write-test’

관리자 권한으로 실행을 해야될 것 같네요.
관리자 권한을 활성화 시키는 법은 아래 링크를 참고하세요~

http://support.apple.com/kb/HT1528?viewlocale=ko_KR&locale=ko_KR 

관리자 권한을 활성화 시키셨으면 다시 pip를 설치해봅시다.

관리자 권한으로 실행가능하도록 sudo를 사용하겠습니다.

$ sudo easy_install pip

이제 pip로 파이썬의 패키지들을 인스톨 할 수 있습니다.
python가상환경을 만들어주는 virtualenv를 설치해봐요.

virtualenv설치

Virtualenv는 파이썬 개발에 필요한 환경을 맥 머신에 기본 설치되어 있는
파이썬 환경과는 별도의 환경으로 완전히 구별하고 싶을때 사용합니다. (영어로는 고립시킨다고 되어있네요.)

아래 명령을 실행시켜 봅시다.(역시 관리자 권한이 필요합니다. ㅎ)

$ sudo pip install virtualenv

자, 이제 장고를 실행시키기위한 환경을 구축해봐요.

프로젝트의 루트로 사용할 디렉토리를 하나 만드셔야 됩니다.

$ mkdir directory_name

$ cd directory_name

그리고 새로운 버추얼 환경을 만들어 봅시다.

$ virtualenv [버추얼환경 이름] –no-site-packages

아래 커맨드로 새로운 버추얼 환경을 실행할 수 있습니다.

$ source [버추얼환경 이름]/bin/activate

이렇게 하시면 터미널의 앞에 버추얼 환경의 이름이 나오게 됩니다.

저는 django라고 이름을 지었는데요, 이런식으로 나옵니다.

(django) user $ _

버추얼 환경에서 나오시려면 아래의 커맨드를 입력하세요.

$ deactivate

마지막으로 쟝고를 설치해보겠습니다~

$ pip install django

이제 쟝고개발환경이 다 준비되었습니다! 와우!

만약에 MySQL을 지원하고 싶으시다면 MySQL서버와 MySQL-python라이브러리를 설치해야해요.

아래의 명령어로 간단히 가능합니다. (brew를 실행해야하니 버추얼 환경에서 나와주세요.)

brew install mysql

#아래 두줄은 붙여서 써주세요~
sudo pip install http://downloads.sourceforge.net/project/mysql-python/mysql-python-test/1.2.3c1/MySQL-python-1.2.3c1.tar.gz?use_mirror=cdnetworks-us-2

PIL이라는 파이썬 이미지 라이브러리도 설치해봅시다.

pip install PIL

이제 필요한 것은 다 준비 되었습니다.

쟝고프로젝트를 개발하실 수 있습니다.

버추얼 환경으로 설치했기에 기존의 맥 환경에는 전혀 영향을 주지 않습니다~!

이제 쟝고 프로젝트를 시작하는 것만 남았군요!

버추얼 환경으로 들어가셔서 쟝고 프로젝트를 생성하는데 까지 해보겠습니다.

source django/bin/activate

쟝고 프로젝트를 생성하는 커맨드는 아래와 같습니다.

django-admin.py startproject project_name

project_name에는 여러분이 만드실 프로젝트명을 넣으세요~ ^^

아..그리고 한가지 빼먹게 있습니다만, mysql설정인데요.

mysql설정은 따로 해주셔야됩니다. 다른 좋은 분들의 링크만 소개하겠습니다.
(저는 공식사이트가 젤 낫긴 하더라구요.)

그럼 재미나는 프로그래밍 하시길 바랍니다. ^^

http://dev.mysql.com/doc/refman/5.6/en/binary-installation.html

http://calflove.tistory.com/334

http://bluexmas.tistory.com/216

덧, 버추얼 환경이라고 하니 용어가 조금 헷갈립니다만,
nodejs나 루비를 아시는 분들이라면 nodejs의 nvm 이나 ruby의 rvm을 생각하시면 좀 더 이해하기 쉬울것 같습니다.
virtualenv는 nvm또는 rvm이 하는 역활들을 해주는 녀석입니다.
각 버전별로 패키지를 따로 설정할 수 있는데요. 가상 환경 이름을 붙이기에 같은 버전이라도
얼마든지 용도에 따라 만들 수 있습니다.

Rsync 정리

회사에서 Rsync를 적극적으로 사용하고 있기에 정리해봤습니다.
조만간 Rsync란 녀석으로 만들어야 되는것도 있고요.
잘 알아두면 프로그래머 인생에 도움이 많이 될 것 같아요.

옵션이나 사용법은 우선 제가 필요로 한 만큼 정리했습니다.

필요에 따라서 문서가 업데이트 될 수도 있습니다.

Rsync란?

2개의 디렉토리를 동기화 시키는 명령어입니다.
하나의 머신의 다른 디렉토리뿐만아니라, 원격에 있는 머신에 있는 디렉토리와도 동기화를 할수 있습니다.
보통사용하는 cp, ftp, rcp이런 카피계열 명령어보다는 동기화 기능이 월등히 좋습니다.
변경됐거나 추가된 파일만 카피한다던지, 소스디렉토리에서 파일을 삭제하면
원격에 있는 머신쪽도 파일을 삭제하는 기능도 있습니다.

Rsync는 동기화할 대상을 가려내는 작업에 “quick check”알고리즘을 사용하고있습니다. quick check알고리즘은 파일사이즈, 최근 변경시간으로 파일들을 찾습니다.

Rsync의 몇가지 추가기능은 아래와 같습니다.

  • 심볼릭링크, 디바이스, 소유자, 그룹 그리고 퍼미션의 복사를 지원
  • GNU tar와 비슷한 exclude와 exclude-from 옵션을 제공
  • CVS exclude모드 – CVS에서 무시하는 파일들을 무시함.
  • 어떠한 리모트 전송쉘이라도 사용가능, rsh, ssh포함
  • 루트권한이 없어도 됨.
  • 파일전송에 파이프라인을 사용하여 레이턴시 비용을 최소화.
  • 익명사용자 혹은 rsync서버인증 지원 (미러링에 최적임)

위와같은 기능을 가지고 있기에, 디렉토리의 백업이나 서버간 파일을 최신파일로 동기화 할때 사용하면 편리합니다.

구문

rsync [-v] [-q] [-a] [-r] [-b] [-u] [-l] [-p] [-o] [-g] [-D] [-t] [-n] [-e=Command] [–del|–delete] [-z] [–exclude] [–stats] [–progress] Source [[USER@]HOST:]DIST 

rsync –version

rsync -h | –help

옵션

-v | –verbose 동기화시 상세정보를 표시함. 해당 옵션은 3개까지 설정가능. 2,3개동시에 설정하면, 더욱 상세한 정보를 표시함
-q | –quiet 동기화 정보를 표시하지 않음. cron등에 의한 배치처리등에서 사용함.
-c | –checksum 전송전에 128비트 MD4의 체크섬을 사용하여, 송신서버의 모든 파일의 체크섬을 만든다. 그 체크섬은 수신서버에서 확인함. 그리고 송신서버와 같은 체크섬, 같은 사이즈, 같은 이름인 파일은 스킵. 해당 옵션을 사용하면 매우 느려짐.
-a | –archive 아카이브 모드로 실행함. [-rlptgoD]옵션을 지정하면 같은 동작을 하나, 해당 옵션 하나로 대부분의 디렉토리, 파일의 정보를 유지하며 동기화가 가능하므로 편리함.
-r | –recursive 재귀적으로 디렉토리를 카피함. 해당 옵션을 지정하지 않으면, rsync명령어로는 디렉토리를 동기화 하지 않음.
-b | –backup 동기화할 디렉토리에 이미 파일이 존재하는 경우, 동기화할 디렉토리에 백업. 이 경우 디폴트로 [~]이 붙는다.
-u | –update 동기화할 디렉토리에 원본소스보다 최신인 파일이 있을경우, 해당 파일은 동기화하지 않음.
–inplace 데이터를 업데이트 해야하는경우, rsync가 파일을 전송하는 방법을 변경한다. 디폴트로는 새로운 복사본을 만들어서 전송하는데, 해당 옵션을 설정하면 동기화 대상 파일에 rsync가 직접 업데이트된 데이터를 쓴다.
이 명령어는 몇가지 영향 끼치는 것이 있다.
1) 바이너리 파일에 사용하면 업데이트 되지 않음.
2) 파일 전송중에는 해당파일은 불일치 상태가 됨.
3) 파일 전송중 실패 혹은 중단이 되면, 해당 파일은 불일치 상태로 남겨짐.
4) 해당파일에 쓰기권한이 없으면 업데이트되지 않음. 그리고
5) rsync의 델타-전송 알고리즘의 효능이 떨어짐.
주의! : 다른 곳에서 해당파일에 접근한다면 사용하지말라, 그리고 복사용으로 사용할경우는 충분히 주의를 기울여서 사용하라.
해당옵션은 큰파일의 블록단위 변화나 데이터의 추가, 그리고 시스템 디스크의 용량이 제한된 상황에서는 유용하다. (네트워크 트래픽 제한은 관계없다.)

또한 해당 옵션은 –partial을 적용시킨다. (전송중 실패한경우 파일을 삭제하지 않기위해서), 그러나 –partial-dir 과 –delay-updates와 같이 사용하면 충돌(conflict)이 일어날 것이다.
rsync 2.6.4에서 –inplace는 –compare-dest, –link-dest와 같이 사용하는건 적절하지 않다.

-l | –links 동기화할 서버에 심볼릭 링크를 작성함. 해당옵션을 지정하지 않을경우에는 심볼릭 링크 파일은 동기화하지 않음
-p | –perms 퍼미션 정보를 유지하면서 동기화를 함.
-o | –owner 소유자 정보를 유지하면서 동기화를 함. root권한을 가진 유저만 실행가능.
-g |–group 그룹 정보를 유지하면서 동기화를함.
-D | –devices 동기화할 디바이스를 재작성함. root권한을 가진 유저만이 실행가능.
-t | –times 파일의 타임 스탬프를 유지하면서 파일을 동기화함. 해당옵션을 지정하지 않는경우는, 모든 파일에 대해 비교 작업을 실행함.
-n | –dry-run 실제로 동기화를 실행하지는 않고, 동기화 하게될 때의 동작을 표시해줌
-e | –rsh=커맨드 rsync커맨드로 사용할 리모트 쉘 프로그램(ssh같은거)를 지정함. 디폴트로는 rsh를 사용
–del|–delete 동기화 소스에 없는 파일이 동기화할 곳에 있는 경우, 그 파일을 삭제함.
–partial 부분적으로 전송된 파일을 유지시킴
–partial-dir=DIR 부분적으로 전송된 파일을 지정한 DIR에 둠.
–delay-updates 업데이트할 파일들을 가장마지막에 둠.
-z | –compress 동기파일을 압축함.
–exclude=패턴 지정한 패턴에 일치하는 파일을 동기대상에서 제외시킴.
–exclude-from=FILE 파일에 기술된 패턴과 일치하는 파일을 제외.
–deamon rsync를 데몬 모드로 실행함.
–config=FILE 별도의 rsyncd.conf파일을 지정
–stats rsync알고리즘의 송신효율을 표시함.
-h | –human-readable 결과의 수치들을 사람이 읽기편한 포맷으로 출력
–progress 전송의 진행 상황을 표시
-P –partial –progress 와 동일
-i | –itemize-changes 모든 업데이트에 대한 요약을 출력
–log-file=FILE 무슨 작업을 했는지에 대한 상세로그를 파일로 남김
동기화 소스 디렉토리 동기화 소스 디렉토리를 지정함.
[[유저명@]호스트명:]동기화할디렉토리 동기화할 서버와 디렉토리를 지정함. 리모트 호스트를 (동기화)타겟으로 할 경우는, 반드시 호스트와 유저명을 같이 지정해야한다.
–version 커맨드의 버전을 표시함.
–help 커맨드의 도움말을 표시함.

사용법

rsync [OPTION]... SRC [SRC]... DEST
rsync [OPTION]... SRC [SRC]... [USER@]HOST:DEST
rsync [OPTION]... SRC [SRC]... [USER@]HOST::DEST
rsync [OPTION]... SRC [SRC]... rsync://[USER@]HOST[:PORT]/DEST
rsync [OPTION]... [USER@]HOST:SRC [DEST]
rsync [OPTION]... [USER@]HOST::SRC [DEST]
rsync [OPTION]... rsync://[USER@]HOST[:PORT]/SRC [DEST]

리모트쉘을 사용하는 경우는 ‘:’을 사용하고, rsync 데몬에 접속하는 경우는 ‘::’이나 ‘rsync://’을 사용한다.
SRC또는 DEST는 모듈명으로 시작해야한다.

동일 호스트내에서 백업하기

rsync -a SRC DIST
rsync -av /home/user/html/ /home/user/backup/

리모트 호스트에 백업하기

rsync -a SRC 유저명@호스트명:DIST디렉토리
rsync -av -e ssh /home/user/html/ www@remotehost.com:/home/user/backup/
rsync -av -e ssh /home/user/html/ www@remotehost.com:/home/user/backup/

참고 URL
http://ftp.wayne.edu/rsync/rsync.html
http://itpro.nikkeibp.co.jp/article/COLUMN/20070822/280151/
http://www.infoscience.co.jp/technical/rsync/rsync.html

참고
rsync -help

Rsync를 처음 만든사람의 논문
http://www.samba.org/~tridge/phd_thesis.pdf

자바개발자를 위한 이클립스 세팅 + 플러그인 설치 for eclipse4.2

자주 하는일은 아니지만,
하게 될때 시간도 많이 걸리고,
엄청나게 귀찮은게 바로 환경세팅이다.

다른 것보다 헷갈리기가 쉬운게
이클립스의 플러그인 설정인데,
안까먹기위해서 정리.

1. 이클립스 다운로드

이클립스는 많은 버전이 있고,
플러그인이 미리 설치되어있는 버전이 있느데 javaee개발을 위한 이클립스를 다운받아서
자기 컴터의 어딘가의 적당한 곳에 압축을 푼다.

나의 경우는 D:\eclipse[버전] 의 형식으로 푼다.
이번에는 4.2버전이므로
「D:\eclipse4.2」가 되겠다.

아래는 다운로드 페이지 링크
http://www.eclipse.org/downloads/packages/eclipse-ide-java-ee-developers/junor

받고나서 적당한 폴더에 압축을 풀텐데
이클립스를 돌릴때에 메모리 부족으로 이클립스가 뻗는경우가 종종있다.
이클립스 압축을 푼 폴더로 이동해서 eclipse.ini파일을 수정해서 메모리를 좀 올려주자.
XXMaxPermSize, Xms, Xmx의 설정만 변경해주면 된다.
수치는 너무 크지 않게 적당히 정하면 된다.

--launcher.XXMaxPermSize
512M
--launcher.XXMaxPermSize
512m
-Dhelp.lucene.tokenizer=standard
-Xms512m
-Xmx1024m

2. JDK설정

– 이클립스에서 기본적으로 사용할 java환경을 설정하자.
Window -> Preferences를 클릭하면 팝업창이 뜨는데 아래와 같다.
팝업창에서 Java -> Installed JERs를 클릭 하면 아래와 같은 창이 나오는데
Add를 누른다.

그러면 Installed JRE Types: 라고 JRE의 타입을 선택하는 페이지가 나오는데,
그냥 「Standard VM」으로 하고 Next를 클릭

아래와 같은 화면이 나오면 Directory를 선택하고 JDK를 설치한 경로를 선택후 Finish를 눌러준다.

잘 설정됐다!

3. WAS서버(톰캣 설정)

Window -> Preferences의 Server를 클릭하면 다음과 같이 된다.

Add를 클릭

톰캣의 버전을 선택하는 부분이 나오는데,
자신의 PC에 인스톨한 톰캣을 선택(나중에 더 추가가능)
나는 우선 6.x로 선택.

Browse를 눌러서 자신이 인스톨한 톰캣폴더를 지정

Finish를 누르면 톰캣이 추가되어있다~

4. 디폴트 인코딩 설정

Window -> Preferences에 들어가서

General -> Workspace에들어가면 하단에 Text file encoding이 있는데 여기서
Ohter를 선택해주고 UTF-8을 선택하자.

————————————————————————–
이제부터 필요한 플러그인들을 설치해보자.

내가 꼭 필요로 하는 플러그인으로는 아래의 플러그인 들이 있는데,
어떻게 설치하는지 알기위해 SVN과 Spring Tool Suite만 설치해보자.
그외 플러그인은 각자 필요한 대로 설치하면 된다.

Subversion플러그인 설치 (Subclipse를 설치하겠삼)

Subversive와 Subclipse가 있으니, 좋은쪽으로 설치하면 된다.
Subversive는 eclipse공식 플러그인이라,
Help → Install New Software → 「Juno – http://download.eclipse.org/releases/juno」의 리스트에있다.
Subclipse는 Update Site에 http://subclipse.tigris.org/update_1.8.x을 설정해서 인스톨한다.

아래와 같이 subclipse와 SVNKit을 둘다 설치해야된다.

이제 next, 라이센스계약에 오케, finish로 설치를 시작해보자.

인스톨하는 중간에 검증되지 않은 프로그램이라고 나오는데 그래도 설치할래?
라는 메세지가 나온다. 무조건 설치하자.
그리고 이클립스를 재시작한다.

Spring Tool Suite 플러그인 설치

help → Install New Software에 들어간다음 Work with: 에 아래와 같은 주소를 넣어주자.
「http://dist.springsource.com/release/TOOLS/update/e4.2」
그중에 필요한걸 알아서 설치하면된다.

나는

Atlassian Connector
Core / Eclipse Integration Commons
– Eclipse Integration Commons
– SpringSource Tool Suite Dashboard
Core / Groovy/Grails Tool Suite
Core / Spring IDE
Core / STS
Extensions (Incubation) / Spring IDE
Extensions / Spring IDE
– Spring IDE Maven Support
Uncagegorized
– AspectJ Development Tools
정도를 설치했다. 설치하고 싶은 내용은 사람마다 다를테니 잘 보고 설치하자.

여기서 「Next」→ 「동의」→「Finish」이다.

추천 플러그인들.
아래 링크는 누군가가 이클립스의 플러그인을 정리해놓은 것이다.
http://www.fromdev.com/2012/01/25-best-free-eclipse-plug-ins-for-java.html

위의 플러그인에 없는것중에 내가 사용하는 것으로는
JUnit과 연동되어서 테스트를 조금 더 편하게 개발할 수 있게 해주는
MoreUnit
MoreUnit소개 – by Outsider

클래스도나 시퀀스 다이어그램을 그려주는 공짜 플러그인인 AmaterasUML

힙덤프, 메모리덤프를 분석할 수 잇는 Memory Analyzer (MAT)등이 있다.

설치방법은 위에 나왔던 SVN이나 Spring Tool Suite와 별다르지 않으므로 큰 문제없이 설치할 수 있을 것이다.

그럼 이클립스로 즐겁게 개발합시다~~~

워드프레스 한글 폰트 변경

워드프레스로 만들어진 다른 블로그를 돌아다니다 보니
폰트가 이쁜거였다.

좀 찾아봤는데, 거의다 웹폰트를 적용하라는 내용이었다.

그래서 웹폰트를 적용할까 하다가, 웹폰트가 아님에도 폰트가 이쁜곳이 있어서 봤더니
거기는 웹폰트가 아닌 그냥 맑은 고딕 –  ‘Malgun Gothic’ 을 사용하고 있었다.

아하! 맑은 고딕쓰면 되겠구나.
폰트 변경법 댄니 쉽다.

사용중인 워드프레스의 테마가 있는 폴더로 이동한다.
나의 경우는  /wp-content/themes/suffusion/ 이었다.

그리고 style.css 파일을 열어서 body를 찾고, 그담에 font-family가 있는 곳을 찾는다.

그리고 거기에 ‘Malgun Gothic’을 젤 앞에 추가해준다. 끝~

body {
        color:#000;
        font-family: 'Malgun Gothic', Arial, Helvetica, sans-serif;

Nginx 시작시키기, 정지시키기, 재시작시키기

필요에 의해서, 아래의 링크를 대~~충 번역한 글입니다.
http://wiki.nginx.org/CommandLine

Nginx 시작시키기, 정지시키기, 재시작시키기

이 페이지는 Nginx를 어떻게 시작시키는지 알려줍니다.
그리고 일단 실행된 Nginx를 어떻게 정지시키고, 재시작할지 컨트롤하는 법을 알려줍니다.

Nginx시작시키기

Nginx는 보통 /usr/bin/nginx 라는 커맨드로 실행됩니다.

Nginx 시작시키기 기본예제

/usr/bin/nginx

Ngnix 시작시키기 고급예제

/usr/bin/nginx -t -c ~/myynginx.conf -g "pid /var/run/nginx.pid; worker_processes 2;"

옵션들

Nginx는 커맨드라인 파라메터를 달랑 몇개만 가지고 있습니다.
수많은 다른 소프트웨어 시스템과는 달리, 설정파일의 설정만으로 설정은 땡입니다. (상상해보세요~)

-c 디폴트파일 대신 사용될 Nginx설정 파일을 지정합니다.

-t  Nginx를 실행하지는 않고 단지 설정파일을 테스트해봅니다. nginx에서 문법에 맞게 설정됐는지 체크합니다. 그리고 설정으로 지정된 파일을 시험삼아 열어봅니다.

-s  master 프로세스로 signal을 날립니다. :stop, quit, reopen, reload. (버전 >=0.7.53)

-v  버전을 찍어줍니다.

-V nginx의 버전, 컴파일러의 버전, 그리고 설정파라메터들을 찍어줍니다.

-ㅔ prefix prefix의 경로를 설정합니다. (디폴트 : /usr/local/nginx/). (버전 >=0.7.53)

-h, -? 도움말 찍기.

nginx 정지, 재시작하기

이미 동작중인 nginx를 정지시키는 방법은 2가지가 있습니다.
첫번째는 -s 명령을 커맨드 라인 파라메터로 넣는 것입니다.
예를들면

/usr/bin/nginx -s stop

이렇게 하면 Nginx서버는 정지될 것입니다. (앞절에서도 말했지만, ‘-s’의 다른 옵션들도 있습니다.)

Nginx를 컨트롤하는 두번째방법은 Nginx의 마스터 프로세스에 시그날을 보내는 것입니다.
디폴트로 nginx는 마스터 프로세스 아이디를 /usr/local/nginx/logs/nginx.pid에 쓰게됩니다.
./configure로 컴파일할때 파라메터로 넘기면 pid경로를 바꿀 수 있습니다. 또는
설정파일에 pid를 직접써서 설정할 수 도 있습니다.
어떻게 ‘QUIT'(정상적으로 종료 – Gracefule Shutdown – )을 Nginx마스터 프로세스로 날리는지는 아래에 나와있습니다.

kill -QUIT $(cat /usr/local/nginx/logs/nginx.pid)

마스터 프로세스는 아래의 시그날들로 조종할 수 있습니다.

TERM, INT - Quick shutdown 빠른 종료
QUIT - Graceful shutdown 정상적으로 종료
KILL - Halts a stubborn process 잘안죽는 프로세스 죽이기
HUP - Configuration reload
      Start the new worker processes with a new configuration
      Gracefully shutdown the old worker processes

      설정 리로드하기
      새로운 워커 프로세스가 시작될때 새로운 설정으로 시작됨
      오래된 워커 프로세스는 알아서 종료

USR1 - Reopen the log files - 로그파일 다시 열기
USR2 - Upgrade Executable on the fly 운행중 실행파일 업그레이드하기
WINCH - Gracefully shutdown the worker processes
        워커프로세스를 정상적으로 종료시키기

워커프로세스가 몇개의 시그날을 지원하기는 하지만, 걔네들을 따로 컨트롤할 필요는 없습니다.

TERM, INT - Quick shutdown 퀵 종료
QUIT - Graceful shutdown 정상 종료
USR1 - Reopen the log files 로그파일 다시열기

시그날을 사용해서 새로운 설정파일을 로딩시키기

Nginx는 운영중에도 nginx를 컨트롤 하기 위해 사용할 수 있는 몇개의 시그날을 지원합니다.
가장 일반적인 시그날은 15인데, 실행중인 프로세스를 정지시키기위해 사용합니다.

USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 2213 0.0 0.0 6784 2036 ? Ss 03:01 0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf

그런데, 더 재미 있는것은 운행중에 nginx의 설정파일이 변경이 된다는 것입니다.
(우리가 리로드 되는 설정의 우선순위를 테스트했음을 주의하세요.)

2006/09/16 13:07:10 [info] 15686#0: the configuration file /etc/nginx/nginx.conf syntax is ok
2006/09/16 13:07:10 [info] 15686#0: the configuration file /etc/nginx/nginx.conf was tested successfully
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 2213 0.0 0.0 6784 2036 ? Ss 03:01 0:00 nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf

nginx가 HUP 시그날을 받았을 때 무슨일이 일어났는가 하면, nginx는 설정파일의 파싱을 시도하고
(지정한 파일이 있으면 그 파일을 없으면 디폴트) 파싱이 성공하면, 새로운 설정을 적용하려고 합니다.
(즉, 로그파일과 listen상태의 소켓이 재 오픈되요. ). 재설정이 성공하면, nginx는 새로운 워커 프로세스를
실행시키고 이전의 오래된 워커들에게는 정상종료되도록 시그날을 보냅니다. 시그날을 받은 워커는 listen socket들을
닫지만, 현재 클라이언트들에 대한 동작은(to servce current clients) 계속됩니다.
모든 클라이언트에 대한 동작이 완료되면 오래된 워커들은 종료되고ㅡ 만약에 nginx가 새로운 설정의 적용에 실패하면,
이전 설정으로 계속해서 동작하게 됩니다.

운행중에 새로운 바이너리로 업그레이드하기 (Upgrading To a New Binary On The Fly)

만약에 nginx의 바이너리를 새로운 녀석으로 교체하고 싶다면,
(새버전으로의 업그레이드 혹은 서버의 모듈들의 추가/삭제를 할 때)
어떠한 서비스의 다운타임이 없이- 들어오는 요청의 소실 없이 – 도 변경가능합니다.

첫째로, 이전 버전의 바이너리를 새것으로 교체하려면, USR2 시그날을 마스터 프로세스로 보내면 됩니다.
그 시그날은 nginx의 .pid 파일을 .oldbin으로 이름을 변경합니다.
(예를들면 /usr/local/nginx/logs/nginx.pid.oldbin), 그러고 나서 새로운 바이너리를 실행시키고,
마스터 프로세스와 새로운 워커 프로세스들이 차례대로 시작됩니다.

: PID PPID USER %CPU VSZ WCHAN COMMAND
33126 1 root 0.0 1164 pause nginx: master process /usr/local/nginx/sbin/nginx
33134 33126 nobody 0.0 1368 kqread nginx: worker process (nginx)
33135 33126 nobody 0.0 1380 kqread nginx: worker process (nginx)
33136 33126 nobody 0.0 1368 kqread nginx: worker process (nginx)
36264 33126 root 0.0 1148 pause nginx: master process /usr/local/nginx/sbin/nginx
36265 36264 nobody 0.0 1364 kqread nginx: worker process (nginx)
36266 36264 nobody 0.0 1364 kqread nginx: worker process (nginx)
36267 36264 nobody 0.0 1364 kqread nginx: worker process (nginx)

여기서, 두개의 niginx 인스턴스가 실행되고, 들어오는 리퀘스트를 같이 처리합니다.
오래된 인스턴스를 빼려면, WINCH시그날을 오래된 마스터프로세스에 보내야합니다.
그러면 그 녀석의 워커 프로세스는 정상종료를 시작할것입니다.

: PID PPID USER %CPU VSZ WCHAN COMMAND
33126 1 root 0.0 1164 pause nginx: master process /usr/local/nginx/sbin/nginx
33135 33126 nobody 0.0 1380 kqread nginx: worker process is shutting down (nginx)
36264 33126 root 0.0 1148 pause nginx: master process /usr/local/nginx/sbin/nginx
36265 36264 nobody 0.0 1364 kqread nginx: worker process (nginx)
36266 36264 nobody 0.0 1364 kqread nginx: worker process (nginx)
36267 36264 nobody 0.0 1364 kqread nginx: worker process (nginx)

그리고 얼마후에, 오래된 워커프로세스는 모두 없어지고, 새로운 워커 프로세스들만이 리퀘스트 요청을 처리하게 됩니다.

: PID PPID USER %CPU VSZ WCHAN COMMAND
33126 1 root 0.0 1164 pause nginx: master process /usr/local/nginx/sbin/nginx
36264 33126 root 0.0 1148 pause nginx: master process /usr/local/nginx/sbin/nginx
36265 36264 nobody 0.0 1364 kqread nginx: worker process (nginx)
36266 36264 nobody 0.0 1364 kqread nginx: worker process (nginx)
36267 36264 nobody 0.0 1364 kqread nginx: worker process (nginx)

여기서, 이전의 서버로 되돌리는것도 가능한데, 왜냐하면 listen socket들을 닫지 않았기 때문에 아래의 절차를
따라하면 됩니다.

– 오래된 마스터 프로세스에 HUP 시그날을 보낸다. – 설정파일의 리로딩 없이 워커 프로세스를 시작시킨다.
– 새로운 마스터 프로세스에 QUIT 시그날을 보내서 그것의 워커프로세스를 정상적으로 종료시킨다.
– 새로운 마스터 프로세스에 TERM 시그날을 보내서 강제로 종료시킨다.
– 어떠한 이유로 새로운 마스터 프로세스가 종료되지 않으면, KILL 시그날을 보낸다.

새로운 마스터 프로세스가 종료되고, 오래된 마스터프로세스는 .oldbin 접미어를 그것의 .pid파일에서 삭제합니다.
그리고 모든것이 업그레이드 하기 전으로 돌아가게됩니다.

만약에 업그레이드가 성공적으로 되었고 새 서버로 유지하는게 좋으면, QUIT시그날을
오래된 마스터 프로세스로 보내면 새로운 서버만이 돌게됩니다.

: PID PPID USER %CPU VSZ WCHAN COMMAND
: 36264 1 root 0.0 1148 pause nginx: master process /usr/local/nginx/sbin/nginx
: 36265 36264 nobody 0.0 1364 kqread nginx: worker process (nginx)
: 36266 36264 nobody 0.0 1364 kqread nginx: worker process (nginx)
: 36267 36264 nobody 0.0 1364 kqread nginx: worker process (nginx)

레퍼런스