글쓴이 보관물: LeekyoungIl

[NoSQL & Cache] Redis vs Memcached ( 왜 Redis 를 사용해야 하는가? )

저는 Memcached 를 이용하여 프로젝트를 한적이 있습니다.
그리고 개인적으로 캐시 솔루션에 관심이 많습니다. (회사에서 하는 업무도 이쪽이 많습니다.)

여튼…

저희 팀원분과 어제 새벽에 Memcached 와 Redis 에 관해 채팅으로 의견을 주고 받다가 팀원분이 한번 읽어보라고 주신 글이 있는데
2014년 10월글 이지만 (아직 Redis 3.0 이 나오기 전글) Redis 와 Memcacheed 의 차이점을 알수있고 가볍게 읽어보기 좋은글 같아서
공유를 하고 제 생각을 조금 넣어서 해석을 해서 포스팅 하니 참고가 되었음 좋겠습니다. (대강 해석 했으니 원문보며 참고만 하세요. ^^)

원문 : http://www.infoworld.com/article/2825890/application-development/why-redis-beats-memcached-for-caching.html

————————————————————————————————————————-

Redis 는 더 강력하고 다루기 쉽기 떄문에 보통 캐시 솔루션을 선택할때 Redis 를 선택합니다, 그러나 Memcached 는 여전히 쓰여지고는 있습니다. (저도 쓰고 있습니다.)

Memcached 와 Redis 중에 어떤것이 더 좋을까? 이것은 최근 데이타 베이스 기반 웹 어플리케이션에 관해서 최대한 성능을 뽑아내기 위헤 토론할떄 항상 나오는 질문 입니다.
이것들은 유명한 캐시 엔진들로 비슷한점도 있지만 매우 중요한 차이점이 있습니다.
하지만 역시 Redis 는 Memcached 보다 더 새롬고 다양한 기능이 있기 때문에 대부분 Redis를 선택 하곤 하지만 그렇지 않은 경우도 있습니다.

유사점들

일단 유사한 부분부터 보도록 하겠습니다.

Memcached 와 Redis 는 in-memory 위에서 동작하는 key-value 스토리지로 둘다 NoSQL 에 속하는 데이타 관리 솔루션 이며 둘다 같은 key-value 데이타 모델을 기반으로 동작합니다.
모든 데이타는 메모리 안에 있으며 이는 때문에 캐시 관점에서 매우 유용합니다. 퍼포먼스 측면에서 두 데이타 스토리지는 처리량이나 지연속도 등 동일한 특성을 나타냅니다.
게다가 in-memory 데이타 스토리지들인 Memcached, Redis 둘다 인기 있는 완성된 오픈소스 프로젝트 입니다.

Memcached 는 원래 2003년에 Brad Fitzpatrick 에 의해 LiveJournal 웹사이트를 위해 개발 되었으며 그뒤로 Memcached 는 C 로 다시 개발되었습니다. (최초에는 perl 로 개발됨) 그리고 공개 되었고 새로운 웹 어플리케이션의 패러다임의 초석이 되었습니다. 그리고 지금까지 Memcached 는 새로운 기능보다는 안정성과 최적화에 중점을 두고 개발되고 있습니다.

Redis 는 2009년에 Salvatore Sanfilippo 애 의해 만들어 졌고 그는 여전히 Redis 의 개발을 리드하는 사람이고 혼자서 프로젝트를 작업하는 사람 입니다.
Redis 는 때로 “약빤 Memcached (ㅎㅎ)” 라고 묘사 됩니다. 이는 Memcached 를 사용하면서 좋은점을 기반으로 개발되었기 떄문 입니다.

Redis 는 Memcached 에 비해 기능이 많아 더 강력하고 다루기 쉽지만 좀더 복잡 합니다.

많은 회사들의 셀수도 없는 어플리케이션의 운영 환경에서 개발자들은 다양한 언어의 클라이언트 라이브러리들을 사용하여 Memcached 와 Redis 를 사용하고 있습니다.
사실상 웹 어플리케이션에서 둘중 하나를 사용하지 않는다는 것은 매우 드문이 입니다.

