2013년 3월 29일 금요일

Thrift 에서 Avro 로 급변경

현재 제작 중인 서비스의 내부 통신용 모듈을 뭘로 할까 하다가...
속도면에서 Apache Thrift 를 사용하려고 했는데, 어찌하다보니 알게된 Avro 가 더 괘찮은 해법이 되지 않을까 싶네요... 
더군다나 Avro RPC는 앞으로 나아갈 방향인 Hadoop 과 통합이 된다니 급 땡기네요.
특히나 대량의 비정형 메타 데이터가 전송되어야해서 Avro가 적격인 거 같습니다...

Avro, Thrift, Protocol Buffers 를 비교한 자료를 보면 어느정도 서로의 장단점을 알 수 있을 듯

2013년 3월 28일 목요일

Windows 8에 Couchbase 2.0 설치하기

Couchbase 2.0을 윈도우즈 8 에 설치했더니... localhost:8091이 안 열림... 서비스는 도는데... 초기화 설정을 못해서 아무것도 안됨...

Mac 에서는 잘 되는뎅....

구글링 해보니 Installing Couchbase 2.0 under Windows 8 에 자세히 나옴.

위와 같이 하면 설정까지는 잘 되는데, couchbase-node1 이 죽어 있음... 에구...
결국 Couchbase  는 Mac 에서만 테스트 중...

2013년 3월 26일 화요일

Spring 3.1 + Redis 를 이용한 Cache

이번 주에는 Spring 3.1 에서 지원하는 Cache 관련해서 많은 글을 썼는데, 요즘 가장 많이 사용되는 Redis 를 저장소로 사용하는 Cache 를 만들겠습니다.

Redis 를 구현하기 위해서 spring-data-redis 와 jedis 라이브러리를 사용했습니다.
jedis 만으로도 구현할 수 있지만, 편하게 spring-data-redis 의 RedisTemplate 를 사용하기로 했습니다.

우선 Redis 를 캐시 저장소로 사용하기 위해 환경설정을 합니다.

1. RedisCacheConfiguration.java


한가지 RedisCacheFactory를 생성할 때 주의할 점은 JedisShardInfo 로 생성해야지, JedisPoolingConfig나 기본 생성자로 생성 시에 RedisTemplate 에서 connection을 제대로 생성 못하는 버그가 있더군요 ㅠ.ㅠ 이 것 때문에 반나절을 허비...

2. RedisCacheManager.java



 3. RedisCache.java



RedisCache의 get / put 은 일반적으로 쓰는 opsForValue() 를 사용했습니다. 다른 것을 사용할 수도 있을텐데, 좀 더 공부한 다음에 다른 것으로 변경해 봐야 할 듯 합니다.
마지막에 clear() 메소드도 jedis 에는 flushDB(), flushAll() 메소드를 지원하는데, RedisTemplate에서는 해당 메소드를 expose 하지 않아 코드와 같이 RedisCallback 을 구현했습니다.

4. RedisCacheTest.java



UserRepository는 전에 쓴 Spring 3.1 + EhCache 등의 글과 같은 코드라 생략했습니다.
Redis 관련은 Windows 에서는 구 버전만 지원하고, 신 버전은 linux 만 가능하더군요...
그래도 성능은 정평이 나있으니, HA 구성 시에는 가장 먼저 고려되어야 할 캐시 저장소라 생각됩니다.

저는 앞으로 hibernate  2nd cache provider for redis,  hibernate-ogm-redis 를 만들어 볼 예정입니다.

2013년 3월 25일 월요일

Spring 3.1 + Couchbase 를 이용하여 Cache 만들기

오늘 글 쓴 김에 다 써버려야 겠네요...
이번에는 Couchbase 를 저장소로 사용하여, Spring Cache 를 사용해 보도록 하겠습니다.
간략하게 Couchbase 에 대해 설명하면... Memcached + CouchDB 라고 보시면 되구요. 설정에 따라 메모리 저장소로 (Memcached), Document DB 형태(CouchDB) 로 사용할 수 있습니다.
Memcached 의 단순 캐시에서 DocumentDB 로 발전했다고 보시면 되고, Map Reduce 도 가능합니다.

하지만!!! 오늘은 그냥 캐시로 사용하려고 합니다.

1. CouchbaseCacheManager



2. CouchbaseCache



3. CouchbaseCacheConfiguration


환경 설정은 각자 환경에 맞추면 됩니다만, default bucket 만 비밀번호 없이 접근이 가능합니다.
다른 bucket 을 사용하려면, 미리 만드시고, 보안을 설정하셔야 합니다.

4. Couchbase Admin Screenshot



