5장 - 복제
- Date
- 2022년 12월 25일 PM 9:52
1. 분산 데이터#
1.1. 여러 장비간 분산된 데이터베이스를 필요로 하는 이유#
- 확장성
- 데이터 볼륨, 읽기 부하, 쓰기 부하가 단일 장비에서 다룰 수 있는 양보다 커지면 부하를 여러 장비로 분배 가능
- 내결함성/고가용성
- 장비 하나가 죽더라도 애플리케이션이 계속 동작해야 한다면 여러 장비를 사용해 중복성 제공 가능
- 지연시간
- 사용자와 지리적으로 가까운 데이터센터에서 서비스를 제공하기 위해 전 세계 다양한 곳에 서버를 두어 지연을 낮춘다
1.2. 고부하로 확장#
1.2.1. 공유 아키텍처#
- 수직 확장을 통해 공유 메모리 아키텍처로 단일 장비처럼 다룰 수 있다.
- 하지만 많은 비용이 들고, 병목 때문에 두 배의 용량을 높힌다고 반드시 두 배의 부하를 처리할 수 있는 것이 아니다.
1.2.2. 비공유 아키텍처#
- 수평 확장을 통해 독립적인 컴퓨팅 자원을 가지는 노드를 생성한다.
- 가성비가 좋은 시스템을 사용할 수 있고 지리적 영역에 걸쳐 데이터를 분산해 지연시간을 줄일 수 있다.
1.3. 복제 대 파티셔닝#

- 복제 = 같은 데이터를 다른 위치에 있는 여러 노드에 유지한다.
- 파티셔닝 = 큰 데이터베이스를 파티션이라는 작은 서브셋으로 나누고 각 파티션은 각기 다른 노드에 할당한다.
2. 복제#
- 복제란 네트워크로 연결된 여러 장비에 동일한 데이터의 복사본을 유지한다는 의미다.
- 복제가 필요한 이유
- 지리적으로 사용자와 가깝게 데이터를 유지해 지연 시간을 줄인다.
- 시스템의 일부에 장애가 발생해도 지속적으로 동작할 수 있게 해 가용성을 높인다.
- 읽기 질의를 제공하는 장비의 수를 확장해 읽기 처리량을 늘린다.
- 복제에서 모든 어려움은 변경 처리에 있으며 노드가 변경을 복제하기 위한 알고리즘으로 단일 리더, 다중 리더, 리더 리스 복제를 살펴본다.
- 복제는 고려해야 할 트레이드오프가 있다.
2.1. 리더와 팔로워#
- 데이터베이스의 복사본을 저장하는 각 노드를 복제 서버(replica)라고 한다.
- 데이터베이스의 모든 쓰기는 모든 복제 서버에 처리돼야 한다.
- 가장 일반적인 해결책은 리더 기반 복제다.

리더-팔로워 모델 - 복제 서버 중 하나를 리더로 정하고 리더는 로컬 저장소에 새로운 데이터를 저장한다.
- 다른 복제 서버는 팔로워가 되어 변경을 복제 로그나 변경 스트림을 통해 전송받아 복사본을 갱신한다.
2.2. 동기식 대 비동기식 복제#