왜 Memcached 와 Redis 는 왜 엄청 인기가 있는것일까요? 뿐만 아니라 매우 효과적이고 상대적으로 심플한것일까요?
둘중 어떤것이든 개발자가 쉽게 사용하기 위해 고려되어있고 이로인해 불과 몇분만에 어플리케아션에 캐시를 적용할수 있습니다.
이것은 매우 작은 시간만 투자해서 즉시 효과를 볼수있고 일반적으로 정렬에서 성능에 극적으로 영향을 끼치며. (보통 데이타 베이스 기반에서 어떠한 데이타를 select 해올때 많은 비용을 차지하는 부분이 order 부분일 것 입니다. 하지만 이런 in-memory 기반의 Memcached 나 Redis 는 메모리에 저장되어 있어서 매우 빠른 정렬이 가능하다는 이야기 같습니다.)
그것은 마치 마법처럼 성능에 있어 간단한 해결책과 큰 이점을 주고 있습니다.

그러면 언제 Memcached 를 사용해야 할까요?

Redis 는 최근에 나왔고 새로운 기능들에 있어 Memcached와 비교된다. Memcached 보다 Redis 를 선택하는것이 항상 더 좋은 선택 이지만 Memcached 가 더 좋은 두가지의 상황이 있습니다.

첫번째로 작고 변하지 않는 데이타 예를들어 HTML 코드의 부분을 캐싱할때 내부 메모리 관리가 Redis 만큼 복잡하지 않아 능률적이기 떄문에 Memcached 는 메타 데이타에 있어 비교적 작은 메모리를 사용합니다. Memcached 에서 지원하는 유일한 데이타 타입인 String은 오로지 읽기 전용이고 더이상 처리가 필요 없기 때문에 데이터를 저장하기에 좋습니다.

두번째로 Memcached 는 여전히 Redis 에 비해 수평적 확장에서 약간의 좋은점이 있습니다. 기능 구현과 디자인 확장을 하는데 있어서 쉽지만. 사실 Redis 도 이런 목적으로(Memcached 처럼 수평적 확장이 쉽도록) 한대 이상으로 확장을 위한 클러스터링이 3.0 이후에 포함되어 있습니다.

언제 Redis 를 사용해야 할까요?

당신이 일할때 강제적을 Memcachd 를 사용해야 하거나 위의 2가지 사항이 아니고서는 항상 Redis 를 사용하는 것이 맞습니다.

당신을 Redis 를 캐시 용도로 매우 강력하게 사용할수 있고. 예를들어 캐시한 콘텐츠를 미세하게 튜닝하거나 그리고 지속성에 및 전반적인 효율성등을 조정할수 있습니다.

Redis 는 분명 캐쉬관리적인 측면에서 확실하게 우월하며. 캐쉬는 새로운 데이타를 캐시하기 위해 오래된 데이타를 지우는 방식의 메카니즘을 사용하고 있습니다. Memcached 도 데이타 관련 메카니즘은 LRU 알고리즘을 사용하고 있으며 Redis 는 이와는 대조적으로 6가지의 데이타 추출 정책이 있습니다. 또한 Redis 는 좀더 정교한 메모리 관리 방식을 사용한다.

Redis 는 당신이 어떠한 오브젝트들을 캐시할수 있도록 엄청 편리한 기능을 제공하며. 반면 Memcached 는 키의 이름이 250 바이트로 제한 되며 캐시 값의 용량은 1메가바이트로 제한됩니다. (10M였나? 그정도로 늘릴수도 있긴함) 그리고 오로지 문자열만 캐시할수 있다. Redis 는 키명과 값의 용량을 각각 512메가 바이트까지 크게 사용할수 있고 그것들은 안전한 바이너리로 관리 됩니다. Redis 는 6가지의 데이타 형식이 있어서 좀더 정교하고 효율적으로 데이타를 캐시하며 이로인해 어플리케이션 개발자에게 좀더 가능성 있는 세상을 열어줍니다.

대신 직렬화된 오브젝트를 저장해야하고 개발자는 Redis 의 해시 를 이용해 오브젝트의 필드 그리고 값을 유니크 하게 관리할수 있습니다. Redis의 해시는 개발자들이 필요한 기능을 제공합니다. 전체 문자열을 가지고 온다던지 역직렬화하고 그것의 값을 업데이트 하고 다시 시리얼 라이즈를하고 또 문자열을 바꾼다던지 자잘한 모든 업데이트 기능을 지원합니다. 그리고 그것은 작은 리소스를 소비하여 개발자의 퍼포먼스를 낼수 있게 한다는 것이좋습니다. 또한 Redis 가 제공하는 다양한 데이타 타입이 있는데 List 그리고 Set 이 있고 더 복잡한 캐시관리에 사용될수 있습니다.