이제 남은 건 Redis 만 남았네요... 요건 다음 기회에...

Spring 3.1 + MongoDB 를 이용한 Cache

앞서 EhCache, Memcached 는 일반적으로 메모리를 저장소로 사용합니다만, MongoDB 와 Couchbase 는 정보를 Document 로 관리하는 NoSQL DB라 볼 수 있습니다.

이런 의미로 단순 캐시로 쓰기에는 너무 많은 기능을 가지고 있다고 봐야합니다. 그런만큼 메모리에서만 작동하는 캐시시스템보다는 성능은 느립니다.
하지만 대용량 데이터나 캐시해야 할 양이 엄청 많다면? 그리고 한번 캐시한 거 영구 저장이 되면 좋겠다면? (물론 삭제 기능은 있고...)

에이 그런거라면 차라리 주 저장소를 Document DB로 바꾸는게 낫죠..

아 그렇긴 하네요... 근데, 개발자들이 NoSQL을 아주 단순히 쓰는 큰 이유는 RDBMS 처럼 관계형 데이터 처리에 익숙해서 key-value나 Document, grid 에 대한 처리에 난감해 한다는 거지요.  이 문제는 hibernate-ogm 으로 어떻게 해결하는지 향후 글을 써 보겠습니다.

우선 MongoDB 로도 가능하다는 보여 드리죠.

우선 제가 사용한 라이브러리는 spring-data-mongo, mongo-java-driver 입니다.

1. MongoCacheManager


2. MongoCache



MongoCacheManager 는 별 내용 없구요... MongCache는 Spring 의 MongoTemplate 를 적극 이용하여, 저장/검색을 수행하였습니다.
상세 내용은 Spring Data Mongo 매뉴얼을 보시면 되겠습니다.

3. MongoCacheConfiguration


너무 간단하죠? 나머지 테스트 코드는 앞 EhCache, Memcached 의 예와 똑같아서 생략하겠습니다.
MongoDB의 경우 Database를 지정해주고, 각 캐시명을 Collection 명으로 매핑합니다.
그럼 이만...

Spring 3.1 + Memcached 를 이용한 Cache 관리

전 글에 이어 Spring 3.1 캐시 저장소를 몇가지 늘려 봤습니다. Memcached, MongoDB, Couchbase 에 대해 만들어 봤습니다.
이번에는 Memcached 에 대해서만 설명해 보겠습니다.
Memcached 는 캐시들을 구분하는 개념이 없다는 게 하나의 특징이고, 분산 환경을 지원하므로, 직렬화/역직렬화를 통해 저장/로드 됩니다.
이것 때문에 당연히 In-Proc 인 ehcache 보다야 속도가 느리지만, HA 구성 시에는 캐시 서버로 좋은 선택이 될 수 있습니다.

그럼 먼저 MemcachedCacheManager 를 정의하면


과 같습니다.

실제 캐시에 데이터를 저장/로드하는 Cache 는 다음과 같습니다.



캐시 저장 시, 이미 있다면 update 되도록 set() 메소드를 사용합니다.

다음으로는 Spring 환경 설정을 보겠습니다. 뭐 특별한 것은 없고, MemcachedClient 를 생성해서 제공해 주면 됩니다.



마지막으로 테스트 코드는 ehcache 예와 같습니다.


어떻습니까? 캐시와 관련해서 개발자가 최소한의 설정만으로 캐시를 효과적으로 사용할 수 있게 되었습니다.
물론 다양한 캐시를 쓸 수 있어, 용도에 맞게 사용하면 더 좋을 듯 합니다.


2013년 3월 24일 일요일

Spring 3.1 + EhCache 를 이용하여 캐시 사용하기

Spring 3.1 이상부터 Annotation을 이용하여, Cache 를 아주 쉽게 사용할 수 있습니다.
데이터를 처리하는 함수에서 @Cacheable 이라는 annotation을 사용하여, 반환되는 데이터를 캐시에 저장한다고 지정하기만 하면 됩니다.

Spring 3.1 Caching and @Cacheable 와 같은 좋은 예제가 많으니 그걸 참고하셔도 됩니다.

저도 비슷하게 함 예제를 만들어 봤습니다.
우선 캐시할 정보를 관리하는 UserRepository 라는 클래스를 구현했습니다. 보시다시피 @Repository 입니다.




처음 getUser() 메소드를 호출하게 되면,  User 인스턴스가 생성되어 반환되면서, 캐시에 자동 저장되고, 두번째 호출서부터는 캐시로부터 읽어드립니다.