- 팔로워1은 동기식, 팔로워2는 비동기식 복제를 사용하고 있다.
- 동기식 복제의 장단점
- 리더와 일관성 있게 최신 데이터 복사본을 가지는 것을 보장
- 동기 팔로워가 응답하지 않는다면 쓰기가 처리될 수 없다.
- 리더는 모든 쓰기를 block하고 동기 복제 서버가 다시 사용할 수 있을 때까지 기다려야 한다.
- 때문에 모든 시스템이 동기식이라면 전체 시스템이 멈추게 된다.
- 동기식, 비동기식을 섞어 사용하는걸 반동기식이라 한다.
- 보통 리더 기반 복제는 완전히 비동기식으로 구성한다.
- 비동기식 복제는 내구성을 약화시키기 때문에 나쁜 트레이드오프 같지만 많은 팔로워가 있거나 지리적으로 분산됐다면 비동기식 복제를 널리 사용한다.
2.3. 새로운 팔로워 설정#
- 때때로 복제 서버 수를 늘리거나 장애 노드의 대체를 위한 새로운 팔로워를 설정해야 한다.
- 클라이언트는 지속적으로 DB에 기록하고 데이터는 항상 유동적이기 때문에 표준 파일 복사본은 다른 시점에 데이터베이스의 다른 부분을 보게 된다.
- 즉 복사 결과가 유효하지 않을 수 있다.
- DB를 잠가 디스크의 일관성을 만들 수 있지만 고가용성 목표에 부합하지 않기 때문에 아래 과정을 통해 진행한다.
- DB잠금을 걸지 않고 리더의 스냅숏을 일정 시점에 가져온다. (MySQL의 innobackupex 툴)
- 스냅숏을 새로운 팔로워에 복사한다.
- 팔로워는 리더에 연결해 스냅숏 이후 데이터 변경을 요청한다. (로그 일련번호와 이진로그 좌표를 통해 진행)
- 팔로워가 스냅숏 이후 데이터 변경의 미처리분을 모두 처리했을 때 따라잡았다고 말한다.
2.4. 노드 중단 처리#
- 노드가 장애로 인해 예기치 않게 중단될 경우 리더 기반 복제에서 고가용성을 달성할 수 있는 방법
2.4.1. 팔로워 장애: 따라잡기 복구#
- 결함이 발생하기 전 마지막 트랜잭션을 알아내 끊어진 이후 발생한 데이터 변경을 모두 요청한다.
2.4.2. 리더 장애: 장애 복구#
- 리더의 장애를 처리하는 일은 까다롭다 팔로워 중 하나를 리더로 승격하고 클라이언트는 새로운 리더로 쓰기를 전송해야하는 재설정이 필요하다.
- 장애 복구 단계
- 리더가 장애인지 판단한다.
- 새로운 리더를 선택한다.
- 새로운 리더 사용을 위해 시스템을 재설정 한다.
2.5. 복제 로그 구현#
2.5.1. 구분 기반 복제#
- 리더는 모든 쓰기 요청을 기록하고 쓰기를 실행한 다음 구문 로그를 팔로워에게 전송한다.
- 합리적인 것 같은 이 접근법도 복제가 깨질 수 있는 사례가 존재한다.
- NOW(), RAND() 등은 복제 서버마다 다른 값을 생성할 가능성이 존재
- 자동증가 컬럼을 사용하거나, 기존 데이터에 의존하는 경우(WHERE) 정확히 같은 순서로 실행되어야 함
- 순서가 다르면 구문의 효과가 다를 수 있음 → 동시에 여러 트랜잭션이 수행되는 것을 제한한다.
- 부수효과를 가진 구문의 경우 부수효과가 완벽히 결정적이어야 모든 팔로워에서 그 효과도 동일하다.
- 트리거, 스토어드 프로시저, 사용자 정의 함수
- 이 문제의 해결책으로 리더는 구문을 기록할 때 모든 비결정적 함수 호출을 고정 값을 반환하게끔 대체할 수 있다.
- But. 여러 에지 케이스가 있기에 일반적으로 다른 복제 방법을 선호한다.
2.5.2. 쓰기 전 로그 배송#
- 일반적으로 데이터베이스의 모든 쓰기는 로그에 기록이 된다.
- 리더가 로그를 팔로워에게 전송하고, 팔로워는 이 로그를 처리함으로써 복제한다.
- 로그는 제일 저수준의 데이터를 기술함
- 디스크 블록에서 어떤 데이터를 변경했는 지와 같은 상세 정보 포함
- 복제 프로세스가 저장소 엔진과 밀접하게 연관된다.
- 리더와 팔로워가 동일한 소프트웨어 버전에서 실행되어야 한다.
- 소프트웨어 업그레이드 시 중단 시간이 필요하다.
2.5.3. 논리적(로우 기반) 로그 복제#
- 로그를 저장소 엔진과 분리하기 위한 대안으로 복제와 저장소 엔진에 각기 다른 로그 형식을 사용한다.
- 이와 같이 복제에서 사용하는 로그를 저장소 엔진의 물리적 데이터 표현과 구별하기 위해 논리적 로그라 부른다.
- RDB의 논리적 로그는 대개 로우 단위이고, 테이블에 쓰기를 기술한 레코드 열이다.
- 삽입된 로우 = 모든 컬럼의 새로운 값을 포함
- 삭제된 로우 = 로우를 식별하기 위한 정보(보통 기본 키)를 포함
- 갱신된 로우 = 로우를 식별하기 위한 정보 + 모든 컬럼의 새로운 값 또는 변경된 컬럼의 새로운 값
- 여러 로우를 수정하는 트랜잭션은 여러 로그 레코드를 생성한 다음 트랜잭션 커밋을 레코드에 표시한다.
- 논리적 로그와 저장소 엔진 내부를 분리해 하위 호환성을 쉽게 유지하고, 리더와 팔로워간 다른 버전의 소프트웨어 실행이 가능
- 논리적 로그는 외부 애플리케이션이 파싱하기 쉽다.
- 데이터 웨어하우스와 같은 외부 시스템에 데이터베이스 내용 전송 시 유용하다.
- 변경 데이터 캡쳐(CDC, change data capture)
2.5.4. 트리거 기반 복제#
- 지금까지 설명한 복제 방식은 애플리케이션의 관여 없이 DB 시스템에 의해 구현되었다.
- 오라클은 GoldenGate 도구를 통해 데이터베이스 로그를 읽어 애플리케이션이 데이터를 변경할 수 있도록 한다.
- 사용자 정의 애플리케이션 코드를 등록할 수 있다.
- 데이터 변경 시(쓰기 트랜잭션) 자동으로 실행된다.
- 트리거를 통해 데이터 변경을 분리된 테이블에 로깅한다.
- 이 테이블에 기록된 데이터 변경을 외부 프로세스가 읽고 처리한다.
- 필요한 애플리케이션 로직 적용 후 다른 시스템에 데이터 변경을 복제한다.
- 트리거의 장점
- 유연성 높아 매우 유용하다.
- 트리거의 단점
- 트리거 기반 복제는 다른 복제 방식보다 많은 오버헤드가 있다.
- 그리고 데이터베이스에 내장된 복제보다 버그나 제한 사항이 더 많이 발생한다.
2.6. 복제 지연 문제#
- 복제는 노드 내결함성 뿐만 아닌 확장성과 지연 시간 때문에도 필요하다.
- 읽기 확장 아키텍쳐
- 리더 기반 복제는 쓰기 분산은 어렵지만 읽기 분산이 가능하다.
- 장점
- 웹 서비스의 경우 읽기 요청이 대부분, 쓰기 요청은 작은 비율로 구성
- 리더의 부하를 경감하고 복제 서버에서 읽기 요청을 처리 → 웹 서비스에 적합
- 복제의 목표 중 확장성, 지연시간 단축 달성
- 단점
- 비동기식 복제 방식에서만 동작한다.
- 동기식 복제는 단일 노드의 장애, 네트워크 중단이 전체 시스템의 쓰기를 마비시켜 적절하지 않음
- 노드가 많아질 수록 다운될 가능성이 커져 동기식 설정과 적절하지 않다.
- 데이터 불일치 = 팔로워와 리더간 일시적 복사 지연 상태
- 최종적 일관성 = 팔로워는 리더와 데이터의 불일치 상태가 있을 수 있지만 쓰기를 멈추면 결국 리더를 따라잡게 된다.
- 복제 지연으로 인한 데이터 불일치는 찰나의 순간이고 크게 문제가 되지 않지만 시스템이 가용량 근처에서 동작하거나 네트워크 문제가 있다면 복제 지연으로 인한 불일치가 문제가 된다.
2.6.1. 복제지연 사례#
자신이 쓴 내용 읽기

