2월, 2018의 게시물 표시

(글로벌 서비스 구축) 컴퓨팅 인프라 구축 계층화 하기.

글로벌 서비스를 구축한다는 것은 수많은 자원과 인프라가 요구된다. 그것을 관리하기 위해서는 많은 인적자원이 필요하고 효율적으로 관리되어야 하지만 100명에서 1천명으로 인적자원이 늘어난다고 10배의 노력이 필요한게 아니라 오히려 10배이상의 효율적인 관리가 필요하게 된다. 이를 효율화 할 수 있는 한가지 방법은 "도메인 이름(Domain name)" 이용해서 자원을 계층적으로 만들고,  각 계층에 이름을 붙이는 방법이다. 다음은 그 예시이다. eunorth. dev. timeline. worker. community.com      1          2              3                          4 1 .eunorth : 북유럽 리전에 있는 2. dev : 개발 목적 3. timeline : 타임라인 서비스 4. worker : 워커 역할 5. community.com : community조직에서 관리한다. 또한 서브넷 주소를 통해 규칙을 만들 수 있다. 퍼블릭 서브넷(웹서버) 라면 세번째 블록의 주소에 1과 2를,  프라이빗 서브넷(WAS, 데이터베이스) 라면 3과 4를 넣는다. 또한, 2개의 Availability Zone 을 사용하면 가용성 존이 1일 경우는 홀수를 부여하고 가용성 존2 일경우는 짝수를 부여하는 방식이다. 또한 국가별 region은 VPC를 분리한다. 예를들어 , 도쿄 리전은 10.10.0.0/16 버지니아 리전은 10.20.0.0/16 아일랜드 리전은 10.30.0.0/16 으로 분리한다. 단기간에 위와같이 리전을 분리할 필요가 없다. 확장할 계획이 있을 때, 새로운 리전을 추가하면 된다.

(Python) __unicode__함수

__unicode__()함수는 객체를 스트링으로 표현해주는 파이썬의 내장 함수로, 모든 객체가 기본적으로 갖고 있는 self.name속성값을 리턴한다. 파이썬3 버전에서는 __str__()함수로 대체되었다.

(Python) 프로젝트생성, 애플리케이션 생성, 데이터베이스 변강사항 반영, 웹서버로 확인 (장고)

이미지
1. 프로젝트 생성 $django-admin.py startproject mysite djangoPractice디렉토리에서 위와 같은 명령어를 타이핑하여 프로젝트를 생성하면 __init__.py파일 (패키지 인경우 생성) settins.py urls.py (URL모듈화를 위해) wsgi.py manage.py가 생성된다. 2. 애플리케이션 생성 $ python manage.py startapp polls

(Python) 정규표현식

*  . (Dot) -> 모든 문자 하나 *  ^(Caret) -> 문자열의 시작 *  $ -> 문자열의 끝 * [] -> [] 괄호 안에 있는 문자 하나, 예를들어 [akz]면 a 또느 k또는 z * [^ ] -> [] 괄호안에 있는 문자 의외의 문자하나, 만일 [^az] 라면 a와 b를 제외한 문자 하나 * * -> 0번 이상 반복, {0,}와 동일 * + -> 1번이상 반복, {1,}와 동일 * ? -> 0번 또는 1번 반복, {0, 1} 와 동일 * {n} -> n번 반복 * {m, n} -> 최소 m 번에서 최대 n 번까지 반복 * | -> 예를들어, A|B라면 A또는 B * [a-z] -> a에서 z까지 임의의문자, 즉 영문 소문자 한 개 * \w -> 영문,숫자 또는 밑줄(_) 한 개, [0-9a-zA-Z_]와 동일 * \d -> 숫자 한 개, [0-9]와 동일

(Python_Django) 템플릿 파일 인식

이미지
장고에서 템플릿 파일은  .html확장자를 가지며, 장고의 템플릿 시스템 문법에 맞게 작성합니다. 중요한점은 템플릿 파일을 적절한 디렉토리에 위치시켜야 한다는 것이다. 즉, 장고는 템플릿 파일이 적절한 위치에 있어야 템플릿 파일을 찾을 수 있다. 장고에서 템플릿 파일을 찾을 떄는 TEMPLATE 및 INSTALLED_APPS에서 지정된 디렉토리를 검색합니다. 이 항목들은 프로젝트 설정 파일인 global_ settings.py 파일에 정의 되어 있다.

