저작권 안내: 저작권자표시 Yes 상업적이용 No 컨텐츠변경 No

스프링5 입문

JSP 2.3

JPA 입문

DDD Start

인프런 객체 지향 입문 강의

팀에서 했던 빅데이터 개요 발표 자료


Posted by 최범균 madvirus

댓글을 달아 주세요



Posted by 최범균 madvirus

댓글을 달아 주세요

조회수, 좋아요. 이 두 값은 전형적인 카운트이다. 글을 읽거나 좋아요 버튼을 누를 때 마다 값이 1씩 증가하는 특징을 갖는다. 예를 들어, 게시글의 경우 다음과 같이 '조회' 수와 '좋아요' 수를 갖는데, 이들 값은 사용자가 글을 조회하거나 '좋아요'를 할 때 마다 1씩 증가하게 된다.


public class Article {

    ...

    private int viewCount;

    private int likeCount;

    ...

}


카운트와 캐시


이제 서비스에 있어서 캐시는 기본이 된 듯 하다. 급증하는 트래픽을 장비로만 막는데는 한계가 있기 때문에, 캐시는 반드시 고려해야 하는 대상이다. 이 캐시를 적용할 때 개발자를 짜증나게 만드는 것이 있는데, 그것은 바로 카운트 방식의 값이다.


예를 들어, 게시판에서 하나의 게시글을 Article 이란 모델로 표현했다고 할 경우, 게시글은 읽기만 해도 증가하기 때문에 Article 및 Article의 List를 담고 있는 캐시는 글의 조회수가 증가될 때마다 캐시에서 제거되어야 한다. (또는 백엔드에서 다시 값을 읽어와 캐시에 넣어야 한다.) 조회수 증가가 크지 않은 사이트는 이렇게 하더라도 전혀 문제가 되지 않겠지만, 캐시를 도입하는 이유는 트래픽이 많아졌기 때문이다. 그런데, 트래픽이 많아졌다는 것은 특정 게시글에 대한 조회 요청이 많다는 것을 의미하고, 이는 조회수의 증가가 발생한다는 것을 의미한다. 조회수의 증가는 캐시에 보관된 게시글 정보가 더 이상 유효하지 않다는 것을 의미하므로 캐시에서 게시글 정보 또는 관련 게시글 목록 정보가 캐시에서 제거된다는 것을 뜻한다. (조회수에 민감하지 않다면 캐시에 보관된 데이터를 일정 시간 동안 사용할 수 있겠지만, 실제로 고객들은 조회수, 좋아요 등의 숫자에 매우 민감하기 때문에 제대로 반영해 주어야한다.) 캐시에서 제거되었으므로 결국 DB에서 다시 읽어와 캐시에 담게 된다. 하지만, 조회수가 증가하기 때문에 결국 다시 캐시에서 제거되고 DB에서 읽어와 캐시에 담는 과정이 반복될 것이다.


트래픽이 증가해서 캐시를 적용했는데, 카운트 증가 때문에 캐시 효과가 없어지는 어처구니 없는 상황이 발생하는 것이다. 사실, 게시글의 내용과 카운트 값은 변경의 빈번도가 완전히 다르다. 제목과 같은 내용은 변화 빈도가 낮은 반면에 카운트 값은 특정 기간 동안에 빈번도가 굉장히 높다.


카운트의 분리


따라서, 특정 컨텐츠에 대한 캐시 효과를 극대화하려면 카운트 류의 값을 별도로 분리해주어야 한다고 생각한다. 예를 들어, 게시글의 경우 다음과 같이 두 개의 모델로 분리한다.



즉, 내용을 담고 있는 Article과 해당 Article의 카운트 값을 갖는 ArticleCount로 구분할 수 있을 것이다. ArticleCount의 id는 Article과 동일한 id를 가질 것이다.


Article과 ArticleCount가 분리되었으니, 이 두 객체를 다루는 서비스도 분리된다.


public interface ArticleService {

    public Article getArticle(Long id);

}


public interface ArticleCountService {

    public ArticleCount getArticleCount(Long id);

    public void increaseViewCount(Long id);

}


조립하기


완전한 게시글 읽기 기능은 Article과 ArticleCount를 필요로 하므로, 다음과 같이 두 서비스를 사용해서 구현한다.


public class ReadArticleService {

    public ArticleDto readArticle(Long id) {

        Article article = articleService.getArticle(id);

        articleCountService.increaseViewCount(article.getId());

        ArticleCount count = articleCountService.getArticleCount(article.getId());

        return new ArticleDto(article, count);

    }

    ...

}


public class ArticleDto {

    private Article article;

    private ArticleCount count;


    public ArticleDto(Article article, ArticleCount count) {

        this.article = article;

        this.count = count;

    }


    public Long getTitle() {

        return article.getTitle();

    }

    public int getViewCount() {

        return count.getViewCount();

    }

    ...

}


AritcleDto는 Article과 ArticleCount로부터 값을 읽어오는 getTitle(), getViewCount() 등의 메서드를 제공한다.