- 사용자가 페이지를 리로딩하면 자신이 제출한 모든 갱신을 볼수 있음을 보장한다.
- 다른 사용자가 제출한 것에 대해서는 보장하지 않는다.
- 구현 방법
- 사용자가 수정한 내용을 읽을 때에는 리더에서 읽는다.
- 이 외의 경우는 팔로워에서 읽는다.
- 시간을 기준으로 리더 읽기 여부를 구분한다.
- 레코드의 마지막 갱신 시각을 기준으로(ex. 1분 이내) 리더 읽기 여부를 구분
- 가장 최근의 쓰기 타임 스탬프를 이용해 질의를 대기한다.
- 복제서버에 아직 갱신이 반영되지 않았다면?
- 다른 복제 서버가 읽기 요청을 처리
- 복제 서버에 갱신이 반영될 때 까지 질의를 대기
- 복제 서버가 여러 데이터센터에 분산된 경우
- 사용자에게 지리적 근접성, 가용성을 보장하기 위해 설계된 경우
- 리더가 제공해야하는 요청은 전부 리더가 포함된 데이터센터로 라우팅되어야 한다.
- 디바이스 간 쓰기 후 읽기 일관성
- 동일한 사용자가 여러 디바이스로 서비스에 접근하는 경우 하나의 디바이스에서 방금 입력한 정보가 다른 디바이스에서도 조회되어야 한다.
- 디바이스 간 쓰기 후 읽기 일관성이 보장되어야 한다.
- 사용자의 마지막 갱신 타임스탬프의 경우 다른 디바이스에서는 알 수가 없다.
- 이러한 메타데이터를 중앙집중식으로 관리해야한다.
- 복제 서버가 여러 데이터센터 간에 분산된 경우
- 다른 디바이스의 연결이 동일한 데이터센터로 라우팅된다는 보장이 없다.
- 사용자 디바이스의 요청을 동일한 데이터센터로 라우팅해야 한다.
단조 읽기

