[번역] Redis partitioning

데이터베이스/Nosql|2019. 3. 6. 22:12

파티셔닝 공부를 위해 아래 페이지의 내용을 번역하며 정리해봤다.

https://redis.io/topics/partitioning


Redis Partitioning: 여러 레디스 인스턴스로 데이터 분배하기


파티셔닝은 데이터를 여러 레디스 인스턴스로 분할하여 모든 인스턴스가 자기가 소유한 키의 집합들만 소유하도록 하는 프로세스이다. 먼저 파티셔닝 개념에 대해 설명하고 레디스 파티셔닝에 대한 대안을 소개한다.

파티셔닝이 효율적인 이유

레디스에서 파티셔닝을 하기는 다음 두개의 이점이 있다.
1. 하나의 컴퓨터로 메모리의 양이 제한되는 경우에 파티셔닝을 사용하여 더 큰 데이터베이스와 메모리를 가질 수 있다.
2. 여러 개의 코어와 여러 대의 컴퓨터에 연산 능력을 확장하고 네트워크 대역폭을 여러 대의 컴퓨터와 네트워크 어댑터로 확장할 수 있다.

기본 파티셔닝 방법 (range partitioning)

파티셔닝에는 여러 기준이 있다. Redis 인스턴스 R0, R1, R2, R3 그리고 많은 사용자를 대표하는 키인 user:1, user:2와 같은 존재한다고 가정해보자. 이때 해당 키들을 어느 인스턴스에 어떻게 넣어야 하는지에 대한 여러 방법을 가지고 있다. 다른말로 말하면 주어진 키들을 주어진 인스턴스에 어떻게 매핑 할것인지에 대한 여러 방법이 있다.

가장 간단한 방법으로 range partitoning이 있다. 이 방법은 특정 범위에 있는 데이터는 특정 인스턴스에 매핑시켜서 데이터를 분배한다. 예를 들면 1 ~ 10000 까지의 데이터는 R0, 10001 ~ 20000 까지는 R1 식으로 저장 할 수 있다. 이 방식은 어떤 범위에 키를 어느 인스턴스로 매핑할지에 대한 정리가 되어있는 테이블이 필요하다.

이 테이블은 관리가 필요하고 모든 번위에대한 정리가 되어있어야 한다. 그래서 매우 불편하여 다른 파티셔닝 기법을 사용하여 이 번거로움을 대체한다.

해시 파티셔닝 Hash Partitioning

이 방식은 키와 함께 동작하고 object_name:<id>형식으로 키를 만들어서 사용하지 않아도 된다. 동작방식은 간단하다. 우선 키 이름을 crc32 해시 함수를 이용해서 숫자로 변경한다. 예를 들면 foobar라는 키는 93024922로 변경한다. 그리고 인스터스 개수 만큼 % 연산을 진행한다. 만약 인스턴스가 4개라면 93024922 % 4는 2이기 때문에 2번째 인스턴스에 들어간다.

다른 파티셔닝 종류

몇몇의 레디스 클라이언트와 프록시로 부터 hash function을 향상시켜서 만든 파티셔닝으로 consistent hashing라고 불린다.

Client side 파티셔닝
- 클라이언트에서 직접적으로 키를 가지고 읽고 기록할 노드를 선택한다. 많은 레디스 클라이언트는 이 파티셔닝을 구현한다.

Proxy assisted 파티셔닝
- 레디스 클라이언트가 바로 레디스 인스턴스에 요청을 보내지 않고 프록시에게 전송한다.
이 프록시는 적절하게 설정된 파티셔닝 스키마 대로 레디스 인스턴스에 저장하고 클라이언트에게 응답한다. 레디스와 Memcached에 대표적으로 Twemproxy가 존재한다.

Query 라우팅
- 임의의 인스턴스로 전달된 쿼리가 올바른 노드로 리다이렉션 되는 것을 말한다. redis cluster는 클라이언트에 도움을 받아서 하이브리드 형태의 쿼리 라우팅을 구현한다.

