- 문제:

https://www.acmicpc.net/problem/16112

 

16112번: 5차 전직

메이플스토리 뉴비 키파가 드디어 레벨 200을 달성하고 5차 전직이라는 시스템을 이용해 캐릭터를 더욱 강력하게 만들려고 합니다. 5차 전직을 하려면 먼저 퀘스트를 통해 아케인스톤이라는 아

www.acmicpc.net

 

(1/10) 문제 이해하는데도 오래걸려서 포기하려고 했던 문제,, 2번 정도 보고 완벽히 아니고 대충 이해가 갔다! 

 

(1/11) 이해 완료~

 

- 코드: 

정답 코드 중에 파이썬이 없어서 자바코드로 먼저 이해했다.

 

<코드 이해 돕기 위한 설명>

100 200 300으로 정렬한 뒤에 1번 퀘스트를 진행하면 경험치에서 100을 빼주고, 1번을 진행한 상태니까 100을 어딘가에 한번 더해줄 수 있다.(활성화 된 스톤이 1개니까) 그다음 2번 퀘스트를 진행하면 경험치에서 200을 빼주고, 200만큼을 어딘가에 두번 더해줄 수 있다. (활성화 된 스톤이 2개니까) 이제 3번 퀘스트를 진행하면 경험치를 빼줄 필요 없이 300을 어딘가에 두번 더해주면 된다.

 

< 내가 이해한 코드와 문제 설명>

"예를 들어서 2,3 번째 아케인스톤이 활성화되어있고(2개가 활성화 되어있네! 그럼 해당 퀘스트를 제외하고 다른 아케인스톤에 해당 퀘스트의 경험치를 2번 뿌릴 수 있음) 첫번째 퀘스트를 진행했을 경우, 첫번째 아케인스톤을 획득하고 2,3번째 아케인스톤에 첫번째 퀘스트의 경험치가 쌓이고 첫번째 아케인스톤 경험치는 0이 된다."

즉, 진행한 퀘스트에 따른 아케인스톤 경험치가 0이 되므로 감소되는 경험치를 최소화하기 위해서는 오름차순으로 정렬해주는 것이 맞다. 퀘스트별 아케인스톤 경험치는 다른 아케인스톤에 본인 경험치를 줄 수가 있는데 활성화 개수에 따라 몇번 줄 수 있는지 달라진다. 그리고 경험치를 주면 본인이 가지고 있던 경험치는 0이 되게한다.

 

import java.util.Arrays;
import java.util.Scanner;

public class TemplateA {
	public static void main(String[] args){
		Scanner scan = new Scanner(System.in);
		int quest = scan.nextInt();	
		int activeS = scan.nextInt();
		
		int [] arr = new int [quest];
		
		for(int i = 0; i < quest; i++) {
			arr[i] = scan.nextInt();
		}
		
		Arrays.sort(arr);
		//오름차순으로 정렬해주어 최대 아케인스톤이 활성화 전까지
		//감소되는 경험치를 최소화한다. 
		
		int count = 0;
		//count는 최대 활성 아케인스톤 값까지 증가할 변수
		int exp  = 0;
		//최대 경험치가 들어갈 변수
		for(int i = 0; i < quest; i++) {
			if(count < activeS) {
				count ++;
				//최대 아케인 스톤값이 될때까지 하나씩 더해줌
				exp -= arr[i];				
				//최대 아케인 스톤 값이 되기 전까지는 하나의 경험치가 사라지게
				//됨으로 그 아케인 스톤의 경험치를 총경험치에서 빼줌
				
			}
			exp += (arr[i] * count);
			//이후 활성화된 아케인 스톤의 수와 경험치를 곱해줌
		}
	
		System.out.println(exp);
}
  
	}

- 코드 이해 후 파이썬으로 구현

n, act = map(int, input().split())

k = list(map(int, input().split()))
k.sort()  # 감소되는 경험치 최소화

cnt, exp = 0, 0
for i in range(n):
    if cnt< act:
        cnt+=1
        exp -= k[i]
    exp += k[i] * cnt
print(exp)

   

❤문제

유형: DP

https://www.acmicpc.net/problem/2775

 

백준 2775번 파이썬 풀이: 부녀회장이 될테야