캐시 분리 적용


이제 ArticleService의 getArticle()에 캐시 기능을 적용하자. 


public class ReadArticleService {

    public ArticleDto readArticle(Long id) {

        Article article = articleService.getArticle(id); // 캐시에서 읽어 옴

        articleCountService.increaseViewCount(article.getId()); // DB에서 반영

        ArticleCount count = articleCountService.getArticleCount(article.getId()); // DB에서 읽어 옴

        return new ArticleDto(article, count);

    }


ArticleService.getArticle()은 이제 캐시에서 Article 객체를 가져온다. 반면 ArticleCount는 항상 DB에서 가져온다. 이제 조회수와 같은 카운트 값이 빈번하게 변경하더라도 Article 객체가 캐시에서 제거되지 않으므로, Article에 대한 캐시 히트율이 높아질 것이다.


지금까지는 그냥 생각일 뿐, 실제로 조회수가 급격하게 증가하는 상황에서 성능이 어떻게 될지는 아직 테스트 해 보지 못했다. 이건 나중에 기회가 되면 한 번 해 보기로 하자.

Posted by 최범균 madvirus

댓글을 달아 주세요

  1. bluepoet 2012.11.29 16:12 신고  댓글주소  수정/삭제  댓글쓰기

    색다른 아이디어의 글 잘 읽었습니다.

    카운트에 대한 객체를 따로 빼내고, 글 정보 자체를 캐시한다음

    해당 글의 카운트 정보만 업데이트하고 그 정보만 DB에서 읽어온다면

    DB 인덱스 설계에 따라 달라지긴 하겠지만, Article에 대한 글정보를 업데이트하고

    가져오는 것보단 비용이 덜하지 않을까 생각됩니다.

    다만, 리스트를 뿌릴 때 Article 하나에서 가져오는 것과

    Article과 ArticleCount를 조인해서 가져오는 것과의 비용은 잘 따져서

    선택해야 될 것 같습니다.

    스트레스 테스트 하시면 결과도 공유해주시면 좋을 것 같네요

멘탈 모델 책의 1~3장 부분에 대한 요약 발표 자료


멘탈모델 1-3장 자료
View more PowerPoint from beom kyun choi
Posted by 최범균 madvirus

댓글을 달아 주세요

CentOS에 설치한 Confluence의 chart 플러그인이 한글을 제대로 출력하지 않아, 그 문제를 해결하고자 구글신께 물어보고 아래와 같이 간단하게 해결할 수 있다.


먼저 한글 폰트가 없다면 root 계정으로 한글 폰트를 설치한다.


$ yum install fonts-korean


위 명령을 실행하면 /usr/share/fonts/korean/TrueType 디렉토리가 생성되고, 그 디렉토리에 batang.ttf, dotum.ttf 등의 한글 폰트 파일이 생성된 것을 확인할 수 있다.


한글 폰트를 설치했으면 다음은 java를 설정할 차례이다. 여기서는 자바 1.6 버전을 /usr/local/java/에 설치했다고 가정한다. /usr/local/java/jre/lib 디렉토리에 위에 설치한 한글 폰트를 사용하도록 font.properties 파일을 생성해주면 된다. 이 파일을 가장 쉬운 방법은 다음과 같이 기존에 존재하는 파일을 하나 복사하는 것이다.


$ cd /usr/local/java/jre/lib

$ cp fontconfig.RedHat.properties.src fontconfig.properties


이걸로 끝이다. fontconfig.properties 파일을 열어보면 다음과 같이 한글 설정 및 폰트 경로가 지정된 것을 확인할 수 있다. 만약 다른 언어들에 대한 설정이 거슬리면 지워주면 된다.


# Component Font Mappings

serif.plain.korean-iso10646=-misc-baekmuk batang-medium-r-normal--*-%d-*-*-c-*-iso10646-1

serif.bold.korean-iso10646=-misc-baekmuk batang-medium-r-normal--*-%d-*-*-c-*-iso10646-1

... [기타 폰트 설정들]


# Font File Names

filename.-misc-baekmuk_batang-medium-r-normal--*-%d-*-*-c-*-iso10646-1=/usr/share/fonts/korean/TrueType/batang.ttf

filename.-misc-baekmuk_gulim-medium-r-normal--*-%d-*-*-c-*-iso10646-1=/usr/share/fonts/korean/TrueType/gulim.ttf

... [기타 폰트 설정들]


# AWT X11 font paths

awtfontpath.korean-iso10646=/usr/share/fonts/korean/TrueType

... [기타 폰트 설정들]




만약 다른 경로에 한글 폰트를 설치했다면 경로를 알맞게 설정해주면 된다.




Posted by 최범균 madvirus

댓글을 달아 주세요

다양한 Test 기법을 도입하기에 앞서 팀내에 테스트 관련 기초 지식을 전달해야 할 것 같아서 만든 발표자료.

TEST?
View more presentations from beom kyun choi.
Posted by 최범균 madvirus

댓글을 달아 주세요

사내 웹 페이지 중 일부를 튜닝해야 해서 조사를 하던 중 이상한 증상을 발견했다. 파이어폭스나 크롬에서는 발견되지 않고 IE 6, 7에서 발견된 증상으로서, 그것은 다음과 같다.

