컴퓨터가 무언가를 "기억"해야 할 일은 굉장히 많다. 컴퓨터는 사람의 이름, 생일부터 비밀번호나 수천 명의 이메일 같은 데이터를 다룰 수 도 있다.
하지만, 이러한 데이터를 단순히 텍스트 파일로 저장하는 것은 굉장히 불편하다. 텍스트 파일을 전혀 구조화되어있지 않고, 다루는 데이터가 많아지면 메모리 사용량과 처리 시간도 급증한다.
따라서 다량을 데이터를 다룰 때는 데이터베이스라는 것을 이용한다.
데이터베이스의 필요성
사용자의 신원을 저장하기 위해 다음과 같은 내용을 일반 파일에 저장했다.
[ { "name":"민준", "birth":"2007/01/04", "sex":"M", "uid":"AFF34" }, { "name":"지유", "birth":"2007/04/06", "sex":"F", "uid":"DECC2" }, { "name":"소윤", "birth":"2007/07/14", "sex":"F", "uid":"3AAFC" } ] |
그리고 이 형식의 파일을 분석(파싱, Parsing)해서 정보를 삽입, 삭제, 수정하는 코드를 작성했다.
노력은 가상하고, 시도는 좋았으나, 이 방법에는 몇 가지 문제가 있다.
만일 사용자가 급증하여 수백명, 수천 명의 정보를 위와 같은 방식으로 처리한다면 정보를 분석하는 코드의 자원(시간, 메모리) 사용량이 커진다.
보안 취약점이나 버그를 수정하려고 분석 코드를 수정하다 보면 코드와 데이터는 점점 복잡해진다.
새로운 필드, 이를테면 사용자의 나이를 추가로 저장하고 싶을 때 파일의 각 사람마다 나이 필드를 일일이 추가해줘야 하고, 나이를 분석하는 코드를 추가해야 한다. 이는 코드를 복잡하게 하고, 버그의 원인이 될 수 있다.
데이터를 업데이트하는 중에 프로그램이 버그로 인해 강제 종료되었고, 파일에 정보가 완전하게 쓰이지 않았다. 가령 uid를 3AAFC에서 5FCCA로 바꾸는 중 5FC까지 쓰고 프로그램이 종료되어 uid는 5FC가 되었다.
이러한 문제는 구조화되어 있고, 안전하며, 항상 일관성을 유지하는 데이터 저장 방식의 요구를 만들었다. 그러한 체계가 데이터베이스이다.
데이터베이스의 특징
데이터베이스는 다음과 같은 특징을 가지고 있다.
- 실시간 접근성: 언제나 데이터베이스는 요청하는 정보를 제공할 수 있어야 한다.
- 지속적인 변화: 데이터베이스는 내용을 수시로 삭제, 추가, 변경할 수 있다.
- 동시 공용: 여러 사용자가 한 데이터베이스의 같은 내용을 동시에 볼 수 있다.
- 내용에 의한 참조: 데이터베이스의 내용은 주소 등에 의해서가 아닌, 정보(키값 등)에 의해 찾는다.
위 조건을 꽤나 간단해 보이지만, 실제로는 풀어야 할 문제가 많다.
예를 들어 사용자 A가 데이터를 쓰는 도중에 B가 데이터를 읽으면 어떻게 되는가? A가 쓰고 있는(완전히 쓰진 않은) 데이터가 읽혀서는 안 된다.
데이터베이스는 이러한 여러 문제 상황에 유연하게 대처하기 위해 설계가 되었으며, 이 부분 때문에 텍스트 파일이 데이터베이스를 대체할 수 없는 것이다.
또한 데이터베이스는 다음 조건을 모두 갖추어야 한다.
- 원자성: 모든 작업은 성공하거나 실패해야 한다. 즉, 진행 중에 중단된 작업은 존재할 수 없다.
- 일관성: 원자성을 만족한다면, 데이터베이스의 정보는 의도한 대로 저장돼야 한다(일관적이어야 한다).
- 독립성: 작업 중에 다른 작업이 끼어들어서는 안 된다. 예를 들어 A가 데이터를 쓰는 중에 B가 데이터를 써서 A와 B의 데이터가 섞여서는 안 된다.
- 지속성: 성공적인 작업은 영원히 반영돼야 한다. 즉, 프로그램이 강제 종료돼도 데이터베이스의 정보는 영향이 없으며. 모든 작업은 로그를 남긴 후에야 성공으로 간주될 수 있다. 나중에는 이 로그를 이용해서 장애가 발생했을 시 데이터베이스 수정을 취소할 수 있다.
이를 통틀어 ACID(Atomicity, Consistency, Isolation, Durability)라고 한다. 데이터베이스는 ACID를 지키기 위해 트랜잭션(Transaction), 롤백(Rollback), 락(Lock) 등의 여러 수단을 사용한다.
만일 데이터베이스가 ACID를 만족하지 않는다면 어떻게 되는지 생각해보자.
지후가 주희에게 100만원을 송금하려고 한다.
은행의 각 사용자에 대한 데이터베이스 구조:
사용자 잔액(잔액은 항상 0 이상이며, 그렇지 않을 시 오류) 주희 140만원 지후 50만원 은행이 [n]원을 A에서 B에게 송금하는 방법:
"A"의 잔액을 ("A"의 잔액-[n])으로 저장 "B"의 잔액을 ("B"의 잔액+[n])으로 저장
은행이 100만원을 주희에게 송금하려고 하면 다음과 같은 일이 생긴다.
"지후"의 잔액을 ("지후"의 잔액-[100만원])으로 저장 - 실패: 잔액이 0원 미만일 수 없음, "지후"의 잔액=[50만원] "주희"의 잔액을 ("주희"의 잔액+[100만원])으로 저장 - 성공, "주희"의 잔액=[240만원]
돈을 송금해야 하는데 돈이 복제되었다. 이는 매우 심각한 문제로 절대 벌어져서는 안 될 일이다.
위의 예시와 같은 문제가 생긴 이유는 데이터베이스의 원자성이 깨져서 일관성이 사라졌기 때문이다. "송금"이라는 작업은 완전히 성공하거나 실패해야 하는데 2개 중 1개 명령은 성공, 1개는 실패했기 때문에 원자성이 깨졌다. 따라서 "송금"이라는 의도된 작업이 이루어지지 않은 것이다.
이를 막으려면 "송금"을 실행하는 중 오류가 하나라도 생기면 즉시 작업을 중단하고, 송금이 시작되기 이전의 상태로 데이터베이스를 되돌려놓아야 한다.
이 외에도 송금중 2번째 작업을 시행하기 전, 주희가 카드를 사용해서 주희의 잔액을 주희의 잔액에서 1만 원 뺀 금액으로 저장하는 명령이 실행되었다고 가정해보자. 원래대로라면 주희의 잔액은 140만원-1만원+100만원=239만원이여야 하지만, 송금의 2번째 명령은 주희의 잔액을 140만원으로 알고 있기 때문에 주희의 잔액을 240만원으로 저장한다. 즉, 또 1만원이 어디선가 복제된 것이다.
이러한 불상사를 막기 위해 데이터베이스에는 ACID가 필수적이다.
'컴퓨터' 카테고리의 다른 글
FTP 서버 구축 (0) | 2021.12.12 |
---|---|
ARP 스푸핑 공격 - 개념 (0) | 2021.10.05 |
RSA 암호화 - 개념편 (0) | 2021.07.22 |
해시(Hash) (0) | 2021.07.22 |