또 다른 Redis 의 중요한점은 데이타를 저장하는 방식이 불투명하지 않다는 것입니다. 이 뜻은 데이타를 저장할떄 서버가 데이타를 직접적으로 조작한다는 것으로 Redis 에 있는 160가지 이상의 명령들은 서버측 내장 명명어로 데이타 를 처리하고 조직하며 이들의 내장된 명령어와 유저의 스크립트 들은 당신에게 손쉽게 데이타 처리를 다른 시스템에 네트웍으로 전달하지 않고 직접적으로 핸들링 할수 있도록 제공합니다.

Redis 는 캐시의 지속성(유사시에 데이타 백업의 의미) 옵션을 제공합니다, 이는 서버가 의도 되지 않게 오류가 나거나 셧다운이 일어났을때 재기동하면서 다시 복구될수있게 디자인 되었으며. 우리는 데이타를 캐시 하는동안 캐시는 휘발성의 성격이지만 이 데이타를 디스크에 저장 시킴으로서 캐싱 시나리오에서 매우 도움이 될수 있습니다. 그러니까 캐시 데이타가 Redis 에서 따로 백업 용도로 저장한 디스크에 존재하면 Redis 서버가 재시작후에 캐쉬를 다시 메인 데이타 스토리지에서 가지고 오는 부하를 덜수 있다는 소리 입니다.

마지막으로 Redis 는 리플레케이션을 제공 합니다. 리플리케이션은 어플리케이션에서 안정적인 캐시를 제공합니다. 생각해보면 캐시의 장애는 오로지 매우 짧은 순간에 유저경험이나 어플리케이션의 성능적인 측면에서 검증이 된 솔루션을 가지고 캐시의 내용 및 가용성을 보장 합니다. 이것은 대부분의 케이스에서 가장 좋은 장점으로 작용 합니다. (아 이부분은 뭔소린지 해석이 잘….. 대략 리플리케이션을 사용할수 있어서 장애를 최소화 할수 있다는 이야기 입니다.)

오픈소스 소프트웨어는 오늘날에 사용할수 있는 최고의 기술을 계속 제공 합니다. 캐시로 인해 어플리케이션의 성능을 개선할떄 Redis 와 Memcached 는 자연적으로 캐시 솔루션에 후보에 올라갔습니다. 그렇지만 좀더 괜찮은 기능과 좀더 발전된 디자인 으로 설계된 Redis 가 당신의 모든 시나리오에서 첫번쩨 선택이 될 것입니다.

————————————————————————————————————————-

지금은 유일하게 Redis 대비 Memcached 의 장점이었던 수평적 확장도 Redis 3.0 이 나오면서 사라지게 되었네요.. ㅜㅜ
결론은 닥치고 Redis 써라 !

[Hbase] 구동시에 regionserver 에서 마스터서버 주소를 localhost 로 접속을 시도할 경우 (Attempting connect to Master server at localhost)

네이버의 pinpoint 를 도입하기 위해 테스트를 하려고 하던중 이었다.

pinpoint 를 설치하기 위해서는 일단 hadoop + zookeeper + hbase 를 설치해야하는 상황…
일단 hadoop 부터 zookeeper 까지는 문제 없이 설치를 완료 했다.

하지만 hbase 는 자꾸 문제가 발생 ….

일단 문제가 hbase 의 regionserver 가 구동시에 master 서버로 접속을 해서 validation 체크를 해야 하는데
자꾸 로그상으로 regionserver 에서 master 서버의 아이피를 localhost 로 보고 있는…

Exception log를 보면

이런식 으로… Attempting connect to Master server at localhost,60000 을 보고 있다.

hbase 설정 파일에는

분명히 마스터로 namenode 를 잡아 놨는데도 저렇게 바라보니 정말 혼란스러웠다..
구글링을 해봤지만 쓸만한 답변은 찾을수가 없었다. (대부분 위에 설정 파일처럼 hbase.master 를 설정 해보라는 것)

