#8. NOSQL

게임 서버 프로그래밍/게임 서버 프로그래밍 교과서

2020. 2. 17. 16:06

8.NoSQL

NoSQL

1. 관계형 데이터베이스와 NoSQL
  • 관계형 데이터베이스의 부족한 점

    • 한 테이블에 저장된 레코드들은 모두 같은 형태의 필드를 가져야 한다

      • 로그 데이터를 한 테이블에 기록할 때는 불편하다
    • 테이블에 필드를 추가하는 경우

      • 기존에 쌓여 있던 수 많은 레코드들 모두에 필드를 다 추가해야한다
      • 추가된 필드 값이 모두 null이 되게 함으로써 문제를 해결할 수 있다
  • NoSQL 등장 배경

    • 레코드가 리스트나 배열이 아닌 트리나 구조체 형태를 갖출 수 있다면 어떨까?
2. 관계형 데이터베이스에서 확장성
  • 게임 서비스를 이용하는 유저가 어마어마하게 많을 때

    • 데이터 엑세스하는 양이 많아진다

      • 정보를 데이터베이스 여러 대에 나누어 저장
    • 수직 분산

      • 여러 테이블을 각각 여러 데이터베이스 컴퓨터에 나누는 것
      • 엑세스 되는 테이블이 기존 테이블들 보다 적다면 수평분산하는 것이 좋다
    • 수평분산

      • 테이블 하나를 데이터베이스 컴퓨터에 나누는 것
    • 샤드

      • 데이터베이스에서 각 컴퓨터가 큰 테이블 1개를 조각조각 가진 것
    • 수평 분할 후 데이터베이스 엑세스 방법

      • 해시 함수 사용

        • 문자열을 입력으로 받고 연산 후 얻은 정수 값을 샤드 넘버로 사용
      • 로케이터 DB 사용

        • 찾는 레코드가 어느 샤드에 저장되었는지를 담고 있는 별도의 테이블에 엑세스하는 방법
      • 로케이드 DB 사용법

        • 게임서버가 DB에 질의
        • 질의와 관련된 레코드의 위치를 어떤 DB(로케이터 DB)에 묻는다
        • 샤드위치 파악후 해당 샤드에서 레코드 엑세스
        • 결과를 서버에 반환
    • RDBMS에서는 데이터 일관성을 중요히 여겨 수평 분산을 이용한 스케일 아웃을 하면 처리속도 측면에서 문제가 생긴다

    • 수평 분산은 기기 두대 이상에 나누어 저장된다. 데이터는 어떤 기기에 저장되고, 그 데이터가 어디에 있는지 가리키는 데이터는 또다른 기기에 저장된다

    • 분산락

      • 기기 둘 이상에 걸쳐 저장된 데이터를 엑세스 하는 동안 다른 스레드나 프로세스에서 엑세스를 블로킹 시켜주는 것
      • 기기 두 대 이상에 걸쳐 발견되어야 하는 데이터는 내부적으로 분산 락으로 보호되면서 엑세스 된다. 이로써 일관성을 지킬 수 있다
    • 데이터베이스 샤드가 많을수록 분산 처리 효과는 퇴색한다

      • 이는 RDBMS의 결점이아니라 일관성을 중요하게여기는 RDBMS의 특징
      • 일관성 원자성이 필요한 것은 맞지만 효율성이 떨어진다
    • 일관성과 원자성을 포기한다면?

      • 락이 줄어들면서 수평 분산 효과를 제대로 볼 수 있다
      • 엑세스하는 데이터가 항상 같은 결과를 입출력하지 않는다는 결과가 발생
      • 락에 따른 처리 성능 하락이 발생하지 않는다
  • 관계형 데이터베이스에서 고가용성

    • 고가용성

      하드웨어 고장 또는 다른 이유로 서버기기가 정상 작동을 하지 않을 때도 사용자 입장에서는 서비스가 지속되는 상태를 유지하는 것

    • 장애극복

      고가용성을 위한 기법중 하나

      • 레코드의 상시 백업

        • DB1에 있는 레코드를 DB2에 항상 백업, 즉 미러링 복제를 수행
        • DB1 = 액티브 or 마스터 , DB2 = 패시브 or 슬레이브
      • 다중화 or 이중화

        • 같은 데이터가 DB1과 DB2에 모두 있게 하는 것
    • RDBMS는 일관성을 중시함으로 데이터를 변경할 때 액티브와 패시브를 모두 변경한 후에야

      '처리 완료'를 선언

    • 가용성을 높이고자 성능을 희생하는것

    • 슬레이브가 많을수록 고가용성은 강력해진다

      • 슬레이브의 변경 전파 과정을 건너 뛰고 서버에 응답함으로서 처리속도를 높일 수 있다

      • 단 마스터와 슬레이브는 항상 같은 상태가 아니고 일시적으로 옛 데이터를 가질수 있다

        • 스테일 데이터

          최신이 아닌 데이터, 일관성이 깨진다

    • ACID 에서 C,I를 어느정도 포기하면 만족스러운 수준의 스케일 아웃과 고가용성 확보 가능

    • BASE

      • 기본적으로 가용성이라는 뜻
      • 데이터 상태가 유연하다
      • 결과적 일관성을 가진다
      • 일시적으로 데이터 일관성이 깨지지만, 언젠가는 일관성을 다시 구축한다
  • 요약

    구분관계형 데이터베이스NoSQL
    레코드 구조테이블 안의 모든 레코드가 동일한 데이터 구조(필드)를 가져야 한다.컬렉션 안의 모든 도큐먼트가 서로 다른 데이터 구조(트리)를 가져도 된다
    중요하게 여기는 것데이터의 원자성과 일관성을 중요하게 여긴다.데이터의 가용성(데이터 엑세스 요청을 신속하게 응답)과 수평 확장성을 중요하게 여긴다
    질의 기능질의에서 할 수 있는 기능이 풍부하여 문법이 표준화되어 있다.질의 기능이 상대적으로 적고 표준이 없다.