백준 2775번 부녀회장이 될테야 알고리즘 분류: 수학, 조합론 링크: https://www.acmicpc.net/problem/2775 2775번: 부녀회장이 될테야 첫 번째 줄에 Test case의 수 T가 주어진다. 그리고 각각의 케이스마다 입력

yoonsang-it.tistory.com

❤코드

t = int(input())

num = 0
for _ in range(t):
    k = int(input())
    n = int(input())
    k0 = [x for x in range(1,n+1)]
    for a in range(k):
        for b in range(1,n):
            k0[b] += k0[b-1]
    print(k0[-1])

상향식으로 풀었당 - 배열에 계속 저장하면서 올라가도록

다이나믹 프로그래밍: 하나의 문제를 단 한번만 풀도록 하는 알고리즘

ex) 피보나치 수열

 

어떨 때 사용? 

1. 큰 문제를 작은 문제로 나눌 수 있을 때 - 크고 어려운 문제가 있으면 그것을 먼저 잘게 나누어서 해결한 뒤 처리

     -> 이 과정에서 메모이제이션(memoization) 사용해야함: 이미 계산한 결과를 배열에 저장

2. 작은 문제로부터 구한 결괏값을 큰 문제에서도 활용 가능

 

2가지 문제 풀이 방식

1. 상향식(바텀 업) 방식: 가장 작은 문제의 답부터 찾아가는 방식, 반복문 사용

2. 하향식(탑 다운) 방식: 가장 큰 문제부터 시작하여 작은 문제 순으로 답을 찾아가는 방식, 재귀 함수 활용

 

1. 상향식(바텀 업) 방식

# 계산된 결과를 memoization 하기 위해 리스트 초기화
d = [0] * 100

d[0] = 1 # a_1 = 1
d[1] = 1 # a_2 = 1

# 바텀 업 방식: 반복문 활용
for i in range(3, n+1):
    d[i] = d[i-1] + d[i-2]

n = 99
print("fibo({}): {}".format(n, fibo(n)))

2. 하향식(탑 다운) 방식

# 계산된 결과를 memoization 하기 위해 리스트 초기화
d = [0] * 100

# 탑 다운 다이나믹 프로그래밍 기법과 재귀 함수를 활용한 피보나치 수열 구현
def fibo (x):
    # 종료 조건 (전달인자가 1 또는 2일 때 1을 반환)
    if x == 1 or x == 2:
        return 1
    
    # 계산된 결괏값이 존재할 경우 해당 결과값 반환
    if d[x] != 0:
        return d[x]
        
    # 계산된 결괏값이 존재하지 않을 경우 피보나치 수열의 결과를 반환
    d[x] = fibo(x-1) + fibo(x-2)
    return d[x]

n = 99
print("fibo({}): {}".format(n, fibo(n)))

 

참고:[알고리즘] 다이나믹 프로그래밍(DP)에 대해 알아보자! (+Python 구현) (tistory.com)

 

- 문제: (1.3일)

https://www.acmicpc.net/problem/1463

 

1463번: 1로 만들기

첫째 줄에 1보다 크거나 같고, 106보다 작거나 같은 정수 N이 주어진다.

www.acmicpc.net

- 코드: DP문제는 처음이라,, 되는 확률들의 횟수를 다 따로 저장해서 비교하는 방식으로 해야한다. 머릿속으로는 생각했는데 어떻게 해야할지 아예 감이 안잡혔다ㅠㅠ 상향식 하향식 방식이 있는데 상향식이 더 코드는 이해하기 쉬웠다.  DP 알고리즘에 대해서 따로 정리하기! 

n = int(input())
cnt = 0
while n>0:
    if n%3==0:
        n = n//3
        cnt+=1
        if n==1:
            break
        if n%2==0:
            n = n//2
            cnt+=1
    if n%2==0:
        n = n//2
        cnt+=1
        if n==1:
            break
        if n%3==0:
            n = n//3
            cnt+=1
    n = n-1
    cnt +=1
print(cnt)

- 정답 코드:

n = int(input())
d = [0] * (n + 1)	## d에 계산된 값을 저장해둔다. n + 1이라고 한 이유는, 1번째 수는 사실 d[1]이 아니고 d[2]이기 때문에, 계산하기 편하게 d[1]을 1번째 인 것 처럼 만들어준다.