이 상태에서 zookeeper 로 hbase 상태를 확인해 보면

이렇게 아무것도 안나오는 상황…

일단은 각 regionserver 들에 HRegionServer 프로세스가 잘 뜨고 있고 namenode 인 마스터 서버에도 HMaster 가 잘뜨고
있기 때문에 결국은 남은것은 host 설정 문제 뿐 이었다… (조언을 부탁 드린 네이버 분들도 이 부분을 알려주심)

이쪽으로 구글링을 집중적으로 해보았다.
결과는 127.0.0.1 localhost 설정을 없애 보라는것

일단 /etc/hosts 내용을 보면

* 참고사항
1. 총 서버는 4대
2. 각 서버의 호스트 명은 hadoop-1, hadoop-2, hadoop-3, hadoop-4
3. 아이피는 내부 아이피 이니 해킹 시도는 꿈에도 꾸지 말것!

이렇게 되어있고 namenode 가 마스터 이다.
그리고 regionserver 는 datanode01 ~ 03 이다.

여기서

이 부분을 이렇게 주석 처리 하고

이렇게 각 서버별로 서버명과 자신의 아이피를 설정해준뒤

zookeeper 클라이언트 에서 /hbase 삭제후에 다시 hbase 기동!

기동하면서 regionserver 로그를 tail 로 찍어놓고 보면

master 서버의 주소를 의도한대로 hadoop-1로 보고 있는것을 알수 있다.

잘 실행이 되는것을 알수 있다.

휴… 해결.. 이제 pinpoint 설치하러 가야겠다.

그런데 이 설정으로 localhost 127.0.0.1 설정이 없어졌는데..
이로 인해 문제가 다른곳에서 발생을 할지 … 좀 걱정이긴 합니다… 따라서… 좀 써보다가 문제가 발생하면
다시 포스팅 하도록 하겠습니다…

———————–추가————————————————————

아무래도 localhost 를 없앤것이 좀 찝찝한 나머지 좀 테스트를 해보았습니다.
결론적으로 말하면 linux 에서는 127.0.0.1 localhost 설정이 hosts 파일에 없어도 기본적으로 localhost 를 127.0.0.1
로 인식하는거 같네요.

이런식으로 인식이 됩니다.

그래도 혹시 어플리케이션 중에 hosts 파일의 localhost 설정을 사용하는 것이 있을수 있기 때문에
각 서버의 /etc/hosts 파일에 localhost 를 추가해 주기로 했습니다.

위의 설정의 요는 localhost 가 127.0.0.1 이 아닌 본인 서버의 아이피만 바라보면 되기 때문에

hadoop-1 서버

hadoop-2 서버

hadoop-3 서버

hadoop-4 서버

이렇게 추가시켜 주었고 잘 동작 하네요..

도움이 되시길 바랍니다.

Format aborted in namenode

하둡을 처음 설치해 보는데 namenode 포멧이 안되는 것이었다.


[root@hadoop-1 bin]# hadoop namenode -format
Warning: $HADOOP_HOME is deprecated.

15/05/22 02:37:44 INFO namenode.NameNode: STARTUP_MSG:
/************************************************************
STARTUP_MSG: Starting NameNode
STARTUP_MSG: host = hadoop-1/127.0.0.1
STARTUP_MSG: args = [-format]
STARTUP_MSG: version = 1.2.1
STARTUP_MSG: build = https://svn.apache.org/repos/asf/hadoop/common/branches/branch-1.2 -r 1503152; compiled by 'mattf' on Mon Jul 22 15:23:09 PDT 2013
STARTUP_MSG: java = 1.7.0_79
************************************************************/
Re-format filesystem in /home/hadoop/hdfs/namenode ? (Y or N) y
Format aborted in /home/hadoop/hdfs/namenode
15/05/22 02:37:46 INFO namenode.NameNode: SHUTDOWN_MSG:
/************************************************************
SHUTDOWN_MSG: Shutting down NameNode at hadoop-1/127.0.0.1
************************************************************/

이유는….

Re-format filesystem in /home/hadoop/hdfs/namenode ? (Y or N) y

이 부분

대소문자 가림….. Y 로 해야한다..

하하..

[AngularJS] controller 2번 호출 되는 문제