정말 편하죠? Cache 와 관련된 코드가 설정만으로 끝낼 수 있다니^^ 물론 Cache 무효화나 key에 따라 다른 결과는 다른 키로 저장하기, 조건에 따라 캐싱하기 등등 더 많은 기능이 있습니다.

위와 같이 Cache 사용하기 위해서는 다음과 같이 Spring Configuration 을 정의합니다.


보시다시피, EhCacheCacheManager 를 제공하는 Bean이 실제 쓰이는 CacheManager 입니다.

테스트는 Spring Configuration을 지정하고, UserRepository.getUser() 를 같은 값으로 두 번 호출하여, 두 번째가 캐시에서 읽어오는지 확인하면 됩니다.
(UserRepository에 보면 log에 쓰는 부분이 있죠? 두 번째에는 나타나지 않으면 됩니다.)


자 테스트 코드는 위와 같고, 마지막으로 ehcache  설정은 다음과 같습니다.



이 것을 응용해서 다른 Cache Provider 에 대해서도 작업을 하실 수 있을 것입니다. 요즘 가장 성능 좋은 것으로 사용되는 Redis 를 활용해도 되겠지요^^

hibernate-ogm configuration for spring framework

요즘 hibernate-ogm 을 제품에 적용하기 위해 공부하고 있습니다만, 아직 많은 활용이 안되나 봅니다. 개발 자료가 별로 없어, 소스와 테스트 코드를 분석하면서 공부하고 있습니다만...

역시 제 나름대로 테스트 환경부터 만들어서 공부하는 습관이 도움이 되네요...
그래서 제가 만든 환경에 대해 설명하고, 이 것을 바탕으로 hibernate-ogm을 제품에 쉽게 적용할 수 있도록 해 보겠습니다.

hibernate-ogm 도 hibernate 와 유사하게 환경설정을 합니다. 다만, hibernate 3.x 대의 Configuration을 이용하여 SessionFactory를 build 하는 것과 유사하게 SessionFactory를 빌드합니다. 즉 hibernate 4.x대와는 다르게 설정하네요.

또 한가지 확실하지는 않지만,  Configuration에서 Package 추가는 잘 안되고, annotationClass 는 제대로 되는군요...
=> 제가 잘못알고 알고 있었네요. package 추가 시에는 scan을 해줘야 하는데 그것은 새로 구현을 해야 하는 거더군요^^

우선 모든 Datastore (NoSql이라 그런지 Database 라 하지 않고 Datastore 라고 하는군요) 에 공통되는 부분을 구현한 GridDatastoreConfigBase.java 파일을 보면



public SessionFactory sessionFactory() {...} 는 아주 익숙한 코드지요? 단지 Configuration class가 hibernate 것이 아닌 hibernate-ogm의 OgmConfiguration을 사용한다는 것만 다릅니다.

아래의 getDatabaseName(), getMappedPackageNames(), getMappedEntities() 메소드는 각자 Datastore와 제품에 따라 재정의하면 됩니다.
그 밑에 getHibernateProperties() 와 getHibernateOgmProperties() 는 각각 Hibernate 설정과 Hibernate-Ogm 설정을 추가할 수 있습니다. 이 부분도 재정의를 통해 추가하시면 됩니다.

그럼 MongoDB를 사용하는 환경설정은? 위의 GridDataStoreConfigBase를 상속하여 몇가지 메소드를 재정의만 하면 됩니다.


MongoDB 만의 설정을 보면 database 명을 설정해줘야 하고, 엔티티의 저장 방식을 설정해주게
됩니다. AssociationStorage enum 값의 설명을 보면 ...


입니다. Entity 들을 전역 컬렉션에 저장, 지정한 컬렉션에 저장, 엔티티별로 저장과 같이 3가지 방식이 있습니다.

뭐 Lazy Initialization을 많이 사용하려면 엔티티별로 저장하고, 일반적으로는 컬렉션에 저장하는게 좋으리라 생각됩니다.

자 그럼 실제 테스트 시에 사용할 Configuration을 보면은


과 같습니다. DB명을 지정하고, 매핑된 엔티티를 지정해 주는 것으로 끝납니다^^
이제부터는 위의 Configuration을 이용하여 테스트 코드를 작성하여 테스트를 수행하면됩니다

hibernate-ogm은 현재까지 NoSQL을 단순 저장소로 밖에 활용 못한 것을 Object Grid 방식으로 사용할 수 있도록 한 차원 업그래이드된 방법을 제공합니다.
이를 통해 앞으로는 RDBMS 뿐 아니라 NoSQL도 특정 제품에 구애받지 않고 사용할 수 있었으면 합니다.



2013년 3월 19일 화요일