print(d)
for i in range(2, n + 1): #11
## 여기서 왜 if 1빼는 방법, 2 나누기, 3 나누기 동등하게 하지 않고 처음에 1을 빼고 시작하는지 의아해 할 수 있다.
## 1을 빼고 시작하는 이유는 다음에 계산할 나누기가 1을 뺀 값보다 작거나 큼에 따라 어차피 교체되기 때문이다.
## 즉 셋 다 시도하는 방법이 맞다.
## 여기서 if elif else를 사용하면 안된다. if만 이용해야 세 연산을 다 거칠 수 있다, 가끔 if continue, else continue를 쓰는 분도 계신데, 난 이게 편한듯.
    d[i] = d[i - 1] + 1
    print(d[i])
    if i % 3 == 0:
        d[i] = min(d[i], d[i // 3] + 1)	## 1을 더하는 것은 d는 결과가 아닌 계산한 횟수를 저장하는 것 이기 때문이다. d[i]에는 더하지 않는 이유는 이미 1을 뺄 때 1을 더해준 이력이 있기 때문이다.
        print(d)
    if i % 2 == 0:
        d[i] = min(d[i], d[i // 2] + 1)
        print(d)
print(d[n])

- 유형: 그래프 문제 -> DFS(깊이 우선 탐색)/BFS(너비 우선 탐색)

   - DFS: 최대한 깊이 내려간 뒤, 더이상 깊이 갈 곳이 없을 경우 옆으로 이동/ BFS 보다 느림

   - BFS: 최대한 넓게 이동한 다음, 더 이상 갈 수 없을 때 아래로 이동

 

* DFS, BFS은 특징에 따라 사용에 더 적합한 문제 유형들이 있습니다.

1) 그래프의 모든 정점을 방문하는 것이 주요한 문제

단순히 모든 정점을 방문하는 것이 중요한 문제의 경우 DFS, BFS 두 가지 방법 중 어느 것을 사용하셔도 상관없습니다.

둘 중 편한 것을 사용하시면 됩니다.

2) 경로의 특징을 저장해둬야 하는 문제

예를 들면 각 정점에 숫자가 적혀있고 a부터 b까지 가는 경로를 구하는데 경로에 같은 숫자가 있으면 안 된다는 문제 등, 각각의 경로마다 특징을 저장해둬야 할 때는 DFS를 사용합니다. (BFS는 경로의 특징을 가지지 못합니다)

 

3) 최단거리 구해야 하는 문제

미로 찾기 등 최단거리를 구해야 할 경우, BFS가 유리합니다.

왜냐하면 깊이 우선 탐색으로 경로를 검색할 경우 처음으로 발견되는 해답이 최단거리가 아닐 수 있지만, 
너비 우선 탐색으로 현재 노드에서 가까운 곳부터 찾기 때문에경로를 탐색 시 먼저 찾아지는 해답이 곧 최단거리기 때문입니다.

 

이밖에도 

- 검색 대상 그래프가 정말 크다면 DFS를 고려
- 검색대상의 규모가 크지 않고, 검색 시작 지점으로부터 원하는 대상이 별로 멀지 않다면 BFS

- 문제:

  - n개의 노드수를 입력하고 첫번째 1노드를 제외한 2~ n개의 부모노드를 순서대로 나열하는 문제.

     https://www.acmicpc.net/problem/11725

- 풀이:

- 문제 해결 방식:  DFS,  재귀 함수

-> 일단 dfs/bfs의 개념부터 알아가느라 정답을 먼저 보고 고민을 해봤다. 문제는 이해가 갔는데 정답 코드를 봐도 왜 저렇게 배열을 만드는지 이해가 안간다.. (12.28) -> 이해 완료!

import pandas as pd
import sys

n = int(input())

tree = [[] for _ in range(n+1)] # 빈 배열 생성
parent = [-1]*(n+1)
for _ in range(n-1):
    a, b = map(int, input().split())
    tree[a].append(b)
    tree[b].append(a)
    
def dfs(n):
    for i in tree[n]:
        if parent[i] == -1:
            parent[i] = n
            dfs(i)
dfs(1)
for i in range(2, n+1):
    print(parent[i])

--> tree의 배열을 보면 이런식으로 결과가 나오는데 각 노드 순서별로 어떤 노드와 연결되어있는지 나타내는 배열이다!

예) 0번 노드는 공백, 1번 노드와 연결된 노드는 4,6, 2번 노드와  연결된 노드는 2, 3번 노드와 연결된 노드는 5,6

 