AngularJS 를 이용해서 개인적인 프로젝트를 하는데 Controller가 2번이 호출되는 문제가 발생 했다.

대략 컨트롤러 소스 를 올려보면

여기서 사용중인 IntroController 소스는

이렇게 되어있는데 저 IntroController 이 두번이 호출이 되는 현상이 발생 했다.

Screen Shot 2015-05-07 at 3.58.05 PM

대략 이런식로..

이게 왜 문제가 발생 하냐면

templateUrl: ‘/assets/views/intro.html’ 이 html 파일 안에

data-ng-controller=”IntroController” 이렇게 컨트롤러를 또 호출해주는 코드가 있었다 -_- ㅎㅎ

하핫 그런데 웃긴것은 검색 해보니 나말고 이런사람 많다는거! =_=;;

Play framework 에서 Cookie 사용하기

이번에 Play framework 에서 사용자 인증을 처리하는데 Cookie 를 사용하기 위해 좀 찾아 보았다.
역시 Play framework! 쿠키 사용하는것이 완전 심플 했다.

이렇게 간단하게 사용이 가능하다.

Play 굿 +_+)=b

ConcurrentHashMap 의 lock 거는 기법

일단 ConcurrentHashMap 과 HashMap 의 차이점은 다 알고 있다는 전제하에 포스팅을 작성 한다.

이 포스팅을 하게된 이유는 사실 어떤분이 나에게 ConcurrentHashMap 과 HashMap 의 차이점을 아냐고 물어봤고
물론 알고 있어서 쏼라쏼라 대답을 했지만 (Multi-Threaded 환경에서 thread safe 여부) 거기에서 끝나지 않고
또 물어보시더라 ConcurrentHashMap 이 왜 Thread 에 safe 한지? 어떤 원리인지 아세요?

그래서 나는 사실 정확하게 알진 못했지만 대략 MySQL 의 innodb 처럼 row-level lock 걸듯이 접근하고 있는 해당 Key 값에
lock을 걸지 않을까요? 라고 대답을 했다.

이 대답은 후에 찾아 보니 반은 맞고 반은 틀리더라…

그리고 다시한번 정확하게 정리한다..

——————————————————————————————————

보통은 우리가 Multi-threaded 환경에서 key-value 저장소가 필요할때 자바에서 사용하는 것이

크게

1. HashTable
2. HashMap
3. ConcurrentHashMap

이렇게 있는데 파악을 하기 위해서 각 자바 source 를 까보았다.
가장 중요한 Get, Set 부분만 보면

1. HashTable


public synchronized V More ...get(Object key)
public synchronized V More ...put(K key, V value)

보이는가? 메소드 레벨에서 synchronized 를 걸어 버린다.

2. HashMap

얘는 볼것도 없이 synchronized 가 없다. 따라서 속도는 빠르지만 Multi-threaded 환경에서 그냥 쓰면 여러 Thread 에서 동시 접근시 Exception 이 난다.

3. ConcurrentHashMap

얘는 특이하게 synchronized 가 아니라 lock 을 사용한다.