- 시간이 거꾸로 흐르는 현상
- 팔로워 간에도 동일한 쓰기에 대해 갱신 시점의 차이가 존재한다.
- 동일한 읽기 요청을 여러번 보낼 때 각기 다른 팔로워에게 전달이 될 수 있다.
- 어떤 팔로워는 쓰기를 알고 있으나, 어떤 팔로워는 모른다면 시간이 거꾸로 흐르는 현상을 겪을 수 있다.
- 단조 읽기
- 위와 같은 종류의 이상 현상이 발생하지 않음을 보장한다.
- 강한 일관성 보다는 덜하고, 최종적 일관성 보다는 강한 보장이다.
- 한 사용자가 여러 번에 걸쳐 읽어도 시간이 되돌아가는 현상을 경험하지 않는다.
- 이전에 새로운 데이터를 읽은 후에는 예전 데이터를 읽지 않는다.
- 구현 방법
- 각 사용자의 읽기가 항상 동일한 복제 서버에서 수행한다. (스티키 세션 같은?)
- 복제 서버가 고장나면 사용자 질의를 다른 복제 서버로 재라우팅할 필요가 있음
일관된 순서로 읽기

- 일관된 순서로 읽기
- 이러한 종류의 이상현상을 방지하기 위해 일관된 순서로 읽기와 같은 유형의 보장이 필요하다.
- 일련의 쓰기가 특정 순서로 발생한 경우 다른 사용자에게도 쓰기에 대해 쓰여진 순서대로 읽는 것을 보장한다.
- 인과성의 위반 발생
- 파티셔닝(샤딩)된 데이터베이스에서 발생하는 특징적인 문제한다.
- 많은 분산 데이터베이스에서 파티션은 서로 독립적으로 동작하기에 쓰기의 전역 순서가 없다.
- 해결책
- 인과성이 있는 쓰기가 동일한 파티션에 기록되게끔 한다.
2.6.2. 복제 지연 해결책#
- 해결 방안의 종류
- 쓰기 후 읽기와 같은 강한 보장을 제공하도록 시스템을 설계한다.
- 비동기식 복제를 사용하지만 동기식 방식으로 동작하는 것 처럼 보인다.
- 애플리케이션이 데이터베이스보다 더 강력한 보장을 제공하는 방법도 있다.
- 그러나 애플리케이션에서 다루기에는 복잡하여 잘못되기 쉽다.
- 트랜잭션 = 애플리케이션이 단순해지기 위해 데이터베이스가 더 강력한 보장을 제공하는 방법
- 애플리케이션 개발자가 미묘한 복제 문제를 걱정하지 않고 올바른 작업 수행을 위해 항상 데이터베이스를 신뢰할 수 있다.
- 이것이 트랜잭션이 존재하는 이유다.
- 분산 시스템에서의 트랜잭션은 많은 시세틈에 포기했다.
- 트랜잭션은 가용성과 성능 측면에서 너무 비싸다.
- 확장 가능한 시스템에서는 최종적 일관성을 선택하는 것이 불가피하다는 주장도 존재한다.
- 이러한 주장의 일부는 사실이지만 지나치게 단순화된 측면이 있다.
3. 다중 리더 복제#
- 리더 기반 복제는 하나의 리더를 거쳐야만 쓰기가 가능하다는 것이다.
- 쓰기 처리를 하는 각 노드는 데이터 변경을 모든 노드에 전달하는데 이를 다중 리더 설정이라 부른다.
- 이 설정에서 각 리더는 동시에 다른 리더의 팔로워 역할도함
- 모든 쓰기를 해당 리더를 거쳐야 하고, 리더 연결이 불가능한 경우 쓰기 불가능한 단점 보완
3.1 다중 리더 복제의 사용 사례#
3.1.1 다중 데이터 센터 운영#