* 문제 해결법: dfs 문제의 트리 노드 문제는 아예 함수 공식을 외우자! 

1. mongoDB 서버 구축

2. docker mongoDB 볼륨 경로 생성 및 실행 

- 사용자 권한으로 들어가기

$ sudo su

- 원하는 디렉토리에 도커 볼륨 마운트 및 mongo-container 생성 후 연동

$ docker run --name mongodb-container -v {사용자 경로}:/data/db -d -p {포트번호}:{포트번호} mongo

3. mongoDB 접속

$ sudo docker exec -it mongodb-container bash
$ mongo

4. mongoDB collection 생성하기

- DB 컬렉션(table) 생성 후 생성 잘 되었는지 컬렉션 목록 확인하기

$ db.createCollection("ceragem")
$ show collections;

- 데이터베이스 목록 확인 후 원하는 디비 사용하기

$ show databases;
$ use admin

- 디비 유저 생성(*필수) 후 mongo와 도커 exit하기 

    - user, pwd는 사용자가 원하는대로 설정해주세요~!

$ db.createUser({ user: 'hello', pwd: 'hello1234', roles: ['root'] })

$ exit  
$ exit

4. .gz 파일 올리기(여기에선 .gz파일을 올렸지만 사용자가 원하는 파일 올리면 됨)

- 앞서 설정했었던 디비의 user, pwd {}란에 입력해주기

- {지정할 경로}에 파일 경로와 이름 넣어주기  

$ sudo docker exec -i mongodb-container sh -c 'mongorestore --archive --gzip -v --username {사용자이름} --password {비밀번호}' < {지정할 경로}/어쩌고.gz

'Language & OS > DB' 카테고리의 다른 글

DBeaver 설치 및 사용방법  (0) 2024.05.20
minio  (0) 2024.02.22
SQL과 NoSQL의 차이  (0) 2023.01.13
[DB] mongoDB 기본 개념  (1) 2022.11.18
이번에는 MongoDB에 대한 기본 개념에 대해서 알아보겠습니다. 이번 시간에는 각 주제별 자세한 내용을 다루기보다는 mongoDB에 대한 전체적인 개념을 파악하는데 초점을 두었습니다. 😊

 

1. mongoDB 소개

  • mongoDB는 도큐먼트(document) 지향적인 데이터베이스입니다.
  • 도큐먼트(document)는 아래와 그림과 같이 field:value 형식으로 구성된 데이터 구조입니다. vaule에는 문자열, 숫자, 날짜, 배열, 다른 도큐먼트를 저장하는 것도 가능합니다.
https://docs.mongodb.com/manual/introduction/#document-database 그림 참조
  • mongoDB는 스키마를 고정하지 않은 형태(Schema-less 구조)입니다.이러한 특징으로 필드 추가 및 제거가 간편합니다.
  • 분산 확장이 간단합니다.
  • 아래의 그림과 같이 샤딩 시스템(샤딩 : 샤드(분산하는 각각의 장비)에 걸쳐 있는 데이터를 분할하는 처리)을 이용하면 분산 확장이 간단합니다.
Mongo DB sharding

 


2. mongoDB 개념

 mongoDB에서는 JSON, BSON 타입 모두 사용합니다. BSON 타입이 무엇인지 어디서 사용되는 건지 알아봅시다. 더 자세한 내용을 확인하고 싶으면 mongoDB 사이트에서 확인해 주세요.

2-1. JSON 타입과 BSON 타입

JSON 타입

 mongoDB는 Document 형태로 데이터를 저장합니다. 이러한 표현 방법을 java script 형식의 오브젝트 표기법 즉, JSON 타입이라고 말합니다. 이 데이터 타입은 사람이 읽고 쓰기 쉽고, 기계가 파싱하고 생성하기 쉽다는 장점이 있습니다.

 

BSON 타입

 mongoDB에서는 모든 데이터는 반드시 JSON 타입으로 표현됩니다. 하지만, 데이터베이스 내에서 저장될 때는 BSON 타입의 바이너리 형태의 데이터로 반환되어 저장합니다.

 BSON 타입은 Binary JSON의 약어로, JSON 문서를 바이너리로 인코딩한 포맷이다. JSON과 비교하여 BSON은 스토리지 공간과 스캔 속도 모두에서 효율적으로 설계되어 있다는 장점이 있습니다.