V More ...put(K key, int hash, V value, boolean onlyIfAbsent) {
lock();
try {
int c = count;
if (c++ > threshold) // ensure capacity
rehash();
HashEntry[] tab = table;
.
.
.

처음에 이 부분만 보고 아싸 내 말이 맞았구나 했다. 하지만 찾아 보니

비슷은한데 CurrentHashMap 은 Map 자체를 Currency 레벨로 영역을 쪼개서 (기본이 16개)
해당 영역별로 lock을 거는 것이었다. 이 Lock 이름은 ReentrantLock 이라고 한다.

소스에서

CurrentHashMap 생성자중에


public More ...ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel) {
...
}

이런놈이 있더라… 하아…

역시 갈길이 멀다.. 그래도 좋은거 하나 확실하게 배웠다.

Play framework 에서 JVM 옵션 조정 하기

전에 포스팅 했던 JSrank 는 Play framework 를 사용하여 만들었는데
오픈 하면서 JVM 옵션을 조정할 일이 생겼다.

간단했다.

Linux 기준으로


shell >> JAVA_OPTS="-Xms512m -Xmx1g -XX:NewRatio=3 -XX:+UseConcMarkSweepGC -Xloggc:gc.log -verbose:gc -XX:+PrintGCDateStamps -server"

하면 끝.

(혹시 모르니 shell 에서 echo $JAVA_OPTS 명령어로 설정값을 확인해 보는것이 좋다)

설정후

play 로 play framework 콘솔 진입후

start 80 (80 포트로 시작)

후에 ctrl + d 로 빠져 나오면 된다. (ctrl + c 하지 말자! 취소다)

ebean 에서 orm 테이블 조인

아놔….

Play framework 를 사용하여 웹어플리케이션을 만들고 있는데
일단 Play framework 는 h2 database engine 이 embedded 되어 있어서 편리하게 사용할수 있고 해당 db 는
ebean 을 사용하여 orm 을 사용할수 있다.

난 사실 orm 보다 sqlmap 을 더 선호하지만 한번 사용해 봤다.

생각보다 ebean 은 사용하기 편했고 별다른 문제가 없었지만 서로 다른 테이블 join 시에 문제가 발생했다.
ebean 의 메뉴얼을 보고 해도 안되는 것이었다… ㅜㅜ 즉


SELECT a.data1, b.data2 FROM A as a INNER JOIN B as b a.id = b.id WHERE ...

이런 쿼리를 짜고 싶다고 가정하면

Entity 2 개를 정의하고 (Ebean 에서 Entity 즉 우리가 일반적으로 Java 프로그래밍에서 말하는 Model)

A Entity


@Entity
@Table(name = "a")
public class A extends Model {
...

@OneToMany(mappedBy = "bTest", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
public ArrayList b = new ArrayList<>();
}

B Entity


@Entity
@Table(name = "b")
public class B extends Model {
...

@ManyToOne(fetch = FetchType.EAGER)
public A a;
}

이렇게 정의 해주고


Ebean.find(A.class)
.select("a.data1, b.data2")
.where()
...

해도 조인이 안걸린다.. 그냥 A 테이블만 select 될뿐…
이걸로 몇일동안 메뉴얼도 보고 이래저래 다 해봤는데 실패..

결국

RawSql rawSql = RawSqlBuilder.parse(sql).create();

를 사용하여 직접 SQL 문 작성하여 만들었음…

아 정말 왜 안되는걸까?…

언젠가 해결 되면 해당 포스트에 댓글로 달겠음… ㅜㅜ

jmx 를 이용한 JVM 모니터링 사용하는 방법

JVM 상태를 모니터링할때 간단하게 사용할수 있는것이 바로 JMX 이다.
java 를 설치하고 기본적으로 깔려있는 비주얼 jvm으로 간단하게 확인 가능하다

java 어플리케이션을 실행전에 해당 옵션을 추가해 주면 된다.

export JAVA_OPTS=”$JAVA_OPTS -Dcom.sun.management.jmxremote=true”
export JAVA_OPTS=”$JAVA_OPTS -Dcom.sun.management.jmxremote.port=포트”
export JAVA_OPTS=”$JAVA_OPTS -Dcom.sun.management.jmxremote.ssl=false”
export JAVA_OPTS=”$JAVA_OPTS -Dcom.sun.management.jmxremote.authenticate=false”
export JAVA_OPTS=”$JAVA_OPTS -Djava.rmi.server.hostname=서버아이피”

해당 설정은 인증없이 바로 JMX 에 접근할수 있으니 ACL 등을 이용해서 접근 권한을 설정하도록 하고

만약 인증이 필요하면 jmxremote.access과 jmxremote.password 파일이 필요하다.

jmxremote.access : 사용자 권한
jmxremote.password : 사용자 비밀번호

jmxremote.access는 $JAVA_HOME/jre/lib/management/ 에 위치해 있다.
jmxremote.password는 $JAVA_HOME/jre/lib/management/에 템플릿파일이 있으니 복사해서 쓰면 된다.
(chmod 600 jmxremote.password 권한 설정 필수 읽기만 가능하도록)

다음 해당 값을 바꿔준다.
export JAVA_OPTS=”$JAVA_OPTS -Dcom.sun.management.jmxremote.authenticate=true”

테스트 결과 어느정도 고 부하가 있는 서버에서도 큰 문제없이 사용이 가능했었다.
그래도 꼭 테스트를 하고 사용하도록 하자