여러 파티셔닝이 있지만 기본 베이스는 기폰 파티셔닝과 해시 파티셔닝에서 구현된것이기 때문에 이 두가지가 기본이다.

Data store or Cache?

레디스에서 파티셔닝은 개념적으로 데이터 스토어와 캐시로 사용할 때 동일하지만 사실 데이터스토어로써 파티셔닝을 사용할 때는 약간의 제약이 존재한다. 레디스가 데이터 스토어로 사용될 때 키는 항상 같은 레디스 인스턴스에 있어야한다. 하지만 레디스가 캐시로 사용될 때 주어진 노드를 사용할 수 없을 때 다른 노드를 사용한다고 해서 큰문제가 되지 않는다. 이 경우에는 인스턴스 맵을 변경하여 수정할 수 있다. 위에서 제시되었던 파티셔닝에서 기존에 가야할 노드가 사용불가능할 경우 다른 노드로 저장될 수 있다. 비슷하게 만약 새로운 노드가 추가되면 새로운 키의 일부는 새로운 노드에 저장될 수 있다.

정리된 컨셉은 다음과 같다.
- 레디스를 캐시로 사용할 경우 scaling up and down이 자유롭다.
- 레디스를 데이터 ㅈ장소로 써 사용할 경우에는 고정된 키-인스턴스 맵이 존재해야하고 인스턴수의 개수는 그렇게 크지 않게 고정되어 있어야 한다. 그렇지 않으면 인스턴스가 추가되거나 제거 될 때 인스턴스간에 키를 리밸런싱 할 수 있는 시스템이 필요하다. 현재는 redis cluster만 이 기능을 제공한다.


PreSharding

위에 본거와 같이 레디스를 캐시로써 사용하지 않는이상 파티셔닝에 단점이 있느 것을 확인 할 수 있다.

하지만 데이터 스토어는 매일 많이 사용된다. 오늘 10개의 레디스 인스턴스 노드를 사용한다고 해도 다음날 50개가 필요할 수도 있다. 그렇기 때문에 고정된 인스턴스로 키-인스턴스 맵으로 관리하는 방식으로는 데이터 스토어로써 레디스를 사용하는데 어려움이 있다.

레디스가 필요 리소스가 적기 때문에 이 문제에 대한 간단한 접근방법은 애초에 많이 생성하는 것 입니다. 만약 하나의 서버로 서비스를 시작한다면 하나의 서버안에서 파티셔닝을 통해 여러 레디스를 구동할 수 있다. 그래서 처음부터 32개 또는 64개의 인스턴스를 만들어서 충분하게 사용자들이 사용할 수 있도록 설계할 수 있다. 이러한 방식으로 인스턴스를 크게 늘리고 만약 데이터 저장소가 더 필요하고 레디스 서버가 더 필요하다면 간단하게 인스턴스를 다른 서버로 이동 시킬 수 있따. 만약 부가적인 서버가 추가된다면 레디스 인스턴스 반을 추가된 서버로 이동 시킬 수 있다.
Redis 복제를 사용하면 사용자를위한 중단 시간이 거의 없거나 전혀 없을 때 이동을 수행 할 수 있다.


레디스 파티셔닝 사용

이론을 공부했다. 이제 어떻게 사용해야하는지 보자.

Redis Cluster
redis cluster는 자동으로 샤딩을 하고 높은 가용성을 가지는것을 선호한다. 2015년 4월 1일 부터 redis cluster를 사용할 수 있다. redis cluster는 query routing과 client side 파티셔닝을 섞어놓은 방식으로 진행된다.

Twemproxy
Twemproxy는 memcached ASCII와 redis 프로토콜을 위해서 트위터에서 개발된 프록시 이다. 싱글스레드이고 C로 개발되어 전적으로 빠르다. 여러 레디스 인스턴스에서 자동으로 샤딩이 되는 것을 지원하며 하나의 인스턴스가 사용이 불가능하면 다른 인스턴스로 전환되는 것을 지원한다.