(MongoDB) Sharding split

* split이란? chunk를 split하여 두 개의 chunk 로 만드는것을 말한다. 일반적으로 mongos에서는 split기능이 automatically로 작동하지만, 관리자에 의하여 수동적으로 split 할 수가 있다. db.adminCommand({split : <database>.<collection>, <find | middle | bounds>}) 예) db.runCommand( { split : "example.User", middle : {location: 0 }})

(MongoDB) Sharding Balancer란?

* 몽고디비 Balancer란? 이 기능은 백그라운드 프로세스가 청크의 수와 각각의 샤드를 감시하는 기능이다. 만약 청크가 주어진 샤드에서 migration thresholds에 도달한다면, 밸런스는 자동으로 그 청크를 다른 샤드로 이동시킨다. 밸런서란, 각각의 청크들이 샤드 콜렉션에 고르게 분포되도록 만들어 주는 것이다. default는 밸런스 프로세스가 항상 enabled이다. * sh.setBalancerState(boolean) -> 이 메소드는 밸런스 기능을 enabled할것인지, disabled할 것인지 설정하는 것이다. 이 메소드를 실행 할 수 있는 곳은 mongos에서만 가능하다. 만약 mongod인스턴스에서 한다면 에러가 발생 할 것이다. 만약, 현재 밸런스 기능이 작동하는지 확인하고 싶다면, sh.isBalancerRunning()를 호출하던지 sh.getBalancerState()를 호출한다.

(python) 정규표현식을 이용한 이미지 parsing

이미지
../img/friends/img로 시작해서 .gif로 끝나는 이미지만 파싱하고 싶다면 "\.\.\/img/friends/img.*\.gif" 에서 .* 는 앞의 문자열들이 한번 나오고 .gif사이에 어떤 문자가 와도 상관 없다고 이해하면된다.

정규표현식

aa*bbbbb(cc)*d(d | ) 다음 표현식을 해석해보자. 1. aa* a를 쓰고 그 뒤에 a*를 썻습니다. a*는 a가 몇개든 상관없고 0개 여도 상관없습니다.

(python) the difference children and descendent in Beautiful.

If you have the next <table>   <tr> </tr>  <tr> </tr>  <tr> </tr>  <tr> </tr>    <table>     <td></td>     <td></td>    </table> </table> If you call bsobj.find("table").children you can find only tr tags but if you call descendants you can find td tags

(python) BeautifuSoup library find() and findAll() (Crawling)