4. JSON
  • 데이터 트리를 문자열로 표현한 것
// {}는 객체를 의미, 앞의 "a" 는 key , : 는 is 1은 value에 해당
ex1) {"a" : 1}
// 문자열을 value로 쓸 때 큰따옴표 사용
ex2) 
{
	"a" : 1,
    "b" : "x",
    "c" : 100
}
// 객체안에 객체 정의 가능, 배열은 []로 표시
ex3)
{
    "a" :1,
    "b" : "x",
    "c" : 100,
    "d" : {"x" :50, "y" : "qp"},
    "e" : [99,88,77]
}
5. MongoDB
RDBMSMongoDB
DB 인스턴스DB 인스턴스
테이블컬렉션
레코드도큐먼트
6. MongoDB 데이터 엑세스
  • 생성/읽기/업데이트/삭제
//컬렉션과 도큐먼트 만들기
db.<COLLNAME>.insert(<OBJECT>)
ex)
db.coll1.insert({"a" :1 })

//읽기
db.<COLLNAME>.find(<COND>)
ex1)
db.coll1.find()
ex2) // gt는 greater , key가 a인 것 중에 1보다 큰 value를 찾음
db.coll1.find({"a" : {$gt : 1}})
ex3)_id 속성은 보여주지 말고 a 속성은 보여주기
db.coll1.find({},{"_id" :0 , "a" : 1})

//업데이트
db.<COLLNAME>.update($set:{K:V})
ex)
db.coll1.update({"a":1}, {$set:{"a":5}})

//지우기
db.<COLLNAME>.remove({K:V})
ex)a인 도큐먼트에서 값이 3인 것을 제거
db.coll1.remove({"a" : 3})

7. MongoDB 수평확장
  • 서버 쪽에서 총 처리 가능량을 올리기위해 사용

  • 서버 쪽의 기기 대수를 늘려서 문제를 해결

  • 수평 확장을 샤딩 혹은 파티셔닝이라고 한다

  • 샤드 클러스트 구성

    • ConfigDB

      MongoDB 샤드 클러스트에 관한 정보를 담고 있음

    • APP

      게임 서버

    • mongos

      APP과 MongoDB의 HUB

    • Shard 1,2,3...

      분산된 데이터베이스

    • 특징

      • 각 샤드는 샤드 키로 구분되는 도큐먼트를 분배해서 가진다

      • 샤드 키가 없는 질의 명령을 실행하면, mongos는 모든 샤드에 질의 명령을 던지는

        브로드캐스트 기법으로 실행. 성능이 큰 폭으로 떨어지므로 주의

      • 모든 샤드 안의 도큐먼트는 같은 샤드 키를 갖는 것이 둘 이상 있어서는 안된다.

      • ConfigDB가 죽으면 모든 샤드도 사용할 수 없다

      • ConfigDB는 필수적으로 다중화(이중화) 해야함