- 각 데이터 센터마다 리더가 있을 수 있다.
- 각 데이터 센터내 리더 팔로워 복제를 사용
- 각 데이터 센터 간 리더가 다른 데이터 센터 리더에게 변경 사항 복제한다.
- 동일한 데이터를 다른 두 개의 데이터센터에서 동시에 변경 가능하므로 쓰기 충돌은 반드시 해소되어야함
- 일부 데이터베이스는 기본적으로 다중 리더 설정 제공
- 단일 리더와 다중 리더간의 설정 비교
# 단일 리더 다중 리더 성능 쓰기는 인터넷을 통해 리더가 있는 데이터 센터로 이동해야해서 쓰기 지연 발생 쓰기는 로컬 데이터센터 처리 후 비동기 방식으로 다른 데이터센터에 복제 데이터센터 중단 내성 리더가 있는 데이터센터가 고장 나면 다른 데이터센터의 팔로워를 리더로 승진 각 데이터센터 독립적으로 동작, 고장난 데이터센터가 온라인으로 돌아왔을때 복제 네트워크 문제 내성 데이터 센터 내 쓰기는 동기식이기에 데이터 센터 내 연결 문제에 민감 비동기 복제를 사용해 네트워크 문제에 보다 잘 견딤, 일시적 네트워크 중단에도 쓰기 처리는 진행되기 때문
3.1.2. 오프라인 작업을 하는 클라이언트#
- 인터넷 연결이 끊어진 동안 애플리케이션 동작해야 하는 경우
- 협업 편집 : 동시에 여러 사람이 문서를 편집할 수 있는 애플리케이션 ex) 이더패드, 구글 독스 등
3.2. 쓰기 충돌 다루기#

- 다중 리더 복제에서 가장 큰 문제는 쓰기 충돌이 발생한다는 점이다.
- 각 사용자가 동시에 편집 후 로컬 리더에 저장하였으나 변경을 비동기로 복제 시 쓰기 충돌 발생
3.2.1. 동기 대 비동기 충돌 감지#
- 동기식으로 충돌 감지를 하면 다중 리더 복제의 장점을 잃어버림
3.2.2. 충돌 회피#
- 충돌 처리하는 가장 간단한 전략
- 충돌 처리가 어려워 충돌 피하는 것이 자주 권장됨
- 특정 레코드의 모든 쓰기를 동일한 리더에서 처리함
3.2.3. 일관된 상태 수렴#
- 모든 복제 서버가 동일해야 하는 원칙으로 일괄성없는 상태를 용인하지 않는다.
- 수렴(convergent) : 모든 변경이 복제돼 모든 복제 서버에 동일한 최종 값이 전달되게 해야 함
3.2.4. 사용자 정의 충돌 해소 로직#
- 충돌 해소의 가장 적합한 방법은 애플리케이션에 따라 다르다.
- 따라서 대부분 다중 리더 복제도구는 애플리케이션 코드를 사용해 충돌 해소 로직 작성
| 쓰기 수행 중 | - 복제된 변경사항 로그에서 데이터베이스 시스템 충돌 감지되면 충돌 핸들러 호출 - 백그라운드에서 실행됨 |
| 읽기 수행 중 | - 충돌 감지 시 모든 충돌 쓰기 저장 - 다음 번 읽기 시 여러 데이터 반환. 애플리케이션은 사용자에게 충돌 내용 보여주거나 자동으로 충돌 해소해 결과를 데이터베이스에 기록 - 카우치DB가 이렇게 동작 |
- 자동 충돌 해소
- 충돌 없는 복제 데이터 타입
- Set, Map, 정렬 목록, 카운터 등을 위한 데이터 구조의 집합
- 병합 가능한 영속 데이터 구조
- Git 처럼 명시적으로 히스토리 추적하고 삼중 병합 함수를 사용한다
- 운영 변환
- 이더패트, 구글 독스 같은 협업 편집 애플리케이션의 충돌 해소 알고리즘
3.3. 다중 리더 복제 토폴로지#