hibernate-validator 사용 시

Business Application 개발 시, DDD를 적용하는 것은 거의 표준이고, Domain Model 을 전 Layer에 걸쳐 사용하는 것이 대세입니다.
hibernate 를 사용하는 경우는 hibernate-validator, hibernate-search 등을 같이 사용하게 되면, 상당히 많은 부분에서 업무 로직 등을 손쉽게 구현할 수 있습니다.

특히 hibernate-validator 는 Model의 속성 값의 제약 조건을 annotation을 이용하여 손쉽게 정의할 수 있습니다.

@NotEmpty
public String getName() { ... }

이라 하면,  엔티티의 name 속성 값은 빈 문자열이면 안된다는 뜻입니다. DB에 insert, update 시에 위의 검사 조건으로 자동 검사가 가능합니다.

자세한 내용은

Hibernate Validator Reference 4.3.1 Html Single
Hibernate Validator Reference Pdf

을 보시는게 ...

기본 제공되는 부가 제약 조건으로는

@AssertFalse, @AssertTrue, @DecimalMax, @DecimalMin, @Digits(integer=,fraction=), @Future, @Max, @Min, @NotNull, @Null, @Past, @Pattern(regex=,flag=), @Size(min=,max=), @Valid
가 있습니다.


부가 제약 조건으로는

@CreditCardNumber, @Email, @Length(min=, max), @ModChceck, @NotBlank,  @NotEmpty, @Range(min,max), @SafeHtml, @ScriptAssert, @URL 등이 있습니다.

위의 Validation이 굳이 필요한가? DB에도 Constraint 를 정의할 수 있는데? 라고 한다면...

Validation은 다음과 같은 단계에 모두 필요합니다.
1. Presentation Layer 에서 입력 작업 시
2. Business Layer 또는 Service Layer 에서 Entity 작업 시
3. Data Access Layer 에서 DB에 insert, update 시

에 하게 되면 굳이 DB에서 작업이 필요없습니다.
그리고 DB는 되도록 부가 작업을 안하게 하는 것이 성능 상 더 좋습니다.

또 향후 저장소를 RDBMS가 아닌 NoSQL을 사용하고자 할 경우에는 hibernate-ogm 을 사용하게 되면 다른 것은 하나도 바꿀 필요 없고, 환경설정만 변경하면 됩니다^^

2013년 3월 17일 일요일

NoSQL 용 ORM인 hibernate-ogm을 소개합니다.

OOP 와 RDBMS 의 매핑을 위해 탄생한 ORM ( Object Relational Mapping ) 이 있다면, OOP 와 NoSQL 의 매핑을 위한 OGM ( Object Grid Mapping ) 이 탄생하는 것은 자연스러운 현상이겠죠^^
ORM의 대표 주자인 JBoss 의 hibernate 를 기반으로 OGM 용 라이브러리인 hibernate-ogm 이 있습니다. 현재 4.0.0 Beta 2 까지 나왔고, 공식 대상 NoSQL은 EhCache, Infinispan, MongoDB 이고, 비공식적으로는  Redis, HBase, Cassandra 도 지원 또는 개발 중입니다.

hibernate-ogm 의 장점 중에 또 한가지는 hibernate-search 도 결합하여, lucene의 인덱스 정보를 no-sql 에 저장이 가능하도록 했습니다. 이렇게되면, 검색 서비스도 분산 환경에서는 확실히 확장성을 보장해 주겠지요.

다음 발표자료를 보시면 좀 더 잘 아실 수 있을 겁니다.


Spring-data 에서도 NoSQL 을 위한 다양한 라이브러리가 있지만, 제가 hibernate 의 heavy user 이라서, no-sql을 사용할 때도 hibernate 를 그대로 사용할 수 있으면 좋겠다 싶었는데, 작년부터 알게되었지만, 이제사 제대로 사용하게 되었습니다.

혹시 관심있으신 분들도 한번 시도해보시기 바랍니다. No-SQL 에서 relation 관련 기존 관습을 타파하지 못해 적용하는데 실패하는 경우도 많고, 실전으로 사용하는데, 신뢰가 없을 때 pilot 으로 시도해 볼 수도 있을 겁니다.

한가지 아쉬운 점은 JBoss 가 너무 자기중심적으로 Infinispan 을 미는 게 확산에 걸림돌이 되지 않나 싶네요^^.
하지만 곧 7월에 책 (Pro Hibernate and MongoDB) 도 나오니, 좀 더 확산이 되지 않을까 싶네요.

2013년 3월 15일 금요일

Spring 을 이용한 hibernate 환경설정

