웹 상에서 말하는 Performance에 대해서 다음과 같은 개념을 획득했다.
1. Performance Concept
Performance라는 것은 단위 요구당 평균 응답 시간을 가지고 특정 시스템의 performance을 논하지 말아야 한다는 것이다. 정확히 말하면 Performance라는 것은 단위 시간당 이 시스템이 처리해 낼 수 있는 최대 가능한 처리 건수를 말한다고 한다. 이를 전문 용어로 TPS (Transaction Per Seconds)라는 개념을 사용한다. 이러한 TPS는 단위 시간당 응답속도인 Average Response Time(유속)이 높으면 당연히 TPS도 높아질 것이다. 하지만 이러한 TPS을 높이는 상관 관계가 있는 것이 또 있는데 바로 동시에 처리할 수 있는 양(즉 송수관의 길이)과 관계가 있다. 기타 Performance라는 것과 함께 알아야 할 개념으로는 다음과 같은 것이 있다.
Active Clients
Web에서 Transaction의 의미
Saturation Point(임계점)
Light Load Zone
Heavy Load Zone
Buckle Zone
Concurrent User
2. 몇가지 질문
질문 1 : 각 사이트에 가서 성능상의 문제가 있는지 없는지는 무엇을 판단 하는가?
일단 고객 사이트에 가서 웹 로그 자료가 있다면 Peek Time시에 기록된 사용자들의 호출 패턴 분석을 통해 평균 Think Time을 확인하여 동시 단말 사용자 수와 최대 호출 빈도를 계산한다. 만일 이 호출 빈도가 앞서 스트레스 테스트를 통해 구한 최대 TPS를 넘어 간다면 H/W증설이나 혹은 해당 성능 저하를 극복할 수 있는 여하한의 방안을 강구해야 하는 시점인 것이다. 반면 그 사용자의 호출 빈도가 해당 응용 어플리케이션의 최대 TPS에 아직 못 미치고 있다면, 해당 시스템은 적어도 아직까지는 성능상의 문제가 없는 것이다.
질문 2 : 각 사이트에 가서 Performance 튜닝을 할때 절차와 방식은 무엇인가?
가. 관련된 모든 수치를 최대한 높인 후, 점차적으로 Active Thread의 수를 증가 시키며 테스트를 수행하고, 그 결과를 반드시 TPS그래프로 그린다.
나.각 Tier 혹은 Machine의 CPU나 Memory, Network, 응용 어플리케이션이 사용하는 TCP/IP Port를 모니터링하고, 각 구간의 임계점(Saturation Point)을 찾는 것이 중요하다. 가급적이면 Back End System부터 Saturation Point을 찾아야 한다.
다.가장 먼저 BottleNeck으로 도출되는 구간부터 튜닝하라.
라.다시 Active Thread의 개수를 증가 시키며 동일한 테스트를 시행하고 TPS의 전체적인 그래프를 통해 성능상의 변화를 확인하라. 이러한 과정은 계속 반복 될 것이다.
질문 3 : 최대 TPS는 어떠한 툴을 사용해서 어떻게 구해야 하는가?
일반적으로 TPS라 하면 단위 시간안에 이 시스템이 최대한 처리할 수 있는 트랜잭션의 개수이다. 즉 하나의 Request을 보내서 Response가 온 갯수인 것이다. 이 개념은 결국 깔때기안에 존재하는 물을 초당 얼마나 밑으로 흘러 보내느냐에 대한 개념과 같은 것이다. 이러한 TPS는 일단 시스템이 가지고 있는 모든 자원을 최대 한도록 사용하게 함으로서 이 시스템이 처리할 수 있는 최대 처리건수를 계산해 내는 것이기 때문에 Stress Test Tool을 사용해서 TPS을 계산해 내어야 한다. 이 값은 단위 시간에 처리한 갯수를 이 단위 시간으로 나눔으로서 알 수 있다. 이때 Active User당 TPS값을 계산해야 한다. 이러한 Active User란 테스트를 수행할 개별적인 테스터의 개수를 의미하는 것으로 일부에서는 이를 동시 사용자라는 용어를 사용하고 일부에서는 "# of Run Thread" 라는 개념을 사용하기도 한다. 반드시 TPS를 개산 할 때는 Max Thread의 개수를 점증적으로 증가시키면서 Active User의 개수를 증가 시켜서 그때 TPS와 Mean Response Time을 계산해 보아야 한다.
질문 4 : TPS와 Response Time의 관계를 나태내는 그래프의 결과는 어떠한 양상을 띄는가?
TPS라는 것은 그 시스템이 자신이 할 수 있는 한도내에서 초당 몇개를 해 낼 수 있느냐를 검사하는 것이기 때문에 이러한 TPS를 검사할 때 Active User를 최대한 다양하게 해 보야야 한다. 이러한 다양한 레벌의 Active User의 수를 늘려서 검사를 해 보았을 때 일반적으로 어느 정도 까지는 TPS가 선형적(Linear)하게 증가하게 된다. 하지만 어느 시점 부터는 이러한 TPS가 변동이 없게 된다. 바로 이 꺽이는 지점이 이 시스템이 낼수 있는 최대 TPS가 되는 것이다. 사실상 이 꺽이는 지점에 있는 Active User의 수를 넘어서 들어오게 되면 그 차이만큼 시스템에서는 큐잉(Queuing)이 발생하게 된다. 따라서 TPS는 변화가 없이 일정하게 유지된다. 이때 최고의 TPS를 나타내는 최초의 Active Client의 수를 Saturation Point(임계점)이라고 한다. 또한 임계점을 중심으로 아직 시스템이 자신이 할 수 있는 최대의 TPS의 전단계를 Light-Load Zone이라고 한다. 이 구간에서의 평균 응답 시간은 일정하게 유지한다. 특정 Active client부터는 일정한 TPS가 유지되는 구간이 있는데 이를 Heavy-Load Zone이라고 한다. 이 구간에서의 평균 응답 시간은 선형적으로 증가한다. 또한 어떤 시점으로부터는 오히려 TPS 수치가 떨어지는 구간이 나타나고 있는데 이 구간을 Buckle Zone이라고 한다. 실제로 Saturation Point는 때론 Network이나 CPU, 메모리 혹은 심지어 응용 어플리케이션의 병목현상으로서 인해 나타나기도 한다. 이러한 병목현상을 제거함으로서 saturation Point을 향상 시킬 수 있다.
질문 5: 어떤 웹 기반 시스템의 성능을 향상 시키기 위해서, 어떤 파라메타의 변경이나 CPU증설, 메모리 증성 혹은 응용 어플리케이션의 로직 수정을 통해 성능 향상을 개선했다고 했을 때 그것을 확인하는 방법이나 혹은 얼마나 향상되었나는 수치적으로 측정하는 방법은 무엇이 있는가.
성능향상에 따라서 변화하는 것은 크게 두가지에 변화가 생긴다. 첫번째로 Response time이 오른쪽으로 이동하는 결과를 초래한다. 그림상에서 보면 50일때 linear하게 상승하던것이 성능향상의 결과로 110인 선에서 급격하게 올라라는 결과를 내고 있다.
아래 그림은 속도 향상의 따른 TPS의 변화를 나타낸 것이다. 마찬가지고 TPS가 48에서 88 TPS로 올라가는 결과를 초래하고 있다. 이 만큼의 속도 향상이 있다는 증거이다. 결과적으로 성능지수(Performance Factor)인 최대 TPS가 48에서 88로 올라갔다는 증거이다.
다음 그림은 이 두개의 그래프를 합쳐서 보여 주는 그림이다.
따라서 향상된 성능은 83%{(88-48)/48 * 100)가 된다.
TPS의 그래프가 앞서의 경우와 같이 항상 증가하는 방향으로 나타나지 않을 수 있습니다. 예를 들어 위 그래프를 보면, 특별히 TPS의 급격한 증가는 보이지 않고 있습니다.
단지 Buckle-zone 지역에서 오히려 TPS가 낮아지는 경향이 있던 것이, 항상 일정한 TPS를 유지하는 방향으로 개선되었습니다. 또, Saturation Point의 변화가 없다는 점도 주목할 점입니다.
Saturation Point의 변화가 없다는 것은 어떤 자원에 대한 한계적 상황이 발생하는 원인 및 시점은 동일하다는 것을 의미합니다. 이러한 경우는 통상 CPU나 메모리, 네트워크용량, 혹은 백엔드시스템(Backend system)의 성능저하가 병목현상(bottle-neck)의 주 원인으로 나타날 때 발생합니다.
이 경우는 각 구간의 통로역할을 하는 파라메터를 앞서의 경우와는 반대로 오히려 적정하게 줄여 주어 해당 자원에 대한 경합현상(contention)을 없애줌으로써 항상 일정한 성능을 내도록 튜닝해야 합니다. 위의 경우는 웹어플리케이션서버의 Worker-Thread 최대치를 너무 높게 책정치 말고 Saturation Point가 나타나는 Active Clients 수치에 맞추어 내려줌으로써 획득한 성능향상, 아니 성능안정(?)의 결과인 것이지요.
이처럼, 튜닝이라는 것은 앞서의 경우처럼 병목현상의 원인이 되고 있는 부분을 충분한 수치로 늘려주는 방법이 있는 반면, 이처럼 특정 파라메터를 제한 시켜주는 기법도 존재합니다. 또한 그에 따른 TPS그래프의 변화는 서로 상의하게 다른 특징을 갖습니다. 전자의 방법이 최대TPS를 끌어올리는 효과가 있었다면, 후자는 Buckle-zone 을 없애고 항상 일정한 TPS가 유지되도록 하는 효과가 있었습니다.
시스템을 사용하는 사용자가 한 두 사람이 아닌 수 많은 사용자가 동시에 수 많은 트렌젝션을 날리는 OLTP(On-Line Transaction Processing)시스템에서는 단일평균응답시간보다는 수많은 동시사용자가 접속했을 때, 보다 안정적인 서비스를 제공하는 것이 더욱 중요하며, 그것의 측정기준은 최대 TPS임을 이젠 인식해야 합니다.
질문 : Saturation Point가 위치한 병목현상의 원인이 CPU 용량부족에 있는 경우에 한하여, CPU의 개수를 1,2,4,8개로 증설할 때 TPS는 어떻게 변하는가.
OS에 따라 약간의 차이가 발생하겠지만, 위 그래프에서 보듯, 전반적으로 선형적인(linear) 성능향상을 기할 수 있다. 하지만 이는 해당 상황이 CPU병목현상에 기인했을 경우에만 위와 같은 결과를 얻을 수 있습니다. 특히, 각 하드웨어 사양별, CPU개수별, 그리고 JDK 버전별로 성능지수는 많은 차이를 보입니다. 아래의 자료를 통해 나름대로 기준잣대를 갖는 것이 무엇보다 중요 합니다.
All SPEC JBB2000 Results Published by SPEC
http://www.spec.org/osg/jbb2000/results/jbb2000.html
질문 6: 기타 다른 성능 향상을 위해서 웹 어플리케이션 서버를 복제하는 경우와 여러대의 노드를 IBM의 e-Network Dispatcher나 L4/L7 로드 발란싱 장비를 이용하여 병렬로 처리하는 경우 성능에는 어떠한 영향을 미치는가.
아래 그래프는 IBM RS6000 S7A(12-way) 사양의 SMP 머신에서 웹어플리케이션서버를 복제(Cloning)하여 운영할 때, TPS의 변화를 보여주고 있습니다. 도표에서 보듯, 단일 머신에서 웹어플리케이션서버의 복제는 그다지 큰 효과를 보여주지는 못하고 있습니다.
물론 이러한 상황은 다양한 변수가 있을 수 있습니다. 예를 들어, 하나의 웹어플리케이션서버 만으로도 CPU를 충분히 사용하여 높은 TPS를 이미 내고 있다면, 복제에 따른 성능향상은 큰 기대를 할 수 없을 것입니다. 반면, 하나의 웹어플리케이션서버로 운영 시에 그 성능저하의 요인이 하나의 Unix Process로 운영되어 SMP 기반의 효율적인 Multi-processor 특성을 십분 발휘하지 못하는 경우에는 효과를 볼 수 있을 것입니다. 그러나 최근 JDK는 대부분 multi-processor, multi-thread 기반으로 동작토록 계속적인 성능향상이 되어 왔기 때문에, 큰 기대는 하기 힘들 것입니다. 실제 프로젝트의 사례를 보면, 실질적인 성능측정을 통해 복제의 개수를 정하는 것이 아니라, 통상 CPU 개수만큼을 복제하여 사용하는 경우가 있는데, 이는 성능향상의 관점에서만 보면, 그리 바람직하지 않다고 볼 수 있습니다.
일반적으로 IBM WebSphere Application Server의 경우, 4-cpu 이하의 기종에서는 웹어플리케이션서버의 복제는 오히려 성능저하를 야기합니다.
NOTE: 복제를 하여 급격한 성능향상을 보았다면, 그것은 SMP의 Multi-Processor의 특성 때문에 성능향상이 되었다기보다는 어쩌면 웹어플리케이션 서버의 특정 파라메터가 상대적으로 작게 조정되어 있었고, 이를 복제하니 충분한 개수가 동시에 수행될 수 있어서 결국 성능향상이 있었을 가능성이 오히려 높습니다. 따라서, 비록 하나로 운영되더라도 적절한 파라메터 조정을 통해 스트레스테스트환경에서 CPU를 100%까지 사용토록 조정하는 것이 더욱 중요합니다.
반면, 여러 대의 서버(노드)를 IBM eND(e-Network Dispatcher)나 L4/L7 로드발란싱 장비를 이용하여 병렬로 운영할 경우, 거의 대부분의 경우에 있어서 머신의 개수에 정비례하여 TPS는 높아집니다. 앞서 CPU 증설에 따른 성능향상은 성능저하의 원인이 CPU용량부족의 경우에 국한된다는 것과는 달리, 이 같은 다중노드(Multi-Node) 기반으로 서비스를 하는 경우는 대부분의 경우에 항상 TPS증가 효과를 볼 수 있습니다.
단, 이 경우도, 예외는 있습니다. 성능저하의 요인이 웹어플리케이션서버가 탑재된 머신에 있는 것이 아니라, 백엔드시스템의 데이타베이스나 혹은 CICS를 경유한 HOST 트렌젝션에 있을 경우, 아무리 웹어플리케이션서버 장비를 늘려본 들 소용이 없을 것입니다. 또한 당연한 얘기겠지만, 네트워크 부하증가로 인해 성능저하가 일어나고 있는 경우도 마찬가지로 효과가 없을 것입니다.
웹어플리케이션서버와 데이타베이스서버를 분리하려는 시도는 매우 바람직합니다. 혹자는 이런 의문을 갖고 있을 수 있습니다. “웹어플리케이션서버가 데이타베이스와 같은 머신에 있어야 네트워크 지연시간이 없으므로 더 빠르지 않은가?” 사실입니다. 데이타베이스서버를 분리할 경우 단일요청에 의한 단일응답시간은 네트워크 지연으로 인해 다소 더 느려 질 수 있습니다. 그러나, 앞서 성능의 특성에 관련하여 단위시간당 최대처리건수(TPS)와 평균응답시간의 그래프를 연상해 봅시다. 만약, 웹어플리케이션서버와 데이타베이스가 같은 머신에 존재할 경우, 그리고, 그 당시의 성능상의 최대 병목원인이 CPU나 메모리, 혹은 디스크 I/O에 있다면, 이를 분리해 줌으로서 CPU와 메모리를 각각 나누어 수행하므로, 비록 단일요청에 의한 응답시간은 늦어지더라도 수많은 Active Clients 증가에 따른 최대 TPS는 더욱 높아 질 것입니다. 웹 기반 시스템이라는 것이 나 혼자만 사용하는 배치성 작업(Batch Job)이 아니라 여러 사람이 동시에 수 많은 요청을 날리는 OLTP시스템이라는 사실을 기억해야 합니다.
NOTE: 분리했을 때 성능향상의 효과를 보려면, 기존 병목의 원인이 분리를 함으로써 해결될 수 있는 성질의 것인가를 먼저 판단해야 합니다
질문 7 : 일반적으로 웹 페이지의 크기는 얼마나 되며 10Mbps에서 이러한 웹 페이지를 주고 받는다면 1초당 몇건을 전송할 수 있겠는가. 즉 Network Line에서의 Bandwidth을 계산해 보아라?
일반적으로 하나의 웹페이지 크기는 보통 10KB가 거뜬히 넘어갑니다. 화면이 좀 예쁘고 다양한 이미지까지 포함되어 있다 싶으면, 아마 30KB를 넘어 어떤 건 100KB에 육박할 것입니다. 평균 10KB라고 가정한다. 이럴 경우 10 Mbps 네트워크 상황에서 최대 TPS을 계산할 경우 일단 10 Mbps라고 해 봐야 실 전송 속도는 60%인 6Mbps정도가 나오고 결국 6Mbps라 함은 6 * 1024/8 = 768(kB/sec)가 된다. 결국 최대 TPS는 768(KB/Sec) / 10KB(한 페이지의 사이즈) = 76.8 TPS가 나온다.
어지간한 벤치마크테스트 하드웨어사양에서는 테스트 대상 어플리케이션의 최대TPS는 100 TPS는 기본이고 1000 TPS 혹은 2000 TPS를 바라보게 됩니다. 그러나 네트웍의 용량은 76.8 TPS를 넘지 못하므로 결국 열심히 네트웍 부하테스트만 하고 있는 꼴인 거지요. 서버측의 CPU는 20-30% 이상 올라가지도 않는데, 성능은 76TPS를 넘지 못합니다. 또, HTTP통신으로 데이터를 주고 받을 경우 네트웍의 수치상 한계인 76TPS의 80-90% 밖에 나오지 않습니다. 결국 100m경주를 하자면서, 막상 경보경주를 하고 있는 셈이 되네요.
같은 방식으로 T1,E1,T3 등에 대해서도 계산해 보세요. 따라서 스트레스테스트를 할 땐 반드시 100Mbps환경에서 테스트가 이루어져야 합니다. 이 같은 네트웍 병목을 확인하는 방법은 해당 서버의 네트웍카드에서 방출되는 초당 데이타량이 해당 네트웍용량에 육박한지를 확인하면 됩니다. 혹은 netstat 로 봤을 때, send queue와 receive queue에 쌓인 양이 전체적으로 100 KB를 넘어서면 네트웍에 의한 병목으로 판단하곤 합니다.
-bps : bit per second (1 byte = 8 bit, 1Kbyte = 1024 byte)
T1 : 1.544 Mbps(1.5Mbps)
E1 : 2.048 Mbps (2Mbps)
T3 : 43.7361 Mbps (45Mbps)
OC3 : 155.2 Mpbs
10 Mbps, 100Mbps
10Mbps급: 실전송속도의 60%라고 한다면
실전송속도 6Mbps = 6*1024(Kbps) = 6*1024/8(KB/sec)
= 768(KB/sec)
10K data전송 : 768(KB/sec) / 10(KB) = 76.8 TPS
100Kdata 전송 : 768(KB/sec) / 100(KB) = 7.68 TPS
100Mbps 의 경우, 이것의 10배 향상
T1 위 경우, 실전송속도가 80%라고 한다면,
10K전송시 158.1(KB/sec) / 10(KB) = 15.8 TPS
100K 전송시 : 1.58 TPS
질문 8 : 무엇이 동시 사용자이고 어떤 수치를 동시 사용자라고 표현하기에 적절한 수치이고 구할 수만 있다면 어떠한 방법을 통해서 이러한 동시 사용자 수치를 구할 수 있을 것인가?
동시 사용자에 대한 개념은 많다. 동시 사용자란 해당 시스템을 사용하기 위해서 PC앞에 앉아 있는 사용자로서, Active User와 InActive User로 구성된다. 여기서 Active User는 Request요청을 하여 응답을 기다리고 있는 사용자를 말하고 Inactive user는 현재 Request를 수행하지 않고 있으며, 화면의 결과를 보고 있거나 다음 버튼을 누르기 전까지의 사용자를 말한다. 단위 시간당 호출 빈도는 동시 사용자의 증가에 비례한다. 이러한 동시 사용자에 대한 정의는 비지니스적인 사람의 수라는 관점이 강조되는 값이다. 일반적으로 "동시 단말 사용자" 라고 부른다.
위의 그림에서 물의 높이는 "현재 수행중인 총 서비스의 개수" 와 일맥 상통한다. 이러한 총 서비스의 개수는 위에서 붓는 물의 양과 깔때기 아래에서 빠져 나가는 물의 양에 의해서 결정된다. 즉 단위 시간당 호출빈도(깔때기 위에서 붓는 물의 양)와 해당 서비스가 얼마나 많은 건수를 단위 시간안에 처리할 수있는가에 의해서 달라진다. 동시 사용자란 개념을 여기서 서비스 하고 있는 개수는 이렇듯이 여러 변수에 의해서 좌우되기 때문에 적절하지 못하다. 따라서 동시 사용자라 Active User와 Inactive User를 포함하는 비지니스적인 사람의 수라고 하는 것이 옳다.그렇다면 동시 사용자에 포함되는 InActive User에서 도대체 몇분을 사용하지 않을 때 동시 사용자로 취급할 것인가가 애매한다.
웹 기반 시스템에서의 동시사용자는 그 근본적인 특성상 정의가 모호할 수 밖에 없습니다. 과거에 클라이언트/서버시스템과 같이 일단 로그온 단계를 거치면 TCP/IP연결이 지속적으로 유지되고 해당 사용자가 그 시스템을 호출하고 있든, 화장실을 갔건, 무조건 단말사용자에 카운팅 되었습니다. 그 때는 그 정의 자체가 명확했고 단순했습니다. 그러나 웹 기반 시스템은 stateless라는 HTTP 프로토콜의 특성상 그렇게 명확하게 정의할 수가 없습니다. 결국 동시 사용자에 대한 범위는 각 Business 적인 관점에서 따로 결정을 해야 한다는 말이다. 오늘 Peak시에 몇 개의 서비스가 큐잉되었나는 시스템 관리자에게는 의미가 있겠지만, 매니저 입장에서는 오히려 어제와 오늘 총 들어왔던 사용자 수나 현재 시스템을 사용하기 위해서 앉아 있는 동시 단말 사용자가 몇 명인가에 더욱 관심이 있기 마련이다.
그렇다면 동시 단말 사용자를 어떻게 구할 것인가. 만일 동시 단말 사용자를 특정 시각을 기준으로 10분 전후에 모두 한번 이상 호출된, 서로 다른 IP Address의 개수라고 한다면 다음과 같이 동시 단말 사용자의 개수를 구할 수있다.
앞에서 정의한 바와 같은 동시사용자를 실시간으로 구하기는 매우 어려워보입니다. 그러나 웹서버의 access_log파일을 분석하면 쉽게 구할 수 있습니다. 위와 같이 개별사용자는 각자의 고유한 시간 간격으로 간헐적인 Hit를 남길 것입니다. 개별사용자는 대부분(?) 고유한 IP어드레스를 가집니다. 동시사용자를 구하는 방법은 특정 시각을 기준으로 10분 전후에 모두 기록이 남아 있다면 그 사용자는 동시사용자 중의 한 사람으로 간주하는 방법을 사용합니다. 만약, 10분전 구간에서는 Hit가 남아 있으나 해당 시각 10분 후 구간에는 Hit가 없다면, 해당 시각에서 그 사용자는 로그아웃 했다고 여겨도 되지 않겠습니까. 이 같은 논리로 위 그래프에서 해당 시각의 동시사용자는 6명입니다. 이 수치는 직관적으로 보듯, 10분 동안 Hit가 남아 있는 서로 다른 IP수 보다 작습니다. 이 같은 수치를 구하는 것은 해당 access_log를 데이타베이스에 넣어 적당한 쿼리문을 통해 쉽게 추출될 수 있을 것입니다. 이때의 단점은 Proxy IP을 사용하는 경우와 L7에서 대표 주소를 사용하는 경우에 정확하게 다른 IP를 구분할 수 없다는 단점이 있으며 단지 예측만 할 수 있을 뿐이다.
질문 9 :최대 TPS상에서 Active client가 개수가 120개 이고 개별 사용자가 그 응답 시간이 몇 초이든 무조건 10초 간격으로 한번씩 호출하고 수용할 수 있는 평균 응답 시간이 1.4초라 가정할 때 이 시스템에서 수용할 수 있는 최대 동시 사용자는 몇명인가?
아래 그림과 같이 r을 평균 반응 시간이라 하고 t는 각 사용자가 무조건 쉬는 간격이다. 이 t의 값이 10초 이기 때문에 각 사용자는 하나의 Request을 요청하고 나서 1.4초에 Response을 받은 후에 8.5초를 쉬고 다시 또다시 Request을 보낸다. 그러나 원안의 120명은 8.6초 동안은 호출을 하지 않으므로 항상 서버 측에 120개의 요청이 꽉 차려면 그러한 120명이 1.4초에 대한 10초의 비율 개수 만큼 더 있으면 서버는 항상 120개의 요청을 처리하는 상황이 발생한다.
즉, 120(명) x { 10(초) / 1.4(초) } = 852 명이 10초마다 한번씩 호출하면 서버는 평균응답시간이 1.4초가 걸리고 수행중인 서비스의 개수는 120개가 될 것입니다. 이러한 과정을 통해 위 도표에서 Active Clients x { 10 / MeanResponseTime } 를 계속적으로 구한 결과는 위의 그림과 같다.
공식 1 : 최대 사용자 구하기
Max User = Active Clients * {t/r}
공식 2 : Active 사용자 구하기
Active Clients = Max User /{t/r}
이 경우 초당 83.3개를 처리한다는 몇명이 어느정도의 빈도로 호출할 때 발생하는 TPS인가에 대한 답이 될 것이다. 결국 852명이 10초 간격으로 호출할때 서버에는 항상 서버에서는 초당 85.2건의 호출(깔때기에 넣는 물의 양)이 들어오게 되면 시스템에서는 수행중인 서비스의 개수가 120(깔때기안의 물 높이)이 될 것이며 이때 시스템에서 처리하는 최대 가능한 건수가 바로 83.3(깔때기 밑으로 빠져 나가는 물의 양)개 라는 결과가 나온 것이다. 이때의 평균 응답 시간은 1.4초가 되는 것이다.
여기에서 Active Client와 Concurrent User사이의 상관 관계를 보여 주는 의미있는 그래프를 한번 보자.
이 그래프를 설명해 보면, 10초에 한번씩 호출하는 사용자가 200명이면 서버에선 10개의 서비스가 계속 수행중인 정도의 부하가 됩니다. 10초에 한번씩 호출하는 사용자 500명이 들어오면 서버에는 항상 30개의 수행 중인 서비스들이 존재하게 됩니다. 10초에 한번씩 호출하는 사용자 800명이 되면 서버에는 항상 90개의 수행중인 서비스들이 있게 될 것입니다. 이러한 사용자가 852명이면 120개가 될 것이고, 900명이면 290개가 항상 수행 중에 있을 것입니다.
여기서 수행 중에 있다는 것은 실제 웹어플리케이션서버가 그 900개의 요청을 동시에 처리하고 있다는 뜻이 아닙니다. 네트워크에서 대기 되어 있든, 최대로 동시 수행 가능한 Worker-Thread의 개수를 제외하고는 나머지는 어디에선가 대기상태에 빠져 있을 것입니다. 어쨌든 요청을 날린 클라이언트 입장에서는 수행 중에 있다는 것을 의미합니다.
만약 이러한 사용자 1000명이 들어오면 어떻게 되겠습니까? 그래프 상 끝이 보이지 않습니다. 무슨 의미입니까? 사용자가 10명 20명 30명 이렇게 선형적으로 증가할 때, 850여명까지는 그나마 100개 이하의 수행 중인 서비스들이 나름대로 안정된 서비스를 하고 있게 되지만, 852명을 넘어서는 순간부터 급격하게 수행 중인 서비스의 개수가 증가합니다. 즉 큐잉현상이 발생한다는 것입니다. 그렇다면 852라는 수치는 무엇을 의미합니까? 바로, 10초당 한번씩 호출한다는 가정 하에 최대로 수용할 수 있는 동시사용자를 의미합니다. 또한, 이렇게 구한 852라는 수치는 앞서 최대 TPS인 83.3에서 구한 833명과 그 수치상에서 매우 유사하다는 것을 확인할 수 있습니다.
이처럼, 웹 기반 시스템에서는 동시단말사용자가 증가하면 그것에 거의 정비례하여 단위시간당 호출하는 건수가 증가하게 됩니다. 그러나, 호출빈도가 선형적으로 증가할 때, 그에 따른 수행중인 서비스개수(즉, 깔때기의 물의 높이)는 선형적으로 증가하는 것이 아니라, 어떤 임계점, 정확히는 호출빈도가 최대 TPS를 넘어서는 시점부터 해당 시스템은 급격하게 느려지는 현상이 심화되며 서비스가 지속적으로 큐잉되어 결국 Hang현상이라는 서비스장애가 발생하게 됩니다.
질문 10 : 스트레스 테스트시 Active Thread/Client 수치와 향후 실제 동시 사용자에 대한 상관 관계에 대한 매핑이 의미가 있는가?
두 수치 사이에는 어떠한 상관관계도 없다.
부하라는 것은 개별 사용자가 어떤 응용 어플리케이션을 몇 초마다 호출하느냐 하는 Think-Time에 의해서 결정되어지며, 서버측에 단위시간당 몇 건의 호출을 주고 있다는 “호출빈도”와 관련된 개념입니다. 반면, 스트레스 테스트 시의 Active Thread/Clients는 현재 항상 수행중인 서비스가 몇 개이냐라는 개념입니다. 예를 들면, 앞서 깔때기에 물을 붓는 행위에서 동시사용자에 따른 호출빈도라는 것은 단위시간당 어느 정도의 물을 붓고 있느냐라는 전송량을 의미하고 있다면, Active Thread/Clients의 개념은 그래서 그 깔때기의 물의 높이가 얼마냐라는 의미를 갖고 있습니다. 물높이가 높다는 것이 단위시간당 전송량이 많다는 것을 의미하지는 않잖습니까. 중요한 것은, 해당 시스템의 최대TPS가 얼마냐 그리고, 사용자들의 호출패턴을 분석하여 몇 초마다 호출하느냐 하는 Think-Time을 구하여, 그래서 몇 명이면 그 호출빈도를 발생시키겠는가를 맵핑시켜야 합니다.
“마의 8초”라는 말이 있습니다. 시스템을 사용할 때, 응답속도가 8초를 넘어서면, 인간이 느끼기에 “느려서 못쓰겠다”라는 느낌을 받는 응답속도라고 알려져 있습니다. 따라서 사용자는 8초를 넘어설 때부터, 정상적인 응답이 끝까지 올 때까지 기다려주지 않게 됩니다. 결국, 위 그래프에서 보듯, “속도저하 허용정도”에 따라, 실제 운영시의 응답속도 그래프는 최대 허용 동시사용자 시점부터 급작스럽게 위로 치솟게 됩니다. 반면 스트레스테스트시는 응답이 느려지더라도 응답이 와야 만이 다시 호출을 합니다. 따라서 스트레스테스트시 응답속도가 느려지는 후반부 구간의 그래프는 클라이언트/서버시스템에서는 의미를 가질 수 있지만, 웹 기반 시스템에서는 다른 양상이 나타납니다. 최대의 TPS가 나타나는 한계사용자수 이후는 계속적인 서비스 큐잉현상이 일어나면서 응답시간은 급격하게 느려지는 장애상황으로 이해해야 합니다.
응답속도에 대해 고려할 부분은 딱 한가지가 남습니다. Saturation Point가 발생하는 시점에서의 평균응답속도가 해당사이트가 충분이 받아들일 수 있는 응답시간 허용한도 기준치 내에 있느냐라는 것이 그것입니다. 그 이후의 응답속도 곡선은 스트레스 테스트 시에서나 나타나는 평균응답속도일 뿐인 것입니다. 실 상황에서는 벌어지지 않습니다.
순수하게 응답속도의 그래프만으로도 상대적으로 어느 것이 더욱 확장성이 높고 더 많은 동시단말사용자를 받아들일 수 있을 것인가를 직관적으로 이해할 수 있기는 합니다. 위 그래프가 보여주고 있듯이, 응답속도가 급격히 느려지는 시점이 보다 우측에 존재할 때 더욱 안정적이라는 것이지요. 그러나 이 그래프는 실 환경에서의 부하량을 나타내고 있지는 않으며, 따라서 최종적으로 확장하려는 목표 시스템에 대한 성능을 예상할 수 있는 자료는 아닙니다..
가급적 모든 개별적인 응용 어플리케이션에 대한 TPS 그래프를 그려서 성능수치(최대TPS)를 구하고, 그 TPS를 높이려는 시도를 하는 것이 곳 튜닝이고 성능개선 행위입니다. 과거치의 웹 로그 자료가 있다면 Peek Time시에 기록된 사용자들의 호출패턴분석을 통해 평균 Think Time을 확인하여 동시단말사용자와 단위시간당 최대 호출빈도를 계산 하십시오. 만약 호출 빈도가 앞서 스트레스테스트를 통해 구한 최대TPS를 넘어가고 있다면 이는 H/W증설이나, 혹은 해당 성능저하를 극복할 수 있는 여하한의 방안을 강구해야 하는 시점인 것입니다. 반면, 그 사용자들의 호출빈도가 해당 응용 어플리케이션의 최대 TPS에 아직 못 미치고 있다면, 해당 시스템은 적어도 아직까지는 성능상의 문제가 없는 것입니다.
질문 11 : WAS의 설정에 보면 Thread의 개수를 정하는 항목이 있다. 이러한 Thread의 개수를 정할 때 기준은 무엇으로 하면 되는가?
서로 다른 n개의 응용어플리케이션이 동시에 서비스할 때, 최대의 성능을 나타내는 임계점(Saturation Point)에 개수를 맞춘다. Thread의 개수를 Saturation Point보다 많은 수로 잡을 경우에 만일 장시간 지속되는 Peak시의 경우에는 많은 수의 Request가 Queuing이 되어서 결국에는 Hang현상이 발생 하게 된다.
만약, 초당 10개씩 밖에 처리하지 못하는 웹사이트에서 초당 12개씩 HIT가 들어온다면, 초당 2개씩 큐잉 현상이 일어날 것이며, 10초이면 2*10=20 개의 서비스가 응답을 받지 못하고 큐잉 될 것이며, 불과 1분이면 2*60 = 120 개의 서비스가 큐잉 될 것입니다. 이는 장애현상, 즉 hang현상에 직면하고 있다는 의미가 됩니다.
충분히 높은 깔대기는 버퍼링 효과를 볼 수 있고, 따라서, 버퍼가 클 수록 좋은 것이 아니냐는 생각을 하고 있을 겁니다. 이 가정은 수도꼭지의 물이 나오는 속도가 가변적일 수 있다는 것, 그래서 과도할 땐 비축해 두었다가(Queuing) 적게 나올 때 모아둔 물을 흘러내리게 하겠다는 것이겠지만, 어쨌든 충분히 긴 일정단위시간당 수도꼭지의 방출 속도가 깔대기의 흘러내는 속도를 전체적으로는 넘어서지 말아야 한다는 부분에서는 동일한 제한을 받습니다. 또한, 깔대기의 예가 아니라, 웹기반 시스템에서의 실질적인 부하량(workload)의 특징은, 동시단말사용자가 많은 시스템일 수록, 특정시간 근방에서는 항상 일정한 HTTP arrival rate 이 발생합니다
질문 12 : 응용 어플리케이션 x,y,z 3개가 있고 이들 최대 TPS가 각각 400,9, 50이라고 가정했을 경우 향후 시스템이 오픈되면 어떤 어플리케이션이 가장 문제를 야기할 것인가?
성능이 가장 낮은 y가 가장 문제가 될 것이라구요? 어떻하죠? 막상 오픈하니 y는 거의 불려지지 않았는데…., 한번도 안 불려졌다면 문제를 일으키고 말고 할 것도 없잖습니까. 이번엔, 서비스를 오픈 하고 나서 서비스를 잘 하긴 했는데, Peak시간대에서 어플리케이션 x,y,z 가 각각 1초당 48.2, 1.2, 22,7 Hit/sec 의 호출빈도로 요청이 들어왔다고 가정해 봅시다. Hit/sec 만 놓고 본다면 어떤 것이 가장 향후에 문제를 일으킬 가능성이 높습니까? 가장 많이 불려진 서비스 즉, 1초당 48.2 건이나 호출된 어플리케이션 x가 가장 문제가 될 것 같다구요? … 정말 그럴까요? x의 최대 성능은 자그마치 1초당 400건이나 처리할 수 있는 상대적으로 무지 성능이 높은 어플리케이션인데도 그럴까요? 즉, 어떤 어플리케이션이 가장 성능상 문제를 야기하겠느냐는 것은 그 어플리케이션의 성능과 실제 불려진 호출빈도의 관계 속에서 상대적으로 결정될 수 있다는 것을 말하고자 합니다. 최대성능대비 얼마나 불려졌나를 나타내는 tj/Ti 값이 가장 큰 것이 가장 성능상의 문제를 안고 있다는 것이지요. 위 예에서는 tj/Ti가 0.45로 가장 높은 수치를 보이므로, 사실은 문제가 있다면 어플리케이션 z가 가장 문제라는 것입니다. 그리고, 각 tj/Ti를 모두 합한 ∑{ti/Ti}값은 0.12 + 0.13 + 0.45 = 0.70, 즉 이 시스템의 성능지수는 70%입니다. 여기서 말하는 70%라는 것은 병목현상의 요인이 CPU에 있든 메모리에 있든, 혹은 backend 서비스의 성능저하에 있든, 어플리케이션 x,y,z가 특정한 호출빈도 (48.2, 1.2, 22.7)로 들어 올 때, 최대 임계성능에 도달하기 까지 현재 70% 수준에 와 있다는 것을 뜻합니다. 경우에 따라 다르겠지만, 사이트 성능진단의 경험에 비추어 보면, CPU가 100%에 도달하여 장애를 일으키는 경우는 극히 드문 경우입니다. 대부분의 사람들이 성능을 얘기하면 CPU나 메모리를 떠 올리는데, 사실은 어플리케이션 내부 로직과 같은 다양한 요인이 더 많습니다,
질문 13 : 웹 어플리케이션서버의 성능장애 유형 중, 왜 대다수가 CPU사용률이 높지 않은가
웹 어플리케이션서버 기반 하에서 운영되고 있는 국내 시스템 장애진단을 경험하다 보면, CPU 사용률이 100%에 다다르면서 장애가 발생하는 경우는 극히 드뭅니다.
CPU사용률이 100%에 이르면서 장애가 일어나는 상황은 일반적으로 다음과 같은 경우가 있을 수 있습니다.
1) 모든 응용어플리케이션들이 매우 잘 튜닝 되어 있는(fine-tuned) 상황에서, 동시단말사용자수 증가로 인한 (상대적) 부하증가(Arrival rate workload increasing)현상이 일어나고, 결국 CPU bottleneck으로 인해 성능저하 및 응답지연현상이 발생하는 경우입니다.
2) 특정 응용어플리케이션 하나가 CPU bounded-job이고, 이러한 batch성에 가까운job이 OLPT환경에서 치고 들어올(?) 경우, CPU 사용률이 급정 하여, 결국 그 동안 잘 운영되던 응용어플리케이션들 마저 제 기능을 수행하지 못하는 경우도 있을 수 있었습니다.
3) Backend Legacy 연동을 위해 한글변환이나, 데이터 변환과정에서 해당 패키지 코드가 최적의 방법으로 Optimizing 되어 있지 않아, 상대적으로 불필요한 CPU 점유를 가져오는 경우도 있었습니다.
4) 예외적인 경우기는 합니다만, 일종의 어떤 응용어플리케이션버그로 인해, 간단한 block의 무한루프 현상에 빠지게 되어 CPU 100% 현상이 일어나는 경우도 있었습니다.
그러나, 웹 어플리케이션서버(Web Application Server) 기반의 EJB/Servlet/JSP 등과 같은 JAVA언어로 구현된 최근 시스템의 경우는, 웹 어플리케이션서버는 process-based로 동작하는 것이 아니라, (일반적으로) 하나의 process에서 다수의 Multi-thread로 동작하게 됩니다. 또한, Java언어에서는 세마포와 같은 thread locking 기법이 매우 간단하게 구현할 수 있기 때문에, C/C++ 언어에서의 Multi-thread 코딩 기법과 같이 (상대적으로) 전문적인 기술을 가진 개발자의 일정능력을 요구하진 않습니다. 그러다 보니 상대적으로 Java에서의 Multi-thread 구현상에 있어서, 성능을 고려치 않은 자바소스가 양산되는 경향이 있습니다.
국내 수십 군데에서의 웹 기반 시스템 장애진단 경험에 비추어 보았을 때, 응답이 급격히 느려지는 "서비스큐잉/Hang현상"이 발생할 당시의 시스템의 상황을 보면, 사례의 90%이상이 전부 CPU사용률은 그리 높지 않습니다. 오히려, 장애 없이 잘 운영될 때가 더욱 CPU사용률이 높습니다. 어플리케이션 리소스 bottleneck 이라는 얘기지요. 마치 DB lock 이 발생하면, 모든 요청이 큐에 대기하게 되고, 결국 실제 processing 하고 있는 서비스 Job의 개수는 많지 않으니 CPU 사용률은 오히려 낮을 수 밖에 없다는 것을 예로 들 수 있습니다. 응용어플리케이션 내에 존재하는 synchronized 키워드를 남발하는 경우도 있을 수 있습니다. 성능적인 측면에서 다양한 경험이 있는 개발자의 조언이 반드시 필요한 부분인 것이지요. 또한, HOST의 CICS Transaction을 사용하기 위해 CTG(CICS Transaction Gateway) API를 이용하여 접근하게 되는데,이 부분에 대한 Java측의 코딩이 성능을 고려하여 smart하게 되어 있지 않을 경우, 유사한 상황에 직면할 수도 있습니다.
울산 모 고객사의 경우를 대표적인 예로들 수 있습니다. CTG API중 실질적인 communication 을 담당하고 있는 Java Gateway Instance를 서로 다른 요청에 대해 공유하고 있다거나, 혹은 Java Gateway를 통한 통신상의 성능향상을 위해 Java Gateway Pool를 사용하고 있을 수도 있는데,이 역시, Multu-thread환경에 익숙한 개발자에 의해 검증되어야 할 것입니다. 거듭 강조하지만, 경험적으로, 성능상의 이유로 장애상황이 발생하면 CPU사용률은 높지 않는 것이 일반적인 현상입니다. CPU 100%가 올라가면서 장애가 일어나는 경우는 오히려 매우 고무적인 상황이며 CPU만 추가하면 해결되는 문제이기도 합니다. 그러나, 이런 경우는 아쉽게도 극히 드문 현상입니다. 이러한 현상을 C/S 시스템의 장애해결에 익숙한 분들은 쉽게 받아들이지 않으시더군요.Client/Server환경에서는 대부분이 process 기반의 프로그램들이 대부분이었고, 사용자 증가는 곧바로 독립된 process의 CPU사용증가를 가져왔기 때문에,상대적으로 C/S환경에서는 CPU bottleneck에 의한 현상이 대표적이었을 것입니다. 무엇보다 중요한 것은, 업무적 차원에서 추정할 수 있는 최대 동시단말사용자수와 최근 며칠 동안 (비록 장애상황에 직면하였지만) 모니터링 된 웹 로그분석을 기반으로 실제 발생하고 있는 workload를 측정하고 모델링 하여 성능테스트를 시행하고, 종합적인 관점에서의 성능진단작업이 반드시 필요합니다. 일련의 경험을 통해 깨닫게 된 사실은, 부하량/성능모델링 관점에서의 CPU자원은 N/W용량이나 Worker Thread의 개수 혹은 Disk I/O, Backend System Connectivity 혹은 응용어플리케이션의 Over Locking(과도한 synchronization 혹은 Transaction Lock) 등과 마찬가지로, Bottleneck을 유발하는 하나의 큐(Queue)일 뿐이라는 것입니다. n개의 서로 다른 응용어플리케이션들에 대한 서로 다른 호출빈도(arrival rate)와 각 응용 어플리케이션들의 최대 Throughput들을 n차원 유클리드 공간상에서 표현했을 때, 병목을 유발하는 다수의 큐(Multiple Queue)들에 의한 임계성능평면(가칭)이 결정되고, 이러한 각 평면이 만나 일련의 병목 경계면을 형성하게 된다는 [다중 병목임계면이론(가칭)]을, 큐잉이론(Queuing Theory)를 응용하여 고민하는 중인데, 이러한 관점에서 보면, CPU에 의한 병목은 최근의 J2EE기반의 웹 어플리케이션서버 환경하에서는 상대적으로 잘 도출되지 않습니다. CPU가 병목으로 나타나기 이전에, 다른 병목임계평면과 먼저 직면하기 때문입니다.
질문 14 소스 상에 synchronized와 같은 동기화 block을 통해서 오히려 전체 response time에 어떠한 영향을 미치는가. 또한 속도를 재고자 하는 블록에 여러 개의 synchronized 블록이 있을 경우 전체적으로 Throughput은 어떻게 되는가.
많은 사람들이 잘못 생각하고 있는 부분이 Connection Pool의 getInstance(), getPooledObject() 류의 method가 synchronized 되어 있기 때문에, 한 순간에 하나씩 처리되어 전체적으로 "성능"이
떨어진다고 쉽게 단정한다는 것입니다. synchronized 는 필요할 때 적절히, "반드시" 사용되어야만 하는 것입니다. "아무리 부하를 주어도, RPG는 2-3 개 밖에 running하고 있지 않다"는 것은 많은
것을 시사하고 있습니다. 분명 RPG 호출로 인한 backend 서비스는 현재의 성능 저하와는 다소 거리가 있다는 것은 분명합니다. 그렇다면 어디일 것인가를 찾아야 하는데, 그 한 예로써, Pool에서 Pooled Object를 꺼내오는 synchronized getPooledObject()류의 method를 의심해 보는 것은 자연스럽기는 합니다. 해당 block의 구현을 얼마나 간결하고 핵심적으로 코딩 하였느냐가 관건이지요. 최근 찾아낸 수식을 제 머리 속에만 간직하고 있다가, 저 아닌 다른 분에게는 오늘 처음으로 몇 자 적어봅니다. synchronzied block S 가 있을 때, 해당 구간에 대한 단일요청에 따른 응답속도(ElapsedTime)가 s (sec)라고 했을 때, 해당 구간에 대한 최대 Throughput은 1/s (request/sec)가 됨을 쉽게 추론할 수 있습니다. synchronized 되어 있으므로, 해당 구간의 소요시간이 1 ms 라면 해당 구간으로 인한 Throughput은 최대 1000 TPS가 될 것이고, 해당 구간에서 100 ms가 절대적으로 소요된다면 최대 10 TPS가 될 수 있겠지요. 반면, synchronized가 걸려있지 않은 적어도 1/s (request/sec)보다는 클 것입니다. 이는 해당 block의 bottleneck으로 작용하는 resource에 따라 달라지는 것이지요. bottleneck으로 작용하는 resource라는 것은 CPU, Backend Service(RPG처럼), Worker-Thread의 개수,Pool의 최대개수, 응용어플리케이션의 over-locking 구간 등등이 모두 Bottleneck의 원인일 수 있으며, 이를 큐잉 이론 관점에서 보면 모두 한계(boundary)를 갖고 있는
"One of Queue"라는 것입니다.
프로그래밍 소스 block A 및 B 구간이 있다고 가정하고, 각 block A, B 구간의 각각의 단위시간당 최대처리건수인 최대 Throughput이 각각 10 TPS, 20 TPS(transaction per second)라고 합시다. 만약, Block A, B구간을 같은 소스에 순차적으로 넣고 최대 Throughput을 측정하면 최대로 얼마가 나올까요?
case 1 : 10 TPS
----------------
program block A
----------------
case 2: 20 TPS
----------------
program block B
----------------
case 3: ?TPS
----------------
program block A
program block B
----------------
답은 ,
1 10*20
----------- = ------- = 6.6666 TPS 가 됩니다.
1 1 10 + 20
--- + ---
10 20
다음과 같은 공식입니다.
1
(Throughput of block A & B) = -----------
1 1
--- + ---
a b
(위 수식은, 차후에 다시 자세히 증명할 기회가 있을 겁니다.)
A구간이 최대 10 TPS였으니, Logic B가 추가되면 전체는 최소한 10TPS보다는 작을 것이고,마찬가지로 구간B의 최대 TPS인 20 TPS보다도 작을 것입니다. 만약, 특정 구간 B의 Throughput b가 상대적으로 A구간의 Throughput a에 비해 TPS가 엄청나게 크다면, 두 구간을 합한 TPS는 구간 A의 최대 TPS a에 매우 가까울 것입니다. 왜냐면, 1/b 에서 b값이 상대적으로 100, 1000, 10000 등과 같은 수치일 경우 위 수식은 a 에 가까운 수치가 될 것이잖습니까?
예) 구간 A, B에 대한 각각의 Throughput이 각각 5 TPS, 1000 TPS일 때, 구간A, B를 순차적으로 하나의 Block으로 만든다면, 최대 몇 TPS가 나올 수 있을까요?
1 / {1/5 + 1/1000} = (5*1000)/(5+1000) = 4.975 TPS
무슨 얘기를 하고자 하는 것이냐 면, ConnectionPool에서 synchronized로 되어 있는 getInstance(), getPooledObject() 부분의 throughput은 (경우에 따라 다르겠지만)응용어플리케이션의 throughput에 비해 상대적으로 매우 큰 수치입니다. (상대적으로) 매우 짧은 순간만 해당 부분을 타는 것이지요. (사실 중요한 것은 "그 짧은 순간"이 얼마나 짧으냐가 중요합니다. synchronized된 해당 구간의 Throughput은 1/(그 짧은 순간) 이라는 절대적인 Throughput으로 나타나기 때문입니다.) 따라서, synchronized block의 Throughput이 상대적으로 응용어플리케이션의 Throughput보다 충분히 크면, 해당 synchronized block으로 인한 성능저하는 (상대적으로) 적을 수 있다는 것입니다. (PooledObject를 Pool에서 꺼내오는 부분은, 단지 가용한 Reference를 꺼내오는
것이 전부일 것이며, 해당 구간의 Throughput은 "충분히" 문제시 되지 않을 수 있습니다.)
질문하신 분의 상황은, 보내주신 글만으로는 판단할 수 없습니다. 소스를 열어보고, 예상되는 성능저하구간을 설정한 뒤, 스트레스테스트를 통해 어느 부분에서 가장 성능이 저하되는 지를 찾아보아야 합니다. 현재로서는 getPooledObject() 그 자체일 수도 있으나, 일단 꺼내온 뒤, RPG를 실제 호출하기 전 초기화 작업이나, 호출 이후의 데이터 Parsing을 위한 구간일 가능성도 배제할 순 없습니다. 설령 getPooledObject() 부분에서 많은 시간이 소요된다면, 그 자체가 문제가 아니라, 응용어플리케이션이 PooledObject를 Pool에서 꺼내간 후, 오랫동안 해당 자원을 사용하기 때문일 수도 있습니다. 물론, synchronized가 걸려 있는 Block에서, 불필요한 잡다한 작업을 넣어 compact하지 않은 코딩을 했을 가능성을 배제할 수 없습니다. 해당 부분은 적어도 위와 같은 이론적 이해를 바탕으로 해당 사이트의 workload량과 H/W용량 및 S/W의Throughput을 고려하여 설계->코딩->Stress Testing->튜닝 과정을 거쳐 반드시 검증되어야 하는 것은 당연합니다. Performance Analysis는 종합예술"이잖습니까. Performance 튜닝 관련한 문서에서 항상 언급하고 있는 것 중의 하나가 synchronized 입니다. synchronized 블록으로 스레드가 진입할 시, 모니터를 획득하기 위해 소요되는 시간도 적지 않거니와 무엇보다도 하나의 Thread가 synchronized 블록을 빠져 나오기까지 다른 Thread는 그 곳에서 대기해야 하기 때문이지요. 이 중, 모니터를 얻기 위해 소요되는 CPU자원은 요즘의 CPU의 빠르기를 감안하고, 또한, 일반적인 시스템 내에서 일어나는 다른 작업, 예를 들어, 데이터의 삽입, 수정, 검색등과 비교한다면 그야말로 매우 미미하여 사실상은 무시해도 상관이 없을 정도입니다.(물론, 수억, 수 십 억 번 이상의 산술적인 계산 등을 반복적으로 행하는 주로 자연과학이나 공학계산용의 어플리케이션에서라면 이러한 작은 시간도 매우 중요하겠죠.) 그렇다면 정말 문제가 될 수 있는 것은 synchronized Block으로 인해 발생하는 Thread들의 wait(큐잉) 현상 일 것입니다. 그런데, 여기에서의 스레드 직렬화 즉, Queuing 현상으로 인해 이 지점이 병목의 주된 원인이 되기 위해서는, 이 블록 내에서 실행되는 Logic의 처리시간이 다른 어떤 Queuing 가능 블록의 처리시간보다도 길어야 합니다.보통, 커넥션 풀에서 커넥션을 얻어오는 Logic은(getConnection())은 synchronized 블록으로 묶여있습니다. 그런데, 커넥션 풀에서 커넥션을 얻어와서 리턴 해주는 Logic이 소요되는 시간이 얼마나 될까요? 이 또한, CPU의 Cluck속도와, 메모리와 CPU간의 데이터 교환 속도, 교환되는 바이트 수를 생각하고, 또한 시스템 내의 다른 Logic과 비교했을 때 엄청나게 미미하여, 거의 신경을 안 써도 될 정도입니다. 여러분은 1초 내에 수천 혹은 수만 번 이상의 getConnection()을 실행시킬 수 있습니다. 만일, getConnection()의 throughput 이 10000TPS 라면, 10000TPS 미만의 throughput을 가진 Logic이 있지는 않을까를 생각해 보세요. 그런 부분이 있다면, 그 부분을 먼저 개선시켜서 10000TPS 이상의 Throughput을 갖게 한 후에, getConnection()의 수행성능 향상을 고려해보시기 바랍니다. 그러나, 대부분의 데이터 처리 로직(대표적인 것이 데이터베이스에 대한 질의입니다.) 아무리 해도 이만큼의 throughput을 보장할 수 없을 것입니다. 따라서,getConnection()에서 사용되는 sychronized 블록은 병목의 용의자 선상에서 아예 제외시키는 것이 정신건강(?)에 좋을 것입니다. 실제로, synchronized 블록은 시스템 내에서 엄청나게 많이 사용됩니다. 아무 생각 없이 사용하실 지 모를 Vector 나 Hashtable 을 열어 보십시요. 셀 수 없이 많은 synchronized 블록이 있는 것을 보실 수 있을 것입니다. 기억하십시요. Synchronized 블록의 사용 자체가 문제가 아니라, synchronized 블록 내에서 실행되는 로직의 수행시간만이 문제가 될 수 있다는 것을