- 복제 토폴로지는 쓰기를 한 노드에서 다른 노드로 전달하는 통신 경로를 설명
- 리더가 둘 이상이라면 다양한 토폴로지가 가능하다.
- 원형 토폴로지
- 각 노드가 하나의 노드로부터 쓰기를 받고, 이 쓰기를 다른 노드에 전달
- MySQL 에서 기본적으로 제공
- 노드 장애 시 노드 간 복제 메시지 흐름에 방해를 줌
- 별 모양 토폴로지
- 지정된 루트 노드 하나가 다른 모든 노드에 쓰기 전달
- 트리로 일반화 가능
- 노드 장애 시 노드 간 복제 메시지 흐름에 방해를 줌

- 전체 연결 토폴로지
- 모든 리더가 각자의 쓰기를 다른 모든 리더에 전송
- 가장 일반적인 토폴로지
- 내결함성이 상대적으로 좋음
- 전체 연결 토폴로지의 문제점
- 네트워크 연결 속도 차이로 인한 복제 메시지 추월
- 리더2는 삽입 이전에 갱신을 처리하게 됨
- 올바른 이벤트 정렬을 위한 버전 벡터 기법으로 해결 가능
- 따라서 다중 리더 복제 시스템을 사용하려면 이런 문제를 인지하고 문서를 주의깊게 읽은 다음 데이터 베이스를 철저하게 테스트해봐야 함
4. 리더 없는 복제#
- 리더의 개념을 버리고 복제 서버가 클라이언트로부터 쓰기를 직접 받을 수 있게 허용하는 접근 방식
- 다이나모 스타일 DB로 리악, 카산드라, 볼드모트 등 오픈소스 데이터스토어가 있음
- 일부 리더 없는 복제 구현에서는 클라이언트가 여러 복제 서버에 쓰기를 직접 전송하는 반면 코디네이터 노드가 클라이언트를 대신해 이를 수행하기도 한다.
4.1. 노드가 다운됐을 때 데이터베이스에 쓰기#

- 다운된 노드에서는 쓰기가 누락되어 오래된(outdated) 값을 읽게 됨
- 읽기 요청을 병렬로 여러 노드에 전송해 최신 값을 읽어와 해결 가능
- 버전 숫자를 통해 읽어온 값 중 최신 값을 결정함
4.1.1. 읽기 복구와 안티 엔트로피#
- 복제 계획은 최종적으로 모든 데이터가 모든 복제 서버에 복사된 것을 보장해야 한다.
- 다이나모 스타일 데이터스토어는 두 가지 메커니즘을 주로 사용
| 읽기 복구 | - 클라이언트가 여러 노드에서 병렬로 읽기 수행하면 오래된 응답 감지 가능 - 복제 서버의 오래된 값을 새로운 값으로 기록 - 값을 자주 읽는 상황에 적합 |
| 안티 엔트로피 처리 | - 백그라운드 프로세스와 복제 서버 간 데이터 차이를 찾아 누락된 데이터를 복사 - 특정 순서로 쓰기를 복사하기 때문에 지연이 있을 수 있음 |
4.1.2. 읽기와 쓰기를 위한 정족수#
- 모든 성공한 쓰기가 세 개의 복제 서버 중 적어도 두 개의 복제 서버에 존재한다는 것을 보장한다면 하나의 복제 서버가 오래된 데이터임을 의미
- 두 개의 복제 서버에서 읽으면 두 개 중 적어도 하나는 최신 값인지 확인할 수 있다.
- n개의 복제 서버가 있을 때 w개의 노드에서 성공해야 쓰기가 확정되고 모든 읽기는 최소한 r개의 노드에 질의해야 한다.
- 이런 r과 w를 따르는 읽기와 쓰기를 정족수 읽기와 쓰기라 부른다.
- 다이나모 스타일 DB에서는 복제 서버(n), 쓰기 노드(w), 읽기 노드(r) 설정 가능하다.
- 일반적으로 n 은 3 또는 5 등의 홀수, w = r = (n+1) / 2 (반올림) 설정한다.