진부한 내용일 수 있지만, Spring 을 이용해 hibernate 에 대한 환경 설정에 대한 정보가 대부분 단편적이거나, 하나의 DB에 대해서만 설명한 글이 대부분이라...
hibernate 가 여러 DB를 동시에 만족 시킬 수 있음을 강조하고, 솔루션을 만들 때 여러 DB에 대해 만족할 수 있도록 테스트를 쉽게 하기 위해 간단하게나마 hibernate 설정을 spring 의 @Configuration을 이용하여 제작해 보았습니다.

우선 모든 DB에 대해 공통적으로 적용되는 부분에 대해 다음과 같이 정의했습니다.


public SessionFactory sessionFactory() {...} 함수가 가장 중요하고, 나머지는 뭐 별로...
당연히 hibernate 설정 클래스이니까... ㅎㅎ
sessionFactory를 만드는데, 여러가지 필요한 설정들을 지정하게 하는데, 미리 정의된 부분도 있고, 사용자가 더 필요한 부분은 "setupSessionFactory(factoryBean)" 위임 메소드를 이용하여, 추가로 정의 할 수 있도록 했습니다.

그럼 대표적으로 사용하는 DB인 HSQL, MySQL, PostgreSQL 에 대한 기본 환경설정 클래스를 보겠습니다.

1. HSql 메모리 DB 사용 (단순 테스트시 유용)

2. MySQL

3. PostgreSql

4. PostgreSql with pgpool-II

과 같다.

아주 사소한 port 번호 같은 것은 기본 값을 사용했다.
뭐 각각 다른 것은 DB명, ConnectionString, Dialect 등이다. 별 차이 없지만, 이렇게 구조적으로  상속체계를 해 놓으면, 실전에서 아주 편리하다.

실제 사용하는 예는 HSql 과 PostgreSql 의 예를 들어보자.

1. HSql 메모리 DB를 이용한 환경 설정 (2nd 캐시도 적용됨)


2. PostgreSql 의 "HAccess" DB 를 이용한 환경 설정 (2nd Cache도 적용됨)

이 것으로 끝나는게 아니고, Application 용 환경설정에서는 다음과 같이 위의 두 가지 환경설정 Class 를 입맛에 따라 Import 해서 테스트를 수행하면 된다.

정말 쉽죠?

이제 실제 단위 테스트 클래스에서 AppConfig를 지정해서 테스트를 수행하시면 됩니다^^

ORM의 장점 중에 여러 DB에 대해 일관된 작업이 가능하므로, 솔루션을 만들때는 최선의 선택이라 생각하는지라, 위와 같은 설정으로 개발을 수행합니다. (비록 한가지 DB만을 대상으로 하는 시스템이라도... 향후 어떻게 될지 모르고, 코드 재활용성도 생각하고^^)

2013년 3월 12일 화요일

hibernate 가 identity column을 clustered index 로 만들지 않는 이유

오랜만에 글을 쓰네요...
요즘 프로젝트 문서 작성을 주로 하는 바람에 글을 쓸 밑천이 없었네요 ㅎㅎ
이런 얕은 내공이라구...

오늘은 그동안 궁금했던 "왜 SQL Server 는 primary key가 clustered index 인데, PostgreSQL, MySQL 등은 clustered index 가 아닌가?" 에 대해 그냥 RDBMS 마다 속 사정이 있겠지... 하고 넘어갔었는데, hibernate 로 매핑을 수행하던 도중에 혹시나 하는 마음에 구글링을 해 봤습니다...

이런 논의가 hibernate 에서도 진행되었었네요...

원문( https://hibernate.onjira.com/browse/HHH-3305 ) 을 보면, Clustered Index 자체가 성능이 좋긴 하고, SQL Server 는 Primary Key가 기본으로 Clustered Index 지만

1. 다른 DB들은  Primary Key가 Clustered Index 가 아니다.
2. 유지 관리에 애로점이 있다.
3. SQL Server 는 DBA 기술이 없는 작은 조직에 초점이 맞춰져있다.
4. Clustered Index 를 삭제하고자 할때에는 부가적인 작업이 필요하다.

흠 이런 이유 때문인지는 모르지만, SQL Server 는 hiberante mapping test 시에 association으 변경 될 때 drop 시 실패하는 경우가 다반사입니다. oracle, postgresql은 괜찮구요. 물론 drop cascade 를 지원하기 때문이기도 하구요...

그동안 습관적으로 Primary Key는 Clustered Index 여야만 해!!! 라는 고정관념을 깨게 되었습니다.

뭐 꼭 필요하다면, DBA 가 튜닝 단계에서 적용해주는게 합당하겠죠^^