  • <meta> 태그를 이용해서 페이지 이동시, 이동 된 페이지의 캐시된 자원에 대한 변경 확인 요청 발생
    • 웹 서버는 이들 자원에 대해 304로 응답
  • 자바스크립트 location.href로 이동시, 캐시된 자원에 대한 변경 확인 요청 발생하지 않음

왜지? 처음에는 캐시 옵션이 잘못된 건줄 알았다. 하지만, 파폭과 크롬에서 테스트를 수행한 결과 그렇지 않다는 걸 발견했다. 아직 왜 그런지는 자세히 파지 않았지만 이상하다. 더 파 볼까?

Posted by 최범균 madvirus

댓글을 달아 주세요

Proxy & CGLIB


Posted by 최범균 madvirus
TAG cglib, proxy

댓글을 달아 주세요

아침에 눈 떠서 노래 하나 들으려고 YouTube를 뒤지다가 우연히 Firehouse의 Overnight Sensation Live를 찾았다.



이런 부류의 노래를 부르면 왠지 좋다.

Posted by 최범균 madvirus

댓글을 달아 주세요

  1. terrybogard 2012.07.21 10:48 신고  댓글주소  수정/삭제  댓글쓰기

    저도 우연히 이글을 보게되었네요 ㅎㅎ
    띠리리리~ 띠리리리~ 이노래 좋쵸~ㅎㅎ
    좋은 자료 마니 보고 갑니다.~

IE를 이용해서 웹 사이트를 개발하다보면 서버에서 생성한 응답 화면이 아닌 IE에서 자체적으로 제공하는 HTTP 오류 메시지가 출력될 때가 있다. 예를 들어, 500에러가 발생할 경우 /error/500.html을 출력하도록 설정했는데 파이어폭스나 크롬에서는 올바르게 에러 화면이 출력되는데 반해 IE에서는 아래 그림과 같은 화면이 출력되는 경우가 있다.


IE에서 도구 -> 인터넷 옵션 -> 고급 탭 -> 'HTTP 오류 메시지 표시' 옵션을 해제하면 IE가 제공하는 에러 메시지 대신 서버에서 생성한 응답 결과가 보이긴 하지만, 사이트를 접속하는 모든 사람들이 이 옵션을 해제했을 거라는 보장이 없다.

실제로 IE는 다음의 두 조건이 충족될 때 자체 오류 메시지 화면을 표시한다.
  • 응답의 상태 코드가 404나 500과 같은 에러 코드이고,
  • 전체 응답 결과 데이터의 길이가 513 바이트 보다 작을 때
따라서, 서버에서 생성하는 에러 페이지의 길이가 513 바이트 이상이 되도록 하면 IE가 제공하는 오류 메시지 화면이 출력되지 않도록 할 수 있다. 예를 들어, JSP의 에러 페이지에서는 아래 코드와 같이 불필요한 주석을 코드에 추가함으로써 응답 결과의 길이가 513 페이지가 넘도록 하면 된다.

<%@ page contentType = "text/html; charset=euc-kr" %>
<%@ page isErrorPage = "true" %>
<html>
<head><title>예외 발생</title></head>
<body>
...
...
</body>
</html>
<!--
만약 에러 페이지의 길이가 513 바이트보다 작다면,
인터넷 익스플로러는 이 페이지가 출력하는 에러 페이지를 출력하지 않고
자체적으로 제공하는 'HTTP 오류 메시지' 화면을 출력할 것이다.
만약 에러 페이지의 길이가 513 바이트보다 작은데
에러 페이지의 내용이 인터넷 익스플로러에서도 올바르게 출력되길 원한다면,
응답 결과에 이 주석과 같은 내용을 포함시켜서
에러 페이지의 길이가 513 바이트 이상이 되도록 해 주어야 한다.
참고로 이 주석은 456바이트이다.
-->

참 해괴한 건, 영문 IE에서 'HTTP 오류 메시지' 옵션의 이름이 'Friendly Error Messages'라는 것이다. 도대체 뭐가 'friendly' 하다는 건지 모르겠다.

Posted by 최범균 madvirus

댓글을 달아 주세요

  1. 2010.09.08 14:35 신고  댓글주소  수정/삭제  댓글쓰기

    이런...수가...있었군요....

  2. 몽상귀 2011.06.07 16:25 신고  댓글주소  수정/삭제  댓글쓰기

    오래된 글이지만, 조건 부분이 실제 내용과 다르기 때문에 글 남깁니다.

    에러 메세지에 관련된 아티클
    http://support.microsoft.com/kb/294807/en-us
    임계치에 관련된 아티클
    http://support.microsoft.com/kb/218155/EN-US

  3. 태은 2013.02.06 10:14 신고  댓글주소  수정/삭제  댓글쓰기

    좋은 정보 감사합니다.^^