2-2. mongoDB 용어 설명

 mongoDB에서 사용하는 용어에 대해 알아봅시다. 이를 쉽게 이해하기 위해 RDBMS 용어와 비교해 봅시다. 아래 표와 같이 mongoDB에서는 table를 collection(컬렉션)이라 하고, row(행)을 Document(도큐먼트), db server를 mongod, db client를 mongo라고 부릅니다.

RDBMS Mongo DB
Database Database
Table Collection
Row Document
Index Index
DB server Mongod
DB client mongo

 


3. 기본 쿼리

이제 mongoDB 기본적으로 사용되는 CRUD 쿼리에 대해 살펴보도록 하겠습니다. 아래 자료는 mongoDB documentation를 참고하였습니다.

3-1. C(Create) - insert

insert 명령어를 이용하여 json 형식 데이터를 삽입합니다. 아래 그림과 같이 field:value 형식으로 되어있는 것을 확인할 수 있습니다.

 >  db.users.insertOne({"name":"sue", "age":26, "status":"pending"})

 

3-2. R(Read) - find

find 명령어 데이터를 검색하려고 합니다. query criteria에는 조건문을 입력하는 것이고, 그 뒤 projection에는 출력하고자 하는 필드에 1을 넣어 줍니다.

 > db.users.find({age:{$gt:18}},{name:1, address:1}).limit(5) 

 

3-3. U(update) - update

특정 조건을 update 할 때 사용됩니다. update filter에 업데이트하고자 하는 도큐먼트 조건을 넣어줍니다. update action에는 업데이트할 것을 넣어줍니다.

 

 > db.users.updateMany( {age:{$gt:18}}, {$set: {status:"reject"}} )

 

3-4. D(Delete) - delete

특정 도큐먼트를 삭제할 때 사용됩니다. delete filter에 삭제할 조건을 넣어줍니다.

 

 > db.users.deleteMany( {status: "reject"} )

4. index

 index에 대해 간단하게 알아보고 넘어가겠습니다. 자세한 내용은 MongoDB index 개념과 indexing 전략 내용을 확인해 주세요.  

4-1. Index 란?

 Query를 더욱 효율적으로 할 수 있도록 documents에 기준(key)을 정해 정렬된 목록을 생성하는 것입니다. 인덱스가 없다면, Mongo DB는 full collection scan(collection의 데이터를 처음부터 끝까지 하나하나 조회) 방식으로 스캔하게 됩니다. Hash index를 제외하고 Mongo DB는 B-Tree 구조로 Indexing으로 되어 있습니다.

 

4-2. 기본 Index

  • 모든 Mongo DB의 컬렉션은 기본적으로 _id 필드에 인덱스가 존재합니다.
  • 컬렉션 생성 시 _id 필드를 따로 지정하지 않으면 mongod 드라이버가 자동으로 _id 필드 값을 ObjectId로 설정됩니다.
  • _id 인덱스는 unique 하고 이는 MongoDB client가 같은 _id를 가진 문서를 중복적으로 추가하는 것을 방지합니다.

 

4-3. Index 생성, 조회, 제거하기

생성하기

createIndex() 메소드 사용하여 생성합니다. 값을 1로 하면 오름차순, -1로 하면 내림차순 정렬됩니다.

> db.collection.createIndex( { key: 1 } ) 

조회하기

> db.COLLECTION.getIndexes()  

제거하기

> db.COLLECTION.dropIndex( { KEY: 1 } )  

 


5. data type

mongodb data type은 아래 사진과 같이 여러 타입이 존재합니다. 많이 사용되는 데이터 타입만 확인하고 넘어가겠습니다.

 

 

  • ObjectId: 12 bytes로 구성된 하나의 document에 유일한 ObjectId가 자동으로 부여됩니다.
  • String: 문자열로 어떠한 UTF-8 문자열도 표현 가능합니다.
  • Date: UNIX 시간 형식으로 저장됩니다. 새로운 Date 객체를 생성할 때는 항상 Date가 아닌 new Date 호출, Date 호출 시 날짜 객체가 아닌 날짜의 문자열 표현 반환합니다.
    • 예) {“x” : new Date()}
    • 기본값) ISODate("1970-01-011T09:00:00.000**+09:00**") : 9시간을 더하면 한국/서울 시간으로 변경.
  • Array: 배열을 표현합니다.
  • Boolen: true, flase 값에 사용합니다.
  • integer: 정수를 저장할 때 사용합니다.
  • double: 부동 소수점을 저장할 때 사용합니다.