The most usage of methods are find() and findAll() in BeautifulSoup. If you use these methods, you can filter tags according to various attributes in HTML page. The next two methods show what parameters findAll(tag, attributes, recursive, text, limit, keywords) find(tag, attributes, recursive, text, keywords) the paramteres are mostly same in two methods. First, tag parameter can be string type or list type; Second, attributes parameters can be dictionary type and find a equivalent tag of them Third, recursive type is boolean. if it is True value, findAll()  search for children and children of children. If it is Fals value. it will find only first tag.(Default is True) Fourth, It is different that text parameter is not a tag attribute but text contents. for example, it can show how many "the clothes", (.findAll(text = "the clothes") and the next is it returns both James tag and Marry tag. .findAll("span", {"class":{"

(python) BeautifuSoup library find() and findAll() (Crawling, 크롤링)

find() 와 findAll()는 BeautifulSoup에서 가장 많이 사용된다. 이 함수를 사용하면 HTML 페이지에서 원하는 태그를 다양한 속성에 따라 쉽게 필터링 할 수 있다. findAll(tag, attributes, recursive, text, limit, keywords) find(tag, attributes, recursive, text, keywords) 1. tag매개변수는 태그 이름으로 문자열 또는 리스트를 넘길 수 있습니다. 2. attributes매개변수는 속성으로 이루어진 파이썬 딕셔너리르 받고, 그중 하나에 일치하는 태그를 찾습니다. 3. recursive 매개변수는 불리언입니다 True이면 findAll함수는 일치하는 태그를 찾아 자식, 자식의 자식을 검색합니다. false이면 최상위 태그만 찾습니다.(default 는 True) 4. text매개변수는 태그의 속성이 아니라 텍스트 콘텐츠에 일치한다는 점이 좀 다릅니다. 예를들어, the clothes가 몇번 나타났는지 보려면 다음과 같이 나타냅니다. .findAll(text = "the clothes") 예를들어, James태그와 Marry태그를  모두 반환합니다. .findAll("span", {"class":{"green", "red"}})

(세금공부) 국민연금 보험료 (연말정산)

연말정산결과 조회 중 국민연금 보험료 항목이 있을것입니다. 그러면 국민연금보험료에 대해 알아봅시다. 국민연금은 근로자 1인 사업자에 근로하면 의무적으로 가입해야 하고, 소득월액의 9%를 연금보험료로 납부합니다. 9%의 국민연금 보험료 중 4.5%는 사업주가, 나머지 4.5%는 본인이 각각 부담합니다. 회사와 직장인이 반반 낸다고 보면 됩니다. 단, 자영업자 등 지역가입자는 본인이 전액 납부해야합니다.

(MongoDB) Sharding (샤딩)

* 샤딩의 목적 1) 데이터의 분산 저장 하나의 서버에 빅 데이터를 저장, 관리하는것은 어렵다. 초당 발생하는 빅데이터를 디스크에 저장할때 발생하는 Write Scaling 문제는 애플리케이션의 성능 저하문제를 유발시키게 될 뿐 만 아니라 샤딩 시스템 전체의 성능 저하 현상을 유발 2) 빠른 성능 분산 처리는 여러 개의 프로세스가 여러 개의 CPU를 통해 동시 작업을 수생했을 떄 가장 이상적이라 볼 수 있다. 3) 데이터의 백업과 복구 전략의 일환 샤딩의 가장 대표적인 기능 중에 하나는 데이터의 분산 저장을 통한 시스템의 성능 향상이라고 볼 수 있다. 만약, 하나의 서버에 빅데이터를 저장, 관리 했을 때 서버의 장애 문제가 발생한다면 유실되어지는 데이터 양은 상상을 초월하게 될 것이고, 시스템을 복구하게 된다면 많은 시간과 비용이 요구 되어 질것이다. ========================================================== 1. 샤딩의 작동 방식 - 샤딩의 구성요소 샤드 클러스터는 샤드, mongos라우터, 설정서버로 구성된다. * 샤드 몽고디비 샤드클러스터는 데이터를 하나 혹은 그 이상의 샤드에 걸쳐서 분산저장한다. 각 샤드는 MongoDB의 복제셋으로 클러스터 전체 데이터의 일부분을 저장한다. *Mongos 라우터 각 샤드가 전체 데이터의 일부분만을 가지고 있다면, 그 일부가 어디있는지 알기 위한 인터페이스가 필요하다. mongos 프로세스는 모든 읽기와 쓰기 요청읋 해당 샤드에 보내는 라우터이다. 그러나 mongos는 지속성이 없는 경량 프로세스이다. 애플리케이션이 실행되는 서버에서 실행됨으로써 각 샤드에 연결되게 된다. *설정서버 mongos라우터가 지속성이 없기 때문에 샤드 클러스터의 상태를 어디선가는 유지하고 있어야 하는데, 그것이 설정 서버(config server)이다. 메타데이터를 지속적으로 유지한다. <컬렉션에 대한 샤딩>

(MongoDB) A single update on a sharded collection must contain an exact match on _id error

In sharding Mongodb cluster If you do CUD working, it is possible to show you next possible A single update on a sharded collection must contain an exact match on _id (and have the collection default collation) or contain the shard key (and have the simple collation). Update request This happend when I did updateFirst query in MongoDB. Beacuse shard cluster does not find where this document, the mongos can not find where it is. actuall UpdateFirst means that to update one document. If Mongos brodcast all shard cluster to update, it is to violate {multi: false} pharse. Therefor, to solve this error, we need to do one of three 1. to add shard key in query 2. to specify "_id" field which is unique key 3. to configure { multi : true }

(MongoDB) A single update on a sharded collection must contain an exact match on _id 에러 상황

샤딩이 된 mongoDb 서버 환경에서 CUD작업이 이루어지면 다음과같은 에러가 발생할 수 있다. A single update on a sharded collection must contain an exact match on _id (and have the collection default collation) or contain the shard key (and have the simple collation). Update request 위 상황은 해당 도큐먼트를 업데이트(updateFirst) 할 때 발생한 상황이다. 이러한 이유는 샤드 클러스터가 해당 도큐먼트가 위치하고 있는 샤드클러스터를 발견하지 못하고 있기 때문이다.   해당 쿼리문에 shard key를 포함하지 않고 있었습니다. 그러므로 해당 도큐먼트를 확인하기 위해서는 모든 샤드클러스터를 확인해야 하는데 mongos는 그 위치를 알아 낼 수 없습니다. 만약 mongos가 모든 샤드클러스터를 brodcast하여 업데이트를 하게 된다면 multi:false라는 구문에 위반되는 상황입니다. 그러므로 위와같은 에러를 방지하기 위해서는 1. shardKey를 추가하거나  2. unique key값인 _id필드를 명시하거나 3. multi : true롤 설정해야 합니다.

(MongoDB) How to use AbstractMongoDBListener (Example)

What is MongoListener? This is eventListener when MongoDB collections has been changed it can help developer do something ( after saving mongodb, elastisearch works next...etc) First of all,  i will show you methods in AbstractMongoDBListener If you want to read detail, you can find it springMongoDB Document. ================================================== void onAfterConvert(AfterConvertEvent<E> event) void onAfterDelete(AfterDeleteEvent<E> event) void onAfterLoad(AfterLoadEvent<E> event) void onAfterSave(AfterSaveEvent<E> event) void onApplicationEvent(MongoMappingEvent<E> event) void onBeforeConvert(AfterConvertEvent<E> event) void onSave(AfterSaveEvent<E> event) ===================================================================== example) I will show you how to use onSave method with overriding This example is  for Listener class when an event is occured from example class class ExampleListener extends A

