맛있는 인터넷으로의 세대교체 블로그와 태그 시스템의 데이터베이스 설계
다양한 환경과 웹2.0이 이슈화되면서 웹에서의 서비스 환경은 다양하게 변화하고 있다. 웹 서비스를 위해 뛰어난 데이터베이스를 설계하려면 우선 웹 서비스의 특성을 이해해야 한다. 웹 서비스는 특정 페이지에 트래픽이 몰리기도 하고, 트래픽이 거의 없는 페이지도 있으며, 통계에서는 나오지 않는 검색 로봇(Robot)이나 RSS 크롤러(crawler)에 의해 숨겨지는 페이지에서 더 많은 트래픽이 발생할 수도 있다. 블로그와 태그의 설계 방법을 통해 웹 서비스의 특성을 이해하면서 효율적인 데이터베이스를 설계하고 관리할 수 있을지 생각해보자.
웹 서비스에서 데이터베이스를 가장 효율적으로 운영하는 방법을 극단적으로 말하자면 데이터베이스를 쓰지 않는 것이다. 다시 말하면 꼭 필요한 부분에서만 쓰고 그 외의 서비스는 쓰지 말아야 한다는 의미이다. 데이터베이스를 쓰지 않아도 되는 로우 데이터(Row Data)에 의해 다른 퍼포먼스를 내야 되는 데이터베이스에 영향을 주어서는 안 된다.
그리고 웹 서비스에서의 데이터베이스는 생각하는 것만큼 관계형 데이터베이스를 잘 표현하지 못한다. 특히 트래픽이 많은 웹 서비스를 구현 할 때는 더더욱 그렇다. 웹 서비스의 데이터베이스를 가장 설계를 잘했다고 말할 수 있으려면 가공되지 않은 로우 데이터를 웹서버에 그대로 보내도록 설계해야 한다. 데이터베이스에 의해 원하는 표현 방식으로 가공된 데이터를 뿌려주도록 설계하는 것은 가장 낮은 퍼포먼스를 내는 지름길이다.
필자의 경우 한때는 편집증이란 소릴 들을 만큼 이런 부분에서 조심한 적도 있다. 웹 서비스에서 심한 트래픽으로 인해 데이터의 과부하를 경험해 본 개발자라면 쿼리 하나를 날리는 데에도 상당히 조심스러워 질 것이다. 서비스를 구현하고 있다면 특히 그렇다. 심지어 그룹 바이(Group by)를 쓰는 것도 조심스럽고 트랜잭션(Transaction)을 걸어야 할 때는 하루정도 고민한 적도 있다. 데이터베이스 때문에 느려질 염려가 없다는 이유로 클러스터 인덱스(Cluster index)되지 않은 오더링(Ordering)을 하지 않기 위해서 오더링 되지 않은 로우 데이터를 웹에 그냥 던져주고 웹에서 오더링을 구현한 적도 있다.
그룹 바이나 해빙(having), 유니온(Union), 낱 인(not in), 라이크(Like) 등은 관리자용 SQL언어이지 웹 서비스에서 표현할 수 있는 SQL은 아니라 생각했던 적도 있다. 지금도 아니라고는 말 못하겠다.
요즘은 데이터베이스의 효율성을 높이기 위해 MMDBMS를 비롯하여 여러 솔루션들이 많이 등장하고 있다. 하지만 대부분의 가난한(?) 개발자에게는 이런 솔루션을 비싼 돈을 주고 적용시켜 볼 여력이 없다. 어떻게든 최소한의 비용으로 최대한의 효율을 내는 방법만을 고민할 뿐이다. 게다가 웹 서비스에서의 데이터베이스는 장비의 성능에 그다지 영향을 받지 않기 때문에 데이터베이스의 설계나 인덱스 하나를 잘 만드는 것이 장비를 업그레이드 하는 것 보다 더 높은 퍼포먼스를 낼 수도 있다.
웹2.0의 데이터베이스
갑자기 웹2.0이라는 말이 홍수처럼 밀려오면서, 개발자들이 이러한 개념을 받아들이기는 꽤나 어려웠을 것이다. 그리고 요즘 새로 만들어지거나 개발 중인 서비스에서 웹2.0을 기반으로 서비스를 오픈하는 경우가 많다. 개발자적인 입장에서 웹2.0의 웹 서비스들을 살펴보면. 몇 가지 주요한 특징이 보인다.
첫째, 대부분의 정보가 사용자에 의해 생산된다.
둘째, 생산된 정보는 그 사용자나 다른 사용자들에 의해 분류되어진다.
셋째, 생산된 정보들은 그 분류를 통해 서로 관계(relation)를 맺는다.
이런 관점에서 보면 웹2.0의 데이터는 살아있다고 할 수 있다. 서비스를 만드는 입장에서 이런 데이터를 어떻게 분류할 것이며 어떻게 관계를 맺는지에 따라 그 데이터는 죽을 수도 있고 가치 있는 삶을 누릴 수도 있다. 그 만큼 웹2.0에서 데이터의 생산, 분류와 관계는 가치가 있으며, 사용자의 노력이나 서비스의 구현 방법에 따라 데이터의 평가가 달라진다.
기존의 웹이나 시맨틱 웹은 리스트 구조의 로그를 연상시킨다. 게시판처럼 리스트를 보여주고 검색을 통해 결과를 추출해내며, 컴퓨터에 의해 자동으로 정보를 생산하거나 수집하게 한다. 하지만 웹2.0에서의 데이터는 엄청난 양의 정보를 유저가 직접 생산해 내고 분류하며, 그 분류를 통해 관계를 성립하게 된다.
처음 웹2.0이란 말이 나올 때 지극히 개발자적인 섣부른 생각으로 웹2.0은 검색을 개발할 수 없는 여건에 있는 가난한 업체들의 컨소시엄이나 상술처럼 보이던 적이 있다. 하지만 절대 그렇지 않다. 처음 정보를 생산하는 동시에 그 생산된 정보는 이런 분류나 관계를 통해 가치 있는 정보가 되고, 유저의 아이덴티티(identity)을 높여주는 역할을 한다. 이것은 정보를 생산하는 사용자에게있어 얼마나 가치 있는 일인지 모른다. 그러한 사이클 때문에 사용자는 더 많은 정보를 생산하게 된다.
이렇게 웹2.0이 이슈화 되면서 개발자들은 엄청나게 쏟아져 나오는 정보들을 분류하고 관계를 맺어줘야 하는 어려운 숙제를 떠맡게 되었다. 가공된 검색의 로우 데이터로서가 아닌 진정한 분류 및 관계를 형성해줘야 하는 역할은 개발자들에게 있다. 또, 이렇게 생산된 로우 데이터를 효율적으로 설계하고 관리하는 것 역시 개발자의 몫이다.
자 그럼 이제 웹2.0의 대표적인 서비스라 할 수 있는 블로그와 태그 시스템을 통해 데이터 생산과 분류, 관계를 어떤 형태의 데이터베이스로 설계하는 것이 효과적인지 알아 보자.
정보를 생산해내는 블로그의 설계 방법
웹2.0에서 유저들이 정보를 생산하는 툴로써 가장 많이 사용하고 있는 것은 바로 블로그이다. 정보를 생산하는 입장에서의 블로그의 설계 방식을 살펴보자. 또, 어떻게 하면 효과적으로 정보를 모으고 용량이 크거나 많은 트래픽에서도 효율적으로 데이터베이스를 관리할 수 있는지에 대해서도 함께 고민해 본다.
단일 데이터베이스에서의 블로그 스키마
<그림 1>은 블로그가 가진 중요한 속성들을 표로 만든 것이다. 그림의 Blog_info에는 블로그에 대한 기본 정보 데이터가 들어가 있고, Blog_post는 블로그에 사용자가 직접 생산한 데이터들이 있다. Blog_trackback은 blog_post에 올라온 글에 대한 다른 블로거들의 의견이 있으며, Blog_comment는 blog_post의 글에 대한 코멘트이다.
사용자는 포스트를 통해 UCC(User Created Contents)를 계속 생산해내고, RSS를 통해 배포하며 태그나 카테고리를 통해 분류하거나 관계를 형성한다. 또, 트랙백(trackback)이나 코멘트(comment)를 통해 커뮤니티를 형성하기도 한다.
<그림 1>의 블로그 데이터베이스 구조는 설치형 블로그들이 일반적으로 가지고 있는 데이터베이스의 구조이다. 하나의 블로그 또는 소규모의 커뮤니티를 운영하는 곳에서는 유용한 구조이다.
블로그를 설계할 때 RDBMS 제품군을 이용하지 않고 블로그를 구성하는 방법을 생각해 볼 수도 있을 것이다. 예를 든다면 mdb와 같은 파일 DB로 하나의 블로그당 하나의 파일 DB를 생성해주는 방법이다. 이렇게 하면 백업하기도 쉽고 익스포트(export)나 임포트(import)하기도 쉽다. 블로그를 생성할 때 mdb를 하나 만들어주면 그만이니 만들기도 간단하다. 트래픽이 몰려도 트래픽을 분산시키느라 고민할 필요도 없고, 새로운 서버에 디렉토리만 이전하면 트래픽 분산이 가능하다. 또, 인덱스를 걸지 않아도 혼자 쓰는 DB인데 부하가 있어도 얼마나 있겠는가.
하지만 회원가입을 받는 웹 서비스를 만들 때 이런 방법은 사용할 수 없다. 커스터마이징 하거나 오류가 있을 때 고치거나, 버전업하기도 힘들고 일괄 관리도 힘들다. 만약 설치형 블로그 툴을 만들고자 한다면 성능 좋은 파일 DB들이 많이 있으니 한번 생각해 볼만하다.
그리고 <그림 1>과 같은 구조로 서비스하는 블로그 서비스 중 로우 데이터만 데이터베이스에 저장하고 있고, 표시되는 페이지는 정적인(Static) Html로 만들어 제공하는 곳도 있다. 다시 정리해 보자면 <그림 1>과 같은 구조는 데이터의 양이 많아졌을 때 해결 방법을 제공하기 어려운 탓에 대규모 서비스의 블로그 형태로는 접합하지 않다.
<그림1> 블로그 스키마1
기능별로 분류한 블로그 스키마
<그림 2>는 각 블로그의 주요 특성에 의해 분류한 것이다. 초창기 카페나 동호회가 이런 구조로 만들어 졌다. 어느 정도 트래픽을 분산시킬 수도 있고, 각 블로그 간의 관계를 형성하거나 통합된 정보를 보여주기에 용이하다. 예를 들면 내가 링크한 블로그의 새로 올라온 글을 보거나 트랙백을 볼 때, 특정 분류의 관계된 정보를 보여주기에 편리한 구조이다. 게다가 트래픽도 어느 정도 분산시킬 수 있는 구조이다. 하지만 여러 가지 이유 때문에 blog_post 등에 트래픽이 집중될 경우 데이터를 분산시키기 어렵다는 단점을 가지고 있다.
<그림2> 블로그 스키마2
블로그 아이덴티티에 의해 분류한 블로그 스키마
<그림 3>은 <그림 1>에서 데이터베이스를 블로그의 특정 ID값에 의해 나눈 것이다. 각 블로그 ID에 분류 가능한 고유의 아이덴티티 값을 부여하고, 분류가능한 값에 의해 블로그가 어느 데이터베이스에 만들어 질지를 정한다.
<그림3> 블로그 스키마3
예를 들어 blogid의 맨 처음 문자를 분류 가능한 코드로 만들고 나머지를 일련번호로 구성한 blogid 값이 있다고 하면, blogid가 10000001이면 blog1 데이터베이스에, blogid가 30001234이면 blog3 데이터베이스에 들어가게 된다. 이 구조는 블로그의 특징을 잘 표현해서 보여주는 분류이다. 그리고 blog1, blog2, blog3는 같은 데이터베이스 구조를 가지고 있기 때문에 확장하기도 용이하고 트래픽이 몰리는 데이터베이스를 조절할 수 있다. 만약 관리자에 의해 트래픽을 예상하고 모니터링 할 수 있으면, 더 효율적으로 트래픽을 분산시키는 구조도 만들어 볼 수 있을 것이다.
블로그 관리 툴에 의해 분류한 블로그 스키마
<그림 4>에서 Blog_admin은 관리용 데이터베이스이다. blog1, blog2, blog3 등 블로그 데이터베이스의 총 블로그 개수, 블로그 포스트 개수 등 블로그에 관련된 정보들을 가지고 있다. 그리고 스타트 서버(stat server)나 애드 서버(ad server)를 운영하고 있는 서비스의 경우 해당 블로그의 데이터베이스 트래픽까지도 blog_admin에서 확인할 수 있다.
또, 현재 어느 데이터베이스의 트래픽이 많은지 로우 데이터는 어디에 많이 쌓이는지도 파악할 수 있다. blog_admin을 통해 나온 자료를 바탕으로 앞으로 만들어질 블로그를 어느 데이터베이스에 생성할 것인지를 정할 수 있는 것이다. 어떻게 보면 blog_admin 데이터베이스가 로드 밸런싱(road balancing)의 역할을 한다고 볼 수도 있다.
간혹 blog_admin을 보고 아무리 관리를 잘한다고 하더라도 예상치 못하게 어느 블로그의 데이터베이스에 트래픽이 몰리는 경우도 있다. 이런 경우도 데이터베이스 단위로 쉽게 백업과 리스토어를 할 수 있어 데이터베이스 서버간의 이동 또한 상당히 자유로운 편이다. 트래픽이나 관리자의 의도에 따라 전략적으로 데이터베이스를 이동할 수 있는 것이다.
잘 살펴보면 블로그도 일정한 생명주기를 가지고 있다는 점을 알 수 있다. 일괄되게 처음 만들 때부터 블로그를 잘 쓰고 있는 경우도 있겠지만, 많은 블로그 사용자들의 주기는 1년을 넘지 않는다. 이런 블로그를 위해 많은 노력이 필요하겠지만 노력만으로 해결할 수 없는 문제들에 봉착하게 마련이다.
이런 경우 blog1, blog2, blog3 순으로 계속 해서 분산 시키며 운영하게 될 경우 시간이 지나면 blog1의 트래픽은 많이 떨어질 것이다. 이때 blog_admin 데이터베이스를 통해 다시 트래픽을 blog1로 보내주는 구조도 가능해진다.
<그림 4>의 구조는 대용량의 트래픽도 쉽고 유연하게 대처할 수 있다. 하지만 블로그 간의 관계를 맺기가 어렵다는 문제가 있다. 예를 들면 사용자가 RSS로 등록한 블로그의 최근 포스트를 보고 싶을 때 blog1, blog2, blog3… 등을 모두 선택해야 하는 아주 비싼 쿼리를 날려야 한다. 하지만 이 쿼리는 가장 많이 쓰이는 쿼리 중 하나이다.
특히 데이터베이스가 서버단위로 분리가 되어 있을 경우는 더더욱 어려워진다. 데이터베이스간의 연결(join)은 웹서비스에서는 피해야 하는 쿼리 중에 하나이다.
<그림4> 블로그 스키마3-1
블로그 간의 관계형성이 가능한 블로그 스키마
<그림 5>의 구조는 블로그를 생성할 때나 blog_post를 쓸 때 blog_info와 blog_post의 정보를 blog_total에 똑같은 데이터를 복사한다. 그래서 blog_total에는 모든 생성된 블로그의 정보를 blog_info_total을 통해 가지고 있으며, blog_post 또한 blog_post_total을 통해 가지고 있다. 그래서 필요한 쿼리(개인 블로그나 RSS)는 blog1, blog2, blog3 각각의 데이터베이스를 통해 정보를 수집하고, 통합된 정보를 읽거나 최근에 올라온 포스트를 확인하는 경우 blog_total 데이터베이스를 통해 정보를 얻을 수 있다. Blog_total 데이터베이스는 각 블로그 간의 연결 고리 역할을 한다.
이때, blog_total의 데이터양이 많아질 우려가 있지만 이것은 블로그의 특성이나 웹 서비스의 특성을 잘 이해하고 있다면 크게 염려할 문제는 아니다. blog_total의 blog_post_total은 최근 1개월 정도의 포스트 자료만 가지고 있어도 유저들이 보고 싶어 하는 정보의 99%는 보여줄 수 있다. 그리고 1개월 후의 데이터는 스케줄러에 의해 삭제한다.
지금까지 블로그의 스키마(Schema)를 설명하고 데이터를 효율적으로 생산하고 분산하는 방법에 대해 몇 가지 예를 들어 설명해 보았다. 물론 앞에서 설명한 방법 이외에도 훨씬 다양하고 잘 설계된 블로그 서비스들도 많다. 특히 웹 서비스는 너무나 많은 환경과 변수, 요구사항들이 발생하기 때문에 같은 서비스라도 다양한 설계 방법이 나올 수 있다. 앞에서 설명한 블로그의 설계 방법은 여러 방법 중 일부라는 점을 잊지 말고, 자신의 기준에 맞는 서비스를 설계하는 것이 가장 중요하다.
<그림5> 블로그 스키마3-2
정보를 분류하고 관계를 맺는 태그 시스템
블로그와 더불어 태그는 웹2.0에서 정보를 분류하고 재생산 하고 관계를 맺는 도구로 최근 가장 이슈가 되고 있는 서비스이다. 요즘 새로 오픈하는 서비스들의 대부분이 태그를 통해서 정보를 분류하여 보여주는 방법을 사용하고 있다.
태그 시스템은 많은 개발자들에 의해 구조화 되어 왔으며 각 개발자들의 방식을 발전시켜가며 정형화되고 있다. 하지만 데이터베이스를 통한 거대(Scale)한 태그 시스템을 만드는 방법에 대해서는 아직 누구도 뚜렷한 해답을 내지 못하고 있으며 여러 논의만 진행되고 있는 상황이다.
del.icio.us 메일링 리스트에 “누군가 del.icio.us의 데이터베이스 스키마에 대해 좀 알려주세요” 같은 질문이 종종 올라온다고 한다. del.icio.us의 개발자인 조슈아 샤흐터(Joshua Schachter)의 인터뷰를 보면 이런 말이 있다.
“나는 mod_perl, HTML::Mason, 그리고 MySQL. 주로 사용한다. 이들은 매우 전형적인 툴이다. 최근 그 로드를 유지하기에는 몇몇 문제점을 가지고 있다. 그래서 지금 새로운 아키텍쳐를 찾고 있는 중이다. 태그는 표준 RDBMS로는 만족스럽게 표현하지는 못 한다”
맨 마지막 문구는 조슈아 샤흐터가 인터뷰나 메일의 답변을 통해 자주하는 말이 있다. 데이터베이스를 설계하는 입장에서는 다소 실망스러운 말이겠지만, 많은 웹 서비스의 경우 특히 큰 규모의 웹 서비스에서는 RDMBS로 구현하기 힘든 부분이 많이 있다.
조슈아 샤흐터는 이런 말도 한다.
“빠른 최적화는 피하라”
물론 요구분석에 따른 설계는 철저히 해야 하지만, 결과를 미리 예측하고, 섣부른 판단으로 최적화(optimize)하는 것보다 하나하나 부딪히며 경험을 통해 재설계(rearchitechting)하는 방법이 기술을 가장 빨리 습득하고 업무도 가장 빨리 진행할 수 있는 지름길이 된다(물론, 욕도 많이 먹는다).
이제 많은 개발자들로부터 커스터마이징 되고 있는 태그 시스템의 여러 가지 구현 방법에 대해서 이야기 해보자. 이 방법들 중 자신이 만들려고 하는 서비스에 적합한 방법을 찾고, 큰 규모의 태그 시스템을 구현할 수 있을지에 대한 해답도 찾아보기 바란다. http://tagschema.com/blogs/tagschema/에서는 태그의 구성요소를 <그림 6>과 같이 정의하고 있다.
<그림 6>에서 말하는 세 가지 구성요소로써의 태그 시스템의 구성은 특히, 연관관계는 굉장히 어렵고 복잡하다. 그리고 대부분의 웹 서비스들이 위의 세 가지 구성요소에서 태그 시스템을 구현하는 경우는 거의 없다.
<그림 7>은 우리가 일반적으로 생각하는 태그의 구조이다. 여기에서 사용자는 아이템과 태그에 종속적이다. 아이템은 태그로 분류할 수 있는 모든 단위를 뜻한다. <그림 7>에서의 user라는 구성요소로 관계설정 필요하다면 보통은 아이템 중 하나의 종류로 들어갈 수 있다.
아이템은 포스트가 될 수도 있고, 사진이나 북마크가 될 수도 있다. 그리고 태그가 아이템의 한 종류가 될 수도 있다. 아이템과 태그의 관계는 ‘Item(1-many) <---------> (0-Many)Tags’이다. 아이템이 태그를 0개 이상 가질 수도 있지만 태그는 아이템이 없이는 따로 존재할 수 없다.
태그 시스템에서 가장 일반적으로 쓰이는 관계를 설정하고 그에 따라 각 태그의 구조를 쿼리로 분석해보자.
1. Item(tag) : tag가 가지고 있는 Item List
2. Tag(item) : item이 가지고 있는 Tag List
3. Tag( ) : 중복을 허용하지 않는 모든 Tag list
현재 서비스 중인 대부분의 태그 서비스가 표시되는 방식은 이 세 가지 표현으로 소화할 수 있다. 이제 이 세 가지 관계를 통해 각 태그 스키마의 구현 방법에 대해 알아보자. 또, 앞으로 나올 태그 스키마의 이름은 http://www.pui.ch/phred/archives/ 2005/04/tags-database-schemas.html에서 나온 이름을 붙일 것이다.
‘MySQLicious Solution’ 태그 스키마
<그림 8>의 구조는 태그에 관한 스키마를 따로 구성하지 않은 형태이다. 하나의 테이블로 구성되어 있으며 분류로서의 태그를 구현했다기 보다 아이템에 대한 키보드와 비슷한 개념의 구조이다. 대부분의 태그에 대한 분류는 풀텍스트 서치(fulltext search)로 구현될 수 있지만 비용이 아주 많이 든다는 단점이 있다.
<리스트 1> MySQLicious relation query
Item(tag)
SELECT * FROM Item WHERE tags like ‘%blog%’
Tag(item)
SELECT tags FROM Item WHERE Itemid = ‘1’
Tag()
Query로 표현하기 힘들다.
‘Scuttle Solution’ 태그 스키마
<그림 9>처럼 태그에 대한 스키마를 정의해 놓으면 ‘MySQLicious’ 보다 효율적인 분류가 가능해 진다. 두 개의 테이블로 구성되어 있으며, 대부분의 서비스들은 이런 스키마를 ‘카테고리’라는 기능으로 구현한다.
이 구조의 스키마는 위의 관계를 표현하는 데에만 적용한다면 참 좋은 스키마 구조이다. 하지만 보다 기능적인 태그의 관리를 하고 싶다면 스키마로는 부족한 점이 많다.
<그림6> 태그의 구성요소
<그림7> 일반적인 태그 구조
<그림8> 태그 스키마 1 (MySQLicious)
<그림9> 태그 스키마 2 (Scuttle)
<리스트 2> Scuttle relation query
Item(tag)
SELECT i.* FROM Item i, Tag t
WHERE i.itemid = t.itemid AND t.tagname = ‘blog’
Tag(item)
SELECT t.tagname FROM Item i, Tag t
WHERE i.itemid = t.itemid AND t. itemid = ‘1’
Tag()
SELECT tagname FROM Tag
GROUP BY Tagid
‘toxi Solution’ 태그 스키마
<그림 10>의 구조는 ‘Scuttle’보다 태그 관리를 유용하도록 하기 위해 태그 테이블을 하나 더 두고 있다. 태그 맵은 아이템과 태그의 게이트웨이와 같은 역할을 한다. 태그 테이블은 태그를 다양한 방법으로 관리할 수 있도록 도와준다. 태그 서비스의 대부분은 ‘toxi’의 구조를 적용하고 있다.
<그림10> 태그 스키마 3 (toxi)
추가(Insert)나 갱신(UPDATE) 비용이 다른 스키마구조 보다 많이 들기는 하지만 그 비용보다는 선택(SELECT)의 비용이 훨씬 줄어들고 전체의 태그를 보여 주거나 태그에서의 링크 순으로 표시할 때 효과적으로 관리할 수 있다.
<리스트 3> toxi relation query
Item(tag)
SELECT i.* FROM Item i, Tagmap tm, Tag t
WHERE t.itemid = tm.itemidAND tm.tagid = t.tagid AND t.tagname = ‘blog’
Tag(item)
SELECT t.tagname FROM Item i, Tagmap tm, Tag t
WHERE i.itemid = tm.itemid AND tm.tagid = t.tagid AND i.itemid = ‘1’
Tag()
SELECT tagname FROM Tag
<그림 10>과 같은 구조의 ‘toxi’에서 약간의 테이블 구조를 변화 시키는 것만으로 자신의 서비스에 맞는, 아니면 경우에 따라 비용이 많이 절감될 수 있는 태그 스키마도 제공해 줄 수 있다.
<그림11> 태그 스키마 3-1 (toxi1)
<그림 11>은 <그림 10>에서 Tagid를 없애고 tagname을 기본 키로 두면서, Item에 Tags 필드를 추가한 구조이다. 이 구조는 테이블간의 연결을 많이 줄일 수 있는 구조이다. 하지만 추가(Insert), 갱신(Update), 삭제(Delete)의 비용이 ‘toxi’보다 두 배 이상 더 비싸다. 한편, 이용 패턴의 대부분이 선택(Select)에 편중되어 있기 때문에 서비스의 흐름을 파악한다면 오히려 비용을 줄일 수 있는 여지도 많이 보이는 구조이기도 하다.
<리스트 4> toxi relation query 2
Item(tag)
SELECT i.* FROM Item i, Tagmap tm
WHERE i.itemid = tm.itemidAND tm.tagname = ‘blog’
Tag(item)
SELECT tags FROM Item WHERE itemid = ‘1’
Tag()
SELECT tagname FROM Tag
<그림 11>과 같은 스키마 구조에서의 선택과 추가 등의 비용을 비교해보자.
선택(Select) 비용 : MySQLicious > Scuttle > Toxi > Toxi1
추가(Insert), 갱신(Update), 삭제(Delete) 비용 : MySQLicious
< Scuttle < Toxi < Toxi1
자신이 개발할 태그 시스템의 규모와 용도를 파악하고 위의 스키마를 커스터마이징 한다면, 분명 효과적인 태그 시스템을 개발 할 수 있을 것 이다.
마지막으로 앞에서 설계한 블로그의 포스트를 예로 Toxi 솔루션을 적용해보자.
Toxi 솔루션을 블로그에 적용하기
<그림 12>는 블로그의 스키마에서 나온 blog_post에 태그 스키마를 적용한 모습이다. 이 예에서는 블로그의 포스트를 기준으로 태그를 적용한 모습이지만 다른 아이템에서도 적용되는 모습은 대부분 비슷할 것이다. 그리고 <그림 12>에서 태그 맵과 태그 테이블을 잘 이용한다면 서비스를 이용하는 모든 사용자의 태그와 그 태그에 대한 모든 분류의 정보를 얻고, 사용자에게 어떠한 태그가 가장 인기 있는지의 여부도 파악할 수 있다.
<그림12> blog_post에 테그 스키마를 적용한 모습
<리스트 5> Blog tag relation query
Item(tag)
SELECT b.* FROM blog_post b, Tagmap tm
WHERE b.blogid = ‘10000002’AND b.blogid = tm.blogid AND b.blog_serial = tm.blog_serialAND tm.tagname = ‘blog’
Tag(item)
SELECT tags FROM blog_post
WHERE blogid = ‘10000002’ AND blog_serial = ‘123’
Tag()
SELECT tagname FROM Tag
WHERE blogid = ‘10000002’
지금까지는 한 가지 아이템으로서 태그와의 관계를 구성해 보았다. 같은 태그로 구성된 여러 아이템이 있다고 가정해보자. 블로그를 예로 들면 아이템으로 활용가치가 있는 것 중 포스트, 사진, 블로그 심지어 태그까지도 아이템으로 묶을 수 있다. 특히 블로거라면 이처럼 서로 다른 아이템을 태그를 통해 한꺼번에 분류하고 싶어할 수도 있다. 아이템으로서의 태그도 중요한 개념이긴 하지만 태그는 다른 태그와 조합하여 새로운 아이템으로 구성할 수 있다는 장점을 가지고 있기 때문이다.
이렇게 여러 아이템에 대한 태그와 관계를 스키마로 표현하는 것도 상당히 의미 있고 재미있는 일이다. 이렇게 하는 데에는 여러 가지 방법이 있다. ‘toxi’ 스키마를 예로 든다면 각 아이템마다 태그 맵 테이블과 태그 테이블을 따로 두고 연결(Union)하는 방법도 있고, 태그 맵에 각 아이템의 특성을 구분할 수 있는 필드를 추가하여 분류할 수도 있다. 많이 복잡하고 어려울 수도 있지만 기술적으로 가능하다면 충분히 설계할 만한 가치가 있는 분류 방법이다.
지금까지 태그 시스템에서 알아본 방법은 가장 일반적으로 사용되고 있는 스키마의 형태이다. 아직도 계속 이런 스키마에 대해서 연구 중이다. 태그 시스템을 DBMS가 아닌 파일 시스템으로 구현해 놓은 곳도 쉽게 찾을 수 있다.
현재의 웹 환경은 이전과 달리 다양하고 복잡한 스키마 구조를 요구한다. 그리고 쏟아지는 데이터의 분량 또한 엄청나다. 이러한 데이터들은 태그나 다른 툴에 의해 분류되고 공유되어 진다. 지금까지 블로그와 태그 시스템을 통해 그러한 웹 환경의 일부분을 살펴보았지만 앞으로는 더욱 다양한 서비스들이 쏟아져 나오고 우리들이 해야 할 일도 늘어날 것이다. 앞서 말한 것처럼 이러한 웹 환경에서 유저들이 생산해내는 정보나 데이터의 가치를 더 높여주는 것이야 말로 개발자들이 해야 할 몫이다.
참고자료
1. http://www.pui.ch/phred/archives/category/tags/
2. http://tagschema.com/blogs/tagschema/
3. http://www.randsinrepose.com/archives/2004/12/03/a_delicious_interview.html
스핑(Sping-트랙백 스팸)
‘핑 스팸’이라고도 부르는 스핑은 최근 블로그 사용자가 늘어나면서 골칫거리가 되고 있다. 대부분의 스핑은 트랙백을 통해 이뤄진다. 다른 방법으로 핑백(pingback)과 코멘트를 사용할 수 도 있지만, 핑백은 거의 사용하지 않고 코멘트는 관리자가 충분히 막을 수 있어 의미가 적다. 그 밖의 다른 몇 가지 방법도 대부분 막을 수 있는데 유독 트랙백 스팸만은 대책이 거의 없다. 다음은 이러한 스핑 문제를 해결하기 위해 블로거들이 내놓은 해결책이다.
● 오래된 퍼머링크에는 핑 수신을 하지 못하게 한다
대부분의 스팸은 최근 글에 쌓이지 않고 오래된 이전 글에 쌓이는 특성이 있다. 이 부분은 블로그들의 관리에 의해 오래된 글에 대해서는 핑 수신을 하지 못하도록 하여 스팸 트랙백을 막을 수 있다. 하지만 이는 퍼머링크라는 의미를 퇴색시키는 일이기도 하다.
● 존재하는 퍼머링크에만 핑 수신을 가능하게 한다
존재하지 않는 퍼머링크에 대해서는 트랙백이나 코멘트를 받지 못하도록 설정한다. 이 부분은 매우 중요하다. 하지만 많은 블로그 서비스들이 이 부분을 간과하는 경우가 많다. 대부분의 스펨은 일련번호 형식으로 자동으로 주소를 부여해서 핑을 보내기 때문에 존재하지 않는 퍼머링크에 대해서 스팸 핑을 보내는 경우가 대부분이다.
● 트랙백 주소를 어렵게 만든다
앞의 방법에 이어서 실행할 수 있는 방법으로 퍼머링크의 주소와 다르게 알기 어려운 랜덤한 트랙백 주소를 부여하는 방법이 있다. 이 방법을 통해 자동으로 보내지는 스팸의 많은 부분을 차단 할 수 있다.
● 블랙리스트의 ip, header, url등을 체크한다
현재도 많은 blacklist들의 ip 및 url정보들이 공유되고 있다. 그리고 자신의 블로그에 많이 보내어지는 spam들의 ip와 url등을 체크해서 막고, 공유함으로써 spam을 차단하는 방법이다.
● 스팸 필터를 이용한다
현재 설치형 블로그들에서는 플러그인 형태로 제공하는 많은 스팸 필터 도구들이 있다. 이런 도구는 블랙리스트 ip에 대한 필터와 함께 특정 단어가 들어가 있는 것들을 막는 방법으로 트랙백 스팸을 필터링한다.
● 전송된 IP와 트랙백 주소를 비교한다
대부분의 스팸은 보내는 IP주소와 알리고자하는 도메인이 일치하지 않는다. 대부분의 스패머(spammer)들은 오픈 프락시를 통해 스팸을 보내고 있다. 이와 같이 둘의 비교로 인해 많은 스팸을 줄일 수 있다. 하지만 이 경우도 이런 프락시를 통하는 정상적인 블로그가 스팸으로 간주될 수 있다.
'IT > Tips' 카테고리의 다른 글
원노트 실행시 "Microsoft OneNote 작동이 중지되었습니다" 오류 해결방법 (14) | 2010.12.07 |
---|---|
Microsoft 온라인 기술 컨퍼런스 (0) | 2010.12.07 |
핸드폰 나밍&개통일 확인하는 법 (0) | 2009.05.28 |
엔지니어형 프로그래머와 문학적 프로그래머, 그리고 게으른 프로그래머 (0) | 2009.03.31 |
당신의 프로그램에 버그를 번식시키는 요인들 (0) | 2009.03.31 |
댓글