주의사항
http://www.zdnet.co.kr/view/?no=20131119174125
여기에 보면 주의사항이 나오는데 핵심은 redis의 경우 싱글 스레드로 돌아가기 때문에 작업이 오래 발생되는 keys나 flushall은 사용하지 말아라. 1만건 이하에 데이터를 조작하는 경우에는 사용해도 되는데 그 이상 사용하는 경우에는 주의하라는 뜻.

댓글()

파티셔닝의 정의와 종류 그리고 샤딩

데이터베이스|2018. 7. 13. 23:28

샤딩과 파티셔닝
DB 보안 회사를 다니고 있고 대규모의 서비스가 기본인 현 시대에 파티셔닝과 샤딩에 대해 많이 들었지만 자세히 알지는 못했다.

이번기회에 한번 정리를 해보자.

파티셔닝
파티셔닝은 퍼포먼스, availability, maintainablity를 목적으로 논리적인 데이터를 다수의 엔티티로 분할하는 행위를 뜻한다. 대부분의 DBMS에서 지원하지만 Mysql 5.1 미만에서는 지원하지 않는다. 샤딩 또한 이 파티셔닝의 한 종류이다.

수평 파티셔닝 (horizotal partitioning, Range Based Partitioning)
샤딩과 동일한 의미를 가지며 스키마를 다수의 복제본을 구성하고 각각의 샤드에 샤드키를 기준으로 데이터를 분리하는 것을 말한다. DBA가 데이터의 패턴과 저장공간을 잘 알고 샤드키를 선정하여 분할한다.




수직 파티셔닝 (vertical partiioning) - 샤딩
하나의 엔티티에 저장된 데이터의 양을 쪼개는것이 아닌 컬럼을 분할한다. (보안상의 이유나 포퍼먼스의 이유)
관계형 데이터베이스에서 대량의 데이터를 처리하기 위해서 데이터를 파티셔닝 하는 기술이다.  DBMS 레벨에서 데이터를 나누는 것이 아니고 데이터베이스 자체를 분할하는 방식으로 어플리케이션 레벨에서 구현해야한다.


Key or Hash Based Partitioning
엔티티를 해쉬함수에 넣어서 나오는 값을 이용해서 서버를 정하는 방식. (사용자의 ID가 숫자로만 이루어져 있는 경우에는 나머지 연산을 이용한다.)
주의 : 해시결과 데이터가 균등하게 분포되도록 해시함수를 정해야한다. (해시함수를 바꾸는 것은 거의 불가능에 가깝기에 균등하게 나눌 수 있는 해시함수 선정이 중요하다.)

Directory Based Partitioning
파티셔닝을 제공하는 특정 서비스를 만드는 것을 의미한다. DB와 cache를 적절히 조합해서 만들거나 샤드키를 조절하는 방법등 여러가지가 있다.




#샤딩시 고려사항

- 데이터 재분배
->  샤딩을 진행 한 DB의 물리적인 용량한계와 성능한계가 왔을 경우 적절하게 shard수를 scale-up 작업을 늘릴 수 있도록 설계해야한다. (확장고려)

- 샤딩으로부터 데이터 조인
-> 샤딩된 데이터베이스간에 조인이 불가능하기 때문에 어느정도의 데이터 중복은 감안해야 한다.

- 파티셔닝 잘 구현하기
-> 샤딩의 기준이되는 샤드키를 잘 정하거나 hash의 경우 함수를 잘 선택해야 한다.

- 샤드된 DBMS들의 트랜잭션 문제
-> XA와 같은 Global Transaction을 사용하면 샤딩된 데이터베이스간에 트랜잭션이 가능하나 성능저하의 문제가 있다.

- Global Unique Key
-> 샤딩에 경우 DBMS에서 제공하는 auto-increment를 사용하면 key가 중복될 가능성이 있기 때문에 application 레벨에서 key 생성을 담당해야 한다.

- 데이터 축소
-> Table 단위를 가능한 작게 만들자.


