태터데스크 관리자

도움말
닫기
적용하기   첫페이지 만들기

태터데스크 메시지

저장하였습니다.
페이지를 읽고 있습니다. ( 아쿠아바다's Blog )
분류 전체보기 (769)
쉐어포인트 (24)
Exchange (12)
SQL (121)
XML (36)
WEB (294)
O / S (97)
삶의향기 (162)
기획 (19)
RSS 피드(IE 7.0부터 기본 지원됩니다. 이전 버전 사용자는 접합한 툴을 사용하세요!!)
연재 순서
1. 32비트 닷넷과 최적화 알고리즘
2. 32비트와 64비트의 공통점과 차이점
3. 64비트 활용 전략 : 최적화된 CPU 활용 방안
4. 효과적인 32비트 프로그램의 64비트 마이그레이션
6. 엔터프라이즈 환경에서 64비트 도입 효과
김태훈 (인터데브 차장)
2005/06/01
펜티엄 프로젝트(www.pentium.or.kr)는 윈도우 사용자그룹에서 매년 벌이는 연례 행사다.

여기서 사용하는 기계는 펜티엄 150∼166MHz. 여기에 마이크로소프트 닷넷 프레임워크가 탑재된 윈도우 2003 서버와 SQL 서버 2000을 설치한다.

MS가 제시한 최소 운영 기준이 펜티엄Ⅱ 350MHz 정도. 이 기준에 현저히 못미치는 시스템을 사용하는 것이다. 이 시스템으로 웹 서버를 운영해 외부에서 접속할 수 있도록 한다. 올해에는 약 200만 건의 게시물을 탑재해 순식간에 각 게시물 사이의 페이징이 가능하도록 설정했다.

일반적인 펜티엄 166MHz 제품에 약 200만 건의 게시물을 올린다면 사용자그룹의 프로젝트에서 운영되는 것과 같은 속도가 날 것인가?

"그때그때 다르다."

<그림 1> 펜티엄 프로젝트의 게시판, 약 202만 건의 게시물이 올라가 있다.

사용자그룹에서 작성한 게시판의 페이징에 특별한 기술이 들어간 것은 아니다. 그렇다고 해서 하드웨어나 소프트웨어에 별다른 설정을 한 것도 아니다. 디폴트로 설정되는 모든 설정 값을 그대로 사용한 것이다.

비밀은 소프트웨어 설계 방식에 있다. 대용량 게시물은 SQL 서버의 인덱스와 SQL 서버의 특성, 그리고 게시물 사이의 관계성을 자료 구조에서 나타나는 그래프를 사용한 것뿐이다.

이것은 특별한 기술이 아니라 기본에 충실한 설계 방식에 따른 것이다. 물론 B-트리(B-Tree)의 요소, 그래프의 특성, 닷넷에서의 객체 성격과 성능 등 종합 지식은 알고 있어야 한다.

DBMS를 구성하는 알고리즘을 알면 쉽다
전산학과 학부 2∼3학년 수준 정도로 설정된 자료 구조나 알고리즘이지만, 현장 프로그래머들도 실제 기초에 대한 지식이 부족한 경우가 많다.

또 현장에서 이루어지는 프로그래밍의 기본이 DBMS인 경우가 많기 때문에 DBMS보다 낮은 수준의(컴퓨터에 가까운) 작업들이 잘 이루어지지 않는다. 전산 기초 과목을 생략하고 현장에서 전산 과정을 익혀온 엔지니어라면 더더구나 DBMS부터 모든 기능을 익혀 왔을 가능성이 높다.

그러나, DBMS는 블랙박스가 아니라 데이터를 저장하고 유지하며, 필요한 데이터를 표준 언어에 의해 입·출력해 주는 하나의 프로그램에 불과하다. 따라서 DBMS에서 사용하고 있는 알고리즘을 정확하게 이해하고 있다면, 해당 알고리즘의 특성을 이용하는 것만으로도 최적의 효과를 낼 수 있다.

예를 들어, 펜티엄 프로젝트에서 원글에 대한 댓글을 찾는 알고리즘은 SQL 서버의 클러스터드 인덱스를 그대로 이용해 댓글의 분포를 그래프로 변환하는 과정을 사용한다.

좀더 자세히 말한다면, MS-SQL의 인덱스 구조는 B-트리를 사용한다. 그래서 인덱스 입·출력 자체는 클러스터드 인덱스건, 비클러스터드 인덱스건 실제 차이가 없다.

클러스터드 인덱스의 경우, 실제 데이터 페이지의 정렬이 각 인덱스 노드의 순서로 정렬되는 특성이 있다. 따라서 잦은 입·출력이 이루어질 경우 노드 오버플로우의 문제가 생겨서 노드 오버플로우 시점의 데이터 지연이 있을 수 있다.

이러한 측면들이 기존의 프로그래밍에서 SQL 구문인 오더 바이(Order By) 구문을 생략하는 효과를 낳게 된다는 사실은 이미 널리 알려져 있다. 그런데, 만일 동일한 인덱스명을 갖는 데이터가 중복으로 연속해서 삽입된다면 어떤 일이 벌어질까?

결론부터 말한다면, 클러스터드 인덱스가 정방향일 경우(역방향인 경우는 알고리즘이 약간 달라진다) 클러스터드 인덱스에 의해 삽입되는 데이터는 클러스터드 인덱스가 정방향이며, 동일 인덱스를 가진 경우에 추가로 삽입되는 데이터는 항상 먼저 삽입된 데이터보다 뒤로 입력된다.

따라서, 클러스터드 인덱스가 걸린 테이블을 읽어들일 경우, 이 두 가지 특성을 이용할 경우 오더 바이 구문을 n번 생략하는 효과를 낳게 된다. 또한, 원하는 페이지의 범위를 정확히 인지한다면 해당 페이지를 한 번에 찾아갈 수 있으며, 인덱스를 올바로 탄다면 전체 데이터를 모두 읽어들여 페이지를 분할하고 원하는 데이터를 뽑아내는 수고를 덜 수 있다.

필요한 인덱스가 위치한 데이터를 한 번에 긁어 오면 되는 것이다. 정렬 구문은 현재까지 사용되는 알고리즘 중 가장 부하를 많이 소모하는 알고리즘 중의 하나이며, 정렬 구문을 제외할 경우 상당히 부하를 줄일 수 있다.

<그림 2> SQL 서버의 클러스터드 인덱스 도해(MSDN)

DBMS가 인덱스나 B-트리 구조라는 사실은 재미있는 결과를 알 수 있게 해 준다.

가령 'Select EmployeeId from Employee' 구문과 'Select count(EmployeeId) from Employee' 구문은 보통 전자가 훨씬 부하가 많이 걸릴 것이라고 생각하기 쉽다. 그러나, 이 두 구문의 CPU 소모량은 크게 차이가 나지 않으며, 'EmployeeId' 필드의 크기가 매우 작다면 I/O의 부하가 조금 전자가 더 걸릴 뿐, 실제 나타나는 효율성은 거의 같다.

트리 구조상 데이터의 총량을 측정하기 위해서는 전체 순회가 필요하며, 이 순회 과정에서 CPU 소모가 이루어지기 때문이다.

이런 특성을 알고 있었을 경우, 대용량에서 동일한 조건으로 개수를 세는 작업이 빈번하게 반복되더라도 미리 개수를 알고 있는 형태로 프로그램을 구성해 훨씬 성능이 좋은 방식으로 작업할 수 있을 것이다. 필요한 경우 개수만을 따로 필드로 보관하는 방법도 생각해 볼 수 있다.

SQL 서버나 운영체제의 설계 원리, 그리고 작성한 코드의 운영 원리를 정확히 파악하고 있다면 시스템 운영 중 어떤 반응을 보일 것인지에 대한 예측이 가능하며, 예측된 대로 대응할 수 있는 방법을 생각해 볼 수 있다.

OOP의 단점을 간과하지 말라
가끔 회사에 신입으로 입사를 지원하는 사람들에게 OOP(Object Oriented Program)와 구조적 프로그램 중 어떤 것이 프로그램 성능이 좋은가 물어 보면, 많은 사람들이 OOP가 효율이 무척 좋다고 말한다.

하지만, OOP는 많은 사람들이 생각하는 만큼 그다지 효율이 좋지 않다. OOP는 근본적으로 시스템의 성능을 올리기 위한 작업 방식이 아니며, 시스템의 물리적인 성능을 올리기보다는 시스템을 설계하고 운용하며, 제작하기 쉽게 만들기 위해 사용하게 된다.

OOP로 이루어진 프로그램은 많은 부하가 생성과 소멸, 연산자 중복 등의 작업에서 나타난다.

닷넷에서는 자바 진영과는 달리 'Type'과 'Class'가 일정 부분 분리돼 있다. 'Class'는 참조형으로, 'Type'은 값형으로 구분해 사용한다.

자바와는 달리 C#이 '순수한' OOP를 따르지 못했다는 것은 이렇게 형이 분리된 데서 나타나는 것이다. 물론 프레임워크에서는 'int'형은 'System.Int32' 구조체로 변형되기는 한다.

32비트 닷넷에서는 32비트의 크기 내에 삽입되는 'Value Type' 형태의 생성과 할당이 가장 빠르게 이루어진다.

'Int32'형과 'char'형, 혹은 'byte'형의 생성과 할당이 가장 빠르며, 64비트를 사용하는 'Int64'형이나 'Double'형이 그 다음으로 가장 빠르게 작업이 이루어진다. 가장 골치 아픈 생성과 소멸의 문제는 참조형으로, 가변 크기를 갖는 것들이다. 대표적인 것이 'string' 형식이다.

'String' 형식은 할당과 생성, 소멸 시간이 다른 형에 비해 훨씬 많이 걸리며, 만일 가변 길이의 'string' 형식의 무한한 덧셈이 이루어진다면 시스템의 효율성을 극도로 떨어뜨린다.

다음과 같은 피보나치 수열 비슷한 알고리즘을 생각해 보자.

     string[] j;
     j=new string[10000000];
     j[0]="a";
     j[1]="a";


     for(int i=0; i<10000000; i++){
     if(i>3)
          j[i]=j[i-1]+j[i-2];

여기서 형식을 'string'에서 'Int64'로 대체하면 32비트 시스템의 성능이 최소 50배에서 100배 정도 좋아진다. 'Int32'로 대체하면 100배에서 200배 정도의 성능 차이를 나타낼 수 있다.

이러한 길이의 변화가 심한 객체가 사용될 경우, 생성과 할당, 그리고 소멸 부하에 의해 시스템은 엄청난 과부하를 느끼게 된다.

실제로 'System.String'에서 나타나는 문제를 해결하기 위해 MS는 'StringBuilder'라는 새로운 클래스를 제시하고 있다. 하지만 'StringBuilder'는 OOP의 장점을 손상하는 객체일 수 있다. 명시적인 연산자 오버로딩을 회피하는 방법이기 때문이다.

하지만, 시스템을 OOP의 장점만으로 설계하기에는 너무나 큰 성능 희생이 따를 수 있기 때문에 이러한 형태의 객체를 선언하고 쓰는 것을 권장할 수밖에 없는 게 현실이다.

객체의 선언 방식은 사용자 정의 객체에서도 동일하게 적용된다. 사용자 정의 객체 역시 성능을 생각하지 않고 설계됐을 경우, 성능을 저해하는 요소로 작용할 수 있다. 특히 오버로딩된 연산자가 객체 전체를 파괴하고 재할당하는 형태로 제작되는 경우, 오버로딩을 회피하고 새로운 연산 함수를 만들거나 새로운 객체를 선언하는 방법으로 회피해야 한다.

객체와 객체가 서로 연관 관계가 있을 경우, 'Linked List' 같은 형식이나 트리와 같은 객체 사이의 관계성 설정을 위한 방법이 필요하다. 이런 방법들은 객체 자체에서 이루어지는 연산을 상당 부분 회피할 수 있다. 또 이미 객체들이 만들어져 있다면 새로 그 객체 모두를 포괄하는 객체를 만들기보다 관계성 설정만으로 새로운 개념을 정의할 수도 있다.

그래서 데이터베이스 층에서 전달된 데이터를 데이터 그리드나 배열 형태로 단순히 받기보다는 객체의 'Linked List' 혹은 'Binery Search Tree' 형태로 받아주면 훨씬 부하를 줄일 수 있다.

메모리를 희생하더라도 CPU 성능은 높게
예전의 자료구조론적인 방법이 닷넷에서도 항상 통용되는 것은 아니다.

과거 시스템은 주로 메모리의 사용량을 줄이기 위해 안간힘을 쓴 경우가 많았다. 32비트 운영체제에서도 실제 사용자 영역 메모리는 2GB에 달하지만, 고용량 시스템인 경우 메모리 영역도 페이징의 한계에 다다라 메모리 확장을 위해 CPU를 확장하고 다중 CPU 사이에서의 프로그램을 해야 하는 경우가 있었다.

그런데, 점차 프로그래밍의 대세가 메모리를 많이 희생하고 CPU의 성능을 올려주기 위한 방법으로 이전되고 있다.

물론, 두 가지가 상충되는 개념이라고 볼 수는 없지만, 현대 프로그래밍에서는 CPU의 클록과 메모리의 소모량 중 하나를 선택하라면 주저 없이 메모리의 희생을 선택하게 된다. 이는 앞으로 64비트 컴퓨터가 대중화될 것이라는 희망에서일 수도 있다.

32비트 시스템이 갖는 4GB의 메모리 한계는 초창기에는 바다와 같이 넓은 용량이었지만 지금 시스템에서 4GB는 사실 대용량에서는 '어림도 없는' 수준이 되고 있다. 오히려 동시 사용자가 많은 웹 서비스와 같은 작업이 대세를 이루기 때문에, CPU의 많은 사용은 불필요한 부하를 야기하며 시스템 성능에 예민한 문제를 일으키게 된다.

따라서 닷넷 시절로 이전했을 때는 다소 메모리를 희생하더라도 CPU의 성능을 올릴 수 있는 방법으로 시스템 설계 방향이 변경되고 있다. 이는 과거 자료구조적인 프로그램 방식이 주로 메모리에 초점을 맞춘 경우가 많았기 때문이다. 32비트와 64비트의 가장 큰 차이는 바로 이 풍부한 메모리와 관련이 있다.

100의 성능을 모두 내도록 하는 것이 '최적화'
최적화라는 것은, 성능이 100인 시스템을 120으로 만드는 것이 아니다. 성능이 100인 시스템이 최대 성능치를 낼 수 있도록 도와주는 것이다.

많은 시스템들이 최적화되지 않은 데는 시스템 자체의 성격이나 전산 기초를 무시한 설계에서 비롯되는 경우가 많다. 이러한 경향은 DBMS 기반 하에서 이루어지는 OOP 설계 방식과 CBD 구현 방식에서 더 나쁜 방향으로 진행되고 있다.

이 칼럼에서 말하고자 하는 것은 기본으로 돌아가자는 것이다. 닷넷 시스템을 다시 처음부터 이해하고, 컴퓨터 자체의 운영 원리를 이해하며, 객체 지향성이 갖는 성능상의 문제점들의 발현 원인과 자료구조론적인 데이터 구성 방식을 찾아보자는 것이다.

닷넷이라고 해서 아주 특별한 기술이 있는 것은 아니다. 컴퓨팅 시스템을 잘 이해하고 있는 사람이 닷넷을 가장 잘 이해할 수 있으며, 최적화 역시 그렇다.

아무리 코드를 열심히 작성해도 결국 펜티엄의 오퍼랜드 코드와 오퍼레이션 코드로 변환되는 것이다.

다음 주제는 32비트 코드를 중심으로 64비트 시스템으로 이전해야 될 몇 가지 필요성과 32비트 코드의 실무적인 최적화 예를 더 들어보도록 하겠다. @


출처 : ZDnet

좀더 흥미로운 내용이 많이 있습니다.. HOME > SQL를 확인하세요
0 Trackback, 0 Comment, :
1  ... 519 520 521 522 523 524 525 526 527  ... 769 
Statistics Graph
Total : 557,403 Today : 33