(MongoDB) AbstractMongoListener Usage example(몽고리스너 사용법)

몽고리스너란, MongoDB 컬렉션에 변화가 발생할 경우 이러한 이벤트에 따라 사용자가 정의한 행위를 실행하는것을 도와주는 이벤트 리스너이다. 먼저, AbstractMongoListener 의 메소드를 설명하겠습니다. void onAfterConvert(AfterConvertEvent<E> event) void onAfterDelete(AfterDeleteEvent<E> event) void onAfterLoad(AfterLoadEvent<E> event) void onAfterSave(AfterSaveEvent<E> event) void onApplicationEvent(MongoMappingEvent<E> event) void onBeforeConvert(AfterConvertEvent<E> event) void onSave(AfterSaveEvent<E> event) 예) Onsave메소드를 오버라이에서 사용하는 방법을 알아보자 이 예시는 Example클래스에 이벤트가 발생했을 때, 일어나는 리스너 클래스이다. Example 클래스에 save가 일어난 후 다음과 같이 특별ㅎ class ExampleListener extends AbstracMongoListener<Example> { @Override public void onAfterSave(AfterSaveEvent<Example> event) {   Example ex = event.getSource();  //이 아래부터 개발자가 원하는 처리를 할 수 있다. } 단, 주의 사항은 onAfterSave같은 경우는 MongoDB에 insert, insertList, save메소드가 발생했을 때만, 이 리스너 메소드가 호출된다. updateFirst, updateMulti, findAndModify가 발생했을 때는 이 메소드가

(Python) DEPRECATION: Uninstalling a distutils installed project (six) has been deprecated and will be removed in a future version. (해결법)

이미지
파이썬에서 특정 패키지 설치시 위와 같은 에러를 발생시키고 있었다. (when I tried to install a package which is pytest, some error is caused) 그래서 다음과 같은 명령어를 이용해 위 에러를 제거하려 하였다 (So I tried to remove this error with next command in macOS) $ pip install --ignore-installed six 그후 원래 설치하려던 pytest를 다시 설치하려 시도하니 (I tried to install again what I want to install prior package) 다음과 같은 에러가 발생하였다. (However error caused again) 위와 같은 에러가 발생하는 이유는 해당 파이썬이 설치된 Os가 Apple에서 제공하는 Homebrew로 설치되어 있기 떄문이다. 즉 파이썬에서 제공하는 pip 시스템과 다르기 때문에 에러가 발생한 것이다. ( The system python is managed by the OS vendor (Apple, Canonical, etc), and is meant to be used by other OS built-in tools. Having pip mess things up in the vendored python is dangerous. ) 그래서 --user옵션을 이용하여 설치하니 정상적으로 설치되었다. (The --user options wors well for my case) $ sudo -H pip install pytest

(Python) pytest 설치하기 (pytest installation in Mac OS)

The Java has a Junit Test Framework.(TDD) It is more generally used in Many Java Programmer. Python has a Pytest Test Tool. It will show you how to install the Pytest Framework. this python version is 3.6 and in Mac OS Before to install the package, you need to install pip Install pytest 1. run the following commnad in your command line: $ pip install -U pytest 2. check that you install the correct version : $pytest --version

(Python) 파이썬 모듈 만들기 (Kr)

Thrid Party 모듈을 공급하고 지원하는 기능은 파이썬 코드 재사용의 핵심 기술입니다. 그래서 파이썬은 개발자가 파이썬 설정에 모듈을 추가할 수 있도록 내장 기능을 제공합니다. 파이썬 표준 라이브러리에 포함된 커다란 모듈 컬렉션은 파이썬 핵심 개발자가 관리하며 많은 사람이 사용하고 원본이 훼손되지 않도록 유지됩니다. 그러므로 개발자가 표준라이브러리에 모듈을 추가하거나 제거하는 작업은 하지 말아야합니다. 그러나 모듈을 사이트패키지에 추가하거나 제거하는 작업은 가능합니다. 파이썬에서는 이와같은 작업을 위해 setup 모듈을 제공합니다. * setup.py이란 무엇인가??(What is setup.py?) ->setup.py is a python file which is usually tells you that module/package you are beneficial about to install has been packaged and distributed with Disutils, which is statndard for Python Modules. This allows you to easily to install Python packages. $ python setup.py install http://docs.python.org/install/index.html 즉, setup.py를 이용해 특정 모듈을 설치하거나, 모듈이나 패키지가 어디에 분포하고있는지 알려주는 표준라이브러리에 있는 파일이다. <setup.py를 이용하는법> 먼저 핵심 단어를 정의할 필요가 있다. package : 폴더/디렉토리가 __init__.py파일을 포함하고 있는것 module : .py확장자를 가지고 있는 파일 Distribution : 하나의 패키지가 다른 파일들과 어떠한 관계를 갖고 있는가 예를들어,  galaxy라는 패키지를 설치한다고 예를들어보자. $ git clone h

(MongoDB) MySql, MongoDB 둘다 적용하는 하이브리드형 개발 주의사항

두 디비를 적용하여 JPA @Transient를 적용할시 주의 사항이 있다. 도메인 객체 클래스에 특정 필드에 @Transient javax.persistence패키지용 어노테이션을 사용하면, 이건 MySql 디비에만 적용된다. 즉, MongoDB에는 위 어노테이션이 적용되지 않는다. 반면, org.springframwork.data.annotation용 Transient를 적용하면 MongoDB에 적용되지만, MySQL에 디비를 붙이는 서버가 올라가지 않는 문제가 있다. 만약 두 디비를 적용하고 한 클래스에서 @Transient어노테이션의 기능을 사용하고 싶다면 JPA용 javax.persistence 패키지의 @Transient를 사용하고, 몽고디비의 converter와 MongoDB Listener을 이용해 몽고디비 저장을 호출하기전 컨터버 기능을 작동해 Reflection을 이용해 위 두 어노테이션으 붙은 필드(변수를) 제거하여 위 기능을 사용하는 방법이 있다. 위 두 어노테이션이 적용되도록 하는 어노테이션을 따로 개발할 예정이다.

(Python) bool형

이미지
파이썬의 모든 객체는 참이나 거짓으로 평가될 수 있습니다. 0, 빈 내장자료구조, 빈 문자열, None등은 모두 거짓으로 평가됩니다. 그 밖의 모든 객체는 참으로 평가됩니다.

(Python) 함수

이미지
파이썬 함수는 다음과 같은 특징을 가진다. 1. def와 return이라는 두 가지 새로운 키워드가 사용된다. 2. 함수는 인자 데이터를 받을 수 있다. 3. 함수 코드와 주석을 붙일 수 있다. (여기서 주석이란 메모를 뜻한다.) 1. 파이썬 함수는 인터프리터가 객체의 유형을 신경쓰지 않는다는 것이다. 즉, 어떤 인자를 받거나 어떠한 객체의 유형을 return해도 신경쓰지 않는다. 파이썬 함수는 def키워드로 시작한다 해당 키워드는 define(정의하다)의 줄임말이라고 보면된다. 다음과 같이 시작한다. 파이썬에서는 문자열을 표현할시 여러 행으로 확장 할 수 없다. 줄바꿈을 할 시 해당 문자열이 종료한다고 생각한다. 문자열을 표현할 때 ' ', ""  "",  """   """" 세가지를 사용하는데 일반적으로 프로그래머는 문자열을 ' ' 이런식으로 사용하며, """ """ 이 의미는 주석으로 사용한다. 1-1. 함수는 인자를 받을 수 있다. 함수 맨 윗부분의 괄호안에 인자를 받을 수 있다. 위 그림처럼 letter이라는 인자를 받아 함수를 처리하고 있다. 함수를 처리하는 곳에 맨 아래부분에 보면 findingvowels라는 함수를 실행시키는데 "EveryBody"라는 인자를 넘긴다. 이 인자는 letter이라는 인자에 대입되어 위 함수가 처리된다. 즉, letter = 'EveryBody'가 된다고 볼 수 있다. 만약 위 함수에 인자를 여러개 넣는다고 가정해보자 즉, findingvowels('EveryBody', 'EveryBody2', 'EveryBody3') 이럴 경우 에러가 발생한다 왜냐하면 함수 선언에 letter이라는 인자 한개만 받고 있

(Python) 튜플 (tuple)

이미지
튜플(tuple)은 리스트처럼 한 번 만들고 데이터를 저장한 다음에는 바꿀 수 없는 자료구조이다. 그럼 왜 튜플(tuple)을 사용할까? 바꿀 수 없는 자료구조가 유용할 때도 있습니다. 특정데이터가 바뀌지 않음으로 부작용을 줄일 수 있습니다. 1. 튜플 vs 리스트 차이점 : 리스트는 대괄호를 사용하지만, 튜플은 괄호를 사용합니다. type을 이용하면 만들어진 객체의 유형을 확인 할 수 있다. 그렇다면 튜플을 바꿀 수 있을까???? vowels[2] = 'I' 로 바꾸려 시도한다면 TypeError를 발생시키게 된다. 즉, 튜플 안에 있는 자료주는 한번 선언되면 바꿀 수 없다. <주의사항> 튜플을 만들 시 단일객체는 만들 수 없다. 다음예제를 보면 ('tuple')로 선언하게 되면 자료형이 str타입이된다. 그러나 콤마(,)를 붙이게 되면 튜플형 자료가 되는 것을 볼 수 있다.

(Python) Set 집합

이미지
파이썬 자료구조 형에는  list, dictionary, set 등 여러가지 자료구조가 존재한다. 그 중 중복된 자료를 포함하지 않는다는 특징을 가지고 있는 set에 대해 설명하겠다. 1. union 2. difference 만약 두 종류의 String형의 자료가 존재한다고 가정해보자. vowels = 'aeiou' word = 'hello' 위 두 자료에서 서로 포함하고 있지 않는객체를 구하고 싶다면 (차집합) difference를 이용하면 된다. 중요한 것은 for문을 사용하지 않고 두 객체의 차이를 구했다는 것이다. 물론 내부적으로는 for문이 사용될 것이라고 생각한다. 위 결과는 vowels에는 포함되어 있지만, word집합에는 포함하고 있지 않다. 수학에서 말하는 "차집합"이라고 보면된다.  difference를 호출하는 첫번째 쪽인 vowels를 기준으로 결과를 도출한다. 3. intersection 세 번째 집합메소드는 한 집합을 다른 집합메소드와 비교하여 어떤 공통 객체가 있는지 알려주는 intersection이다. 정리  파이썬의 집합은 중복을 허용하지 않는다. 딕셔너리처럼 set도 중괄호로 표기합니다. 하지만 딕셔너리는 키/값이 있는 반면 집합에는 키/값 쌍이 없어요. 대신 집합의 고유 객체를 콤마로 분리합니다. 딕셔너리처럼 집합도 순서를 유지하지 않습니다. 순서를 유지하지 않기 때문에 sorted 함수를 이용하면 시퀀스에 있는 객체를 포함하는 집합이 만들어진다. 이때 중복된 데이터는 제거된다.