6. 샤딩(Sharding)

6-1. 샤딩이란

 빅데이터를 저장하기 위해서는 한 대의 서버에 저장하는 것은 불가능합니다. 초당 엄청난 양의 데이터를 insert 하면 Write scaling 문제가 발생하여 서비스 성능 저하를 유발합니다. 따라서 이를 해결하기 위해 여러 대의 서버에 분산 처리하는 것이 이상적입니다.

 샤딩을 하게 되면 여러 대의 독립된 프로세스가 병렬로 작업을 동시에 수행하여 이상적으로 빠른 처리 성능을 보장받습니다. 또 하나의 서버에서 관리를 하면 유실 시 큰 손실이 따르게 됩니다. 분산 처리를 하면 이러한 위험 요소로부터 안전하게 데이터를 저장, 관리할 수 있습니다.

 

6-2. 샤딩 시스템 구조

샤딩 시스템 구조 

mongos 라우터

 mongos 프로세스는 중계자 계층으로 응용 계층(client)에서 전달된 질의를 분석하여 적절한 샤드에 보내는 라우터 역할을 합니다. 또한 mongos는 각 서버에서 어떤 일을 하는지 client가 모르게 해주는 역할을 합니다.

 

shard

 Shard는 데이터를 하나 혹은 그 이상의 샤드에 걸쳐 분산 저장한다. 각 샤드는 전체 데이터의 일부를 저장한다. 그리고 각 샤드는 그림과 같이 리플리카 셋으로 구성되어 있습니다.

 

config servers

 config servers는 샤드 시스템에 대한 설정 세팅과 메타 데이터를 저장/관리합니다. 다시 말하면 config servs는 각 샤드 서버에 어떤 데이터가 어떤 식으로 분산 저장되어 있는지에 대한 meta 데이터가 저장되어 있습니다. mongoDB 3.4에서는 config servers도 리플리카셋으로 구성되어야 한다고 합니다.

 

6-3. shard key 구성

 shard key 구성 방법은 mongoDB 샤딩 시스템 구축할 때 가장 중요합니다. 이는 여러 개의 샤드 서버로 분할될 기준 필드를 가리키며, partition과 load balancing에 기준이 됩니다. 따라서 적절한 카디널리티를 가진 필드가 shard key로 선택되어야 합니다.

 카디널리티는 조건을 만족하는 데이터의 분산 정도를 나타내는 값으로 전체 데이터 중에서 조건을 만족하는 데이터의 분포가 넓으면 낮은 카디널리티라고 하며 분포가 좁으면 높은 카디널리티라고 표현합니다. 예를 들어 사원번호는 고유한 값이니 높은 카디널리티입니다. 남/여 라는 필드로 샤드키를 구성하면 낮은 카디널리티입니다.

 결과적으로 카디널리티가 너무 높거나 낮은 필드는 shard key로는 적절하지 않습니다. 왜냐면 데이터를 적절하게 분산 저장하기에는 데이터 값의 유형이 적절하게 잘 분포되어야 할 필요가 있습니다.

 


7. replication

 복제는 여러 서버에서 데이터베이스 서버를 분산하고 관리하는 것입니다. "장애는 항상 발생한다"라고 하는 피할 수 없는 사실 때문에 대부분의 데이터베이스 관리 시스템에서 복제는 핵심적 요소입니다. mongoDB에서 복제는 아래와 같은 특징을 가집니다.

  • Master/slave 관계를 갖는 원본과 복사본 사이입니다. 
  • Master에서 쓰기 operation을 수행하고 이러한 operation을 Master의 oplog(명령어 기록)에 기록합니다. slave는 Master의 oplog를 복제하고 각자의 데이터 세트에 오퍼레이션을 비동기 방식으로 동일하게 적용됩니다. 
  • Master는 (read/write)용이고, slave는 master의 데이터를 미러링하고 있는 read 전용입니다. Slave에 write가 가능하도록 설정해 줄 수 있지만 속도면에서 권장하지 않습니다. 

 

7-1. 복제 동작 원리

