ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Cassandra 의 간략한 특징과 timestamp 에 대해
    기록해야 기억한다/OSS(Open Source Software) 2020. 12. 16. 15:15
    SMALL

    1. 안녕 Cassandra ?

    최근 업무를 진행하며 Cassandra 를 사용할 기회가 있었습니다. 나름 유명한 상태이지만 사용해본적이 없어서 여느 RDB 를 사용하듯이 사용하였는데 몇가지 문제가 있었습니다. 그중 하나가 바로 timestamp 값에 대한 핸들링이였고, 그에 대한 내용과 사용상 특징 몇가지를 정리하려 합니다.

     

     

    2. Cassandra 의 사용상 특징

    카산드라는 scalability와 high availability에 최적화된 대표적인 분산형 Data storage 라고 합니다. 자세한 내용은 알지도 못하고 그에 대해 다룰 글이 아니기에, 단순하게 사용상 특징 몇가지만 언급합니다.

     

    • RDB 와 같은 조건 쿼리 사용상 제약 : 분산되어 있는 Key 가 있을 경우 반드시 Key 순서에 맞추어 where 조건이 있어야 정상적인 조건 쿼리가 가능함
    • Update 시 PRIMARY KEY 는 갱신할 수 없음 - 단순한 제 생각으로는 분산형 스토리지이기에 그런게 아닐까 합니다.
    • Table 간의 Join 이나 Transaction 을 지원하지 않음
    • Paging 처리가 어려움
    • CQL(Cassandra Query Language) 를 지원하며 Generic SQL 과 비슷함(그렇다고 막사용하면..당연히 안됩니다.)
    • 분산되어 있는 노드들의 timezone 이 달라도 무관하다. <-- 이글의 주제입니다.

     

    3. Cassandra 의 Timestamp

    cassandra 의 timestamp 는 UNIX epoch (1970/01/01 00:00:00+00:00) 이후의 microseconds 로 인코딩된 값을 사용합니다. 이에 카산드라 timestamp 를 사용하는 클라이언트는 항상 UTC 로 간주하여 사용하여야합니다. pytz(파이썬 라이브러리) 문서에 따르면, "시간을 처리하는 방법 중 가장 선호하는 방법은 항상 UTC 로 작업하고 사람이 읽게되는 출력에 대한 내용만 현지 시간으로 변환하는 것"이라고 합니다. 이처럼 timestamp에 write 하는 모듈이나 read 하는 모듈모두 UTC 기준으로 시간을 작성/처리하여야 합니다. 만약 그걸 잊는다면!? 전혀 다른 시간에 대한 결과로 이어집니다.

     

    • cassandra timestamp 는 항상 UTC 이다.!!
    • cassandra 의 date, time 은 Python 의 표준 라이브러리의 datetime.date, datetime.time 과 매우 유사함

     

    4. timestamp 값의 조회

    위에서 설명한 이유로 select 시의 where 조건에서도 RDB 처럼 년월일시분초로 입력하면 결과가 나오지 않고 'Z' 또는 '+00:00' 을 붙혀서 timezone 을 지정하여야 한다.

     

    • 조회안되는 경우
      • select timestamp1 from table where timestamp1='2020-01-01 00:00:00.000' 
    • 정상적인 조회의 경우
      • select timestamp1 from table where timestamp1='2020-01-01 00:00:00.000Z
      • select timestamp1 from table where timestamp1='2020-01-01 00:00:00.000+00:00'

     

    5. java 에서의 cassandra

    "spring-data 는 시간형식 JSR301 스펙에 대한 컨버터들을 제공합니다."

     

    경험으로 spring-data 를 통해 cassandra 를 이용하였고, 그에 Entity 는 LocalDateTime 으로 정의하여 사용하고 있었습니다. 애석하게도.. UTC 같은 정보는 미리 확인하지 않았었고 그냥 RDB 사용하듯이 사용하는데 해당 문제가 확인되었습니다. (결론적으로는 write 하는쪽도 고려가 안되어 있었긴 한데..

     

    간단히 언급하자면 입력되어 있는 각 정보들을 Datagrip 같은 DB 툴로 확인하면 타임존정보는 노출되지 않기에 "아~~ 값이 자정이구나." 했고, 그 내용 그대로 조회되길 기대했지만..!! Cassandra 는 UTC, 나는 KST 의 시간이기에 당연히 9시간의 차이가 나는 정보가 넘어오는 상태였습니다.(기본적으로 spring-data 는 systemDefault 로 timezone을 지정합니다.)

     

    아시다시피 LocalDateTime 은 Timezone 정보를 정의하지 않습니다. 명확히 사용하려면 ZonedDateTime 혹은 java.time.Instant 를 사용하여야 합니다. cassandra 의 timestamp 는 datastax 에 따르면 integer, string 형식으로 처리되고 해당 형식에 맞는 codec 이나 컨버터가 있어야 기대했던 동작이 가능합니다. spring-data 에서는 org.springframework.data.convert.Jsr310Converters 를 통해 시간형식을 처리하고 정의되어 있지 않은 ZonedDateTime 등은 별도의 컨버터를 구현해야 합니다.

     

    6. 별도의 컨버터 정의(spring-boot)

    spring-boot(2.3) 기준으로 별도의 컨버터를 추가하려면 CassandraCustomConversions 을 정의해주면 됩니다.

    (spring-boot 가 아닌 경우는 AbstractCassandraConfiguration 을 상속받아 처리하셔야 할 것 같습니다.)

     

    @Configuration
    public class MyCustomConfig {
        @Bean
        public CassandraCustomConversions customConversions() {
            Set<Converter<?, ?>> converters = new HashSet<>();
            converters.add(MyCustomConverter.INSTANT);
            return new CassandraCustomConversions(converters);
        }
    
        @ReadingConverter
        public enum MyCustomConverter implements Converter<Instant, LocalDateTime> {
            INSTANT;
    
            @Override
            public LocalDateTime convert(Instant instant) {
                // 여기에서 필요한 변경사항을 적용하면 됩니다.
                return LocalDateTime.ofInstant(instant, ZoneOffset.KST);
            }
        }
    }

    읽어올때는 @ReadingConverter, 저장할때는 @WritingConverter 를 사용하며 해당 컨버터의 K, V 는 Entity 의 속성을 따라야 합니다. 위의 경우 Instant 가 cassandra 의 timestamp 이며, LocalDateTime 은 해당 테이블의 Entity 속성입니다.

     

    7. 정리

    • Cassandra 의 Timestamp 는 UTC 를 기준으로 한다.
    • 입력시에도 UTC 를 감안해서 입력해야하며 조회시에도 UTC 를 감안해서 조회해야한다.
    • 입력시 UTC 를 고려하지 않고 입력되어 있는 값이라면 조회시 별도의 Converter 를 이용해서 보정하여야한다.

     

    반응형
    LIST

    댓글

Designed by Tistory.