출처 : http://theeye.pe.kr/archives/1917
출처 : http://genesis8.tistory.com/21








댓글()

Java8 스트림을 이용한 데이터 추출

JAVA/Java 8|2018. 5. 31. 07:43

스트림에 있는  데이터를 List, String, Set 다양한 형태로 변경하여 추출   있다.

toArray
Stream.toArray Object[] 리턴한다.
 
올바른 타입의 배열을 원하는 경우 다음과 같이 배열 생성자를 전달한다.
String[] result = words.toArray(String[]::new);
 
Collect 메소드
- Collect : 종료 작업으로 인자로 받은 형태의 데이터 타입으로 결과물을 생성한다
- Collect 병렬화를 지원한다또한 공급자누산자결합자를 기본적인 파라미터로 받으며 이는 
  Collectors라는 클래스를 통해 간편하게 정의하여 사용할  있다.

1) List, set, String



1
2
3
4
5
6
7
Stream<String> data = Stream.of("dd", "aa", "cc");
        
// stream 데이터를 list로 변환
List<String> result = data.collect(Collectors.toList());
        
// stream 데이터를 set으로 추출
Set<String> setdata = data.collect(Collectors.toSet()); 
cs




스트림에 있는 모든 문자열들을 서로 연결해서 모으려고 하는 경우 다음과 같이 호출   있다.
 

문자 이어 붙히기


1
2
3
4
5
6
7
Stream<String> data = Stream.of("dd", "aa", "cc");
        
// 데이터 이어 붙히기
String temp = data.collect(Collectors.joining());
System.out.println(temp);
        
==> ddaacc 
cs




구분자 삽입하여 이어 붙히기

1
2
3
4
5
6
7
8
9
10
public static void main(String args[]) {
        
    Stream<String> data = Stream.of("dd""aa""cc");
        
    // 데이터 이어 붙히기
    String temp = data.collect(Collectors.joining("||"));
    System.out.println(temp);    
}
 
==> dd||aa||Cc
cs


그룹핑과 파티셔닝
그룹핑

 
Stream 들어있는 데이터 중에 성질이 같은 값들의 그룹을 만들어서 사용하고자  경우가 있을 것이다.
Stream collect 메소드의 구분자로 Collectors.groupingby 사용하며 기준은 Person dept 사용하여 그룹핑을 한다.




 다운스트림 컬렉터(downStream Collector)
 -> 그룹핑 결과를 List 반환하지 않고 특별히 기재한 방식으로 출력하도록 해주는 


1) set으로 출력




2) 분류된 데이터의 개수를 출력






파티셔닝
리턴되는 값이 boolean 분류 함수인 경우에는 groupingBy 대신 partitioningBy 사용하면 스트림 요소가 true, false 리턴하는 두개의 리스트로 구분된다.




댓글()

애플리케이션 확장 방법 스케일 큐브 (Scale Cube)

web/마이크로서비스|2018. 5. 27. 00:32

A애플리케이션을 확장하는 데 필요한 세 가지의 주요 접근방식이 있다.


크게 x, y, z 축으로 구분하여 설명한다.


먼저 

x축 방향의 확장은 애플리케이션을 복제해서 수평적으로 확장하는 것을 의미

y축 방향의 확장은 서로 다른 기능을 분리하는 것을 의미

z축 방향의 확장은 데이터 파티셔닝(Partitioning) 또는 샤딩(Sharding)을 의미



y축 방향의 확장이 일체형 애플리케이션에서 마이크로서비스를 적용하여 분리하는 것을 의미한다.

예를 들면, 항공사 예약에서 검색 500건당 예약 1건이 발생한다고 한다.


그럴경우 하나의 일체형 애플리케이션으로 만들경우 성능을 좋게 하기 보다는 두 개의 서비스를 분리하여 검색 서비스에 물리적은 리소스를 더 부여하고 예약에 상대적으로 낮게 부여 함으로써 효과적으로 애플리케이션을 분리할 수 있다.


댓글()