mongoDB에서 복제가 되는 순서는 아래와 같습니다.

  1. 몽고디비 슬레이브는 주기적으로 마스터에게 자신의 optime보다 큰 oplog 요청합니다.
    • oplog에는 primary가 데이터가 아닌 명령어를 기록합니다. 
  2. 5초 안에 마스터에서 쓰기 연산이 발생하면 데이터를 응답합니다. 만약 발생하지 않았다면 데이터가 존재하지 않다는 응답을 보내줍니다.
  3. 슬레이브는 요구한 oplog 데이터가 존재하면 자신의 oplog에 데이터를 저장하고 바로 마스터에게 다시 oplog를 요청합니다.

 

7-2. 리플리카셋(replicatset)

 마스터 서버와 슬레이브 서버의 관계는 원본 데이터베이스에 대한 복제한 데이터를 하나 더 저장하는 관계를 의미합니다. 장애가 발생하면 복구 작업으로 작업을 수행할 수 있습니다. 그러나 실시간으로 마스터 서버에 복구는 어려우며 슬레이브 서버를 바로 사용하기에도 어렵습니다. 따라서 이런 문제점을 개선한 것이 리플리카셋 입니다.

 

리플리카셋 특징

리플라카셋 특징은 아래와 같습니다.

  • primary 서버는 2초 단위로 secondary 서버 상태를 체크하며 동기화를 위한 heartbeat 작업을 수행합니다.
  • 만약 secondary 서버가 중지되더라도 복제 작업만 중지될 뿐 primary 서버에 대한 읽기 작업은 정상적으로 수행합니다.
  • secondary 서버가 복구되면 그동안 밀린 데이터를 복구하기 위해 primary 서버는 계속 oplog를 저장하며, 복구되면 자동으로 동기화해줍니다.
  • 만약 primary 서버가 장애가 생긴다면 secondary 서버를 primary 서버로 만들게 됩니다.

 

리플리카셋 동작 원리

 client의 요청을 처리하는 하나의 primary server와 primary server의 복제 데이터를 가진 여러 secondary server로 구성됩니다. 이 서버들은 서로 heartbeat로 서로 죽었는지 주기적으로 확인합니다. primary 서버는 heartbeat가 과반수를 가져야 하며, 그렇지 않은 경우 seconday 서버로 전환되고 primary 서버를 뽑기 위해 투표를 시행합니다. primary가 되기 위한 조건은 priority(master가 되는 우선순위)와 votes 등이 있습니다.

리프리카셋 

 


8. 마무리

 이번 시간에는 mongoDB에 대한 전체적 내용을 알아보았습니다. 각 주제별 자세한 내용을 다루지는 않았지만 mongoDB에 대한 전체적인 개념을 파악하는데 초점을 두었습니다. 각 주제에 자세한 내용은 다음에 블로그에 포스트하도록 하겠습니다! 😃

출처:

https://ryu-e.tistory.com/2

'Language & OS > DB' 카테고리의 다른 글

DBeaver 설치 및 사용방법  (0) 2024.05.20
minio  (0) 2024.02.22
SQL과 NoSQL의 차이  (0) 2023.01.13
[DB] docker container를 활용해 MongoDB에 데이터 입력하기  (0) 2022.11.22

2022.10.12 수요일

이코테 p.178-181

yo = int(input())

_list = []
for i in range(yo):
    _list.append(int(input()))

_list = sorted(_list, reverse=True)
for a in _list:
    print(a, end=' ')
std = int(input())

std_inf = []
for i in range(std):
    std_inf.append(input().split(' '))

# std_inf = [['ㅎ', 95],['ㅇ','77']]
for i in range(len(std_inf)):
    std_inf[i][1] = int(std_inf[i][1])
    
sort = sorted(std_inf)

for i in range(len(sort)):
    print(sort[i][0], end=' ')

❤️문제

책 이것이 코딩테스트다 p.110

구현문제.

 

❤️내코드

n = int(input())
move = map(str, input().split(" "))
# n = 5
# move = ["R", "R", "R", "U", "D", "D"]

ga, se = 1, 1 

for i in move:
    if i == "R":
        if ga == n:
            pass
        else:
            ga += 1
    elif i == "U":
        if se == 1:
            pass
        else:
            se -= 1
    elif i == "L":
        if ga == 1:
            pass
        else:
            ga -= 1
    elif i == "D":
        if se == n:
            pass
        else:
            se += 1
            
print("%s %s" %(se, ga))

 

 

+ Recent posts