[Q] 다수의 쓰레드 풀을 이용한 클라이언트 서버 통신프로그램 개발시 어려운 점

김남도의 이미지

혼자서 삽질하다가 질문을 올립니다.

클라이언트 서버 통신에서 서버부문의 개발을 해보려고 합니다.
그러나, 어려운 점이 많아서 질문을 드리고자 합니다.

서버에서 클라이언트 동시사용자는 500 유저를 수용하고자 합니다.
방식은 500개의 쓰레드 풀을 만들어 두려고 했습니다.

서버의 하드웨어 메모리가 512M인 관계로 쓰레드 생성이 안되더군요.
단독 프로그램에서 생성가능한 숫자가 256개로 제한이 되더군요.

그래서 가능한 방법을 파악하고자 분리하려고 작업을 하였습니다.

자식프로세스는 세개의 쓰레드로 구성되어 있습니다.
쓰레드 펑션1에서 처리할 일은 부모프로세스에서 Socket을 통하여 clientfd를 받아와
클라이언트와의 통신을 담당합니다.

쓰레드 펑션2에서 처리할 일은 데이터베이스의 내용을 확인하는 프로그램과 소켓통신합니다.
데이터베이스에서 읽어올 내용이 많아서 어쩔 수 없이 미리 메모리에 올리기 위한 편법으로
프로그램을 하나 더 띄워야 할 것 같습니다...-_-

쓰레드 펑션3에서 처리할 일은 클라이언트의 접속을 부모 프로세스로부터 소켓통신으로 받아와
[문1] "현재 자식 프로세스가 클라이언트의 접속을 처리중이면 Busy를 알려주고 작업이 끝나면
IDLE문자를 송신하여 작업 가능함을 알립니다."

자식 프로그램 내의 세개의 쓰레드에서 각 쓰레드간의 통신은 Mutex를 사용하려고 합니다.
여러가지 방법을 고안하고 fork를 써보고, execpl을 써보기도 하였으나,
[문2]"부모프로세스에서 자식 프로세스를 여러개 구동하지 못하는 현상이 발견되었습니다."

부모 프로세스를 실행시켜둔 상태에서 콘솔을 여러개 띄우고 자식프로그램을 실행하면,
여러(약 30여개)개의 자식프로세스는 부모프로세스와 통신에 문제가 없습니다. 소켓통신에
이상은 없어보입니다.

[문1]에서 소켓통신이 아니라, FIFO를 통한 작업을 수행하려고 테스트 해보았으나,
[문2]의 문제로 인하여 FIFO도 실패한 상태입니다.

============================================================================
두서가 없는 것 같아서 정리해서 다시 질문을 드리고자 합니다.

부모프로그램 :
클라이언트의 접속요청을 감지하여 IDLE인 자식 프로세스로 던져주고, 풀상태를 관리합니다.
자식프로그램을 실행시킵니다.(희망사항은 500개입니다.-숫자상으로는 1500개가 넘는
쓰레드가 돌아가겠군요)

자식프로그램 :
실질적인 클라이언트와의 통신을 담당합니다.
데이터베이스의 내용을 확인합니다.
부모프로그램에게 자신의 현재 상태를 알립니다.(Busy, Idle..)

[문1]에 해당하는 내용을 퍼포먼스를 감안한다면 FIFO가 좋습니까? 아니면, 쓰레드를 사용한
소켓통신이 좋습니까?

[문2] 500개의 쓰레드 풀을 기동하기 위한 방법을 찾는 과정에서 fork()는 사용할 수 없음을
알게 되었습니다. 프로세스가 생성되는데 걸리는 시간이 너무 오래 걸리는 것으로 판단되었기
때문입니다.

헤매고 있습니다.....뭘 질문했는지도 모르겠습니다.....쑥덕같은 질문에

찰떡같은 대답을 원하는 것은 상당한 철면피일지도 모르겠으나, 2주가 넘도록 제자리에서 맴돌고

있다보니 도움을 청할 수 밖에 없네요.

이해에 도움이 되고자 그림을 첨부해 봅니다.

File attachments: 
첨부파일 크기
Image icon Concept.JPG31.93 KB
kewlbear의 이미지

프로세스에서 만들 수 있는 최대 스레드 수는 커널 파라미터를 바꾸면 될 것 같습니다만 스레드가 500개라면 메모리가 너무 부족한 것 같네요. 그리고 스레드를 미리 만들어 놓는 스레드 풀처럼 fork도 미리 해놓는 preforked 방식이 있습니다. 이런 방법에 대한 자세한 사항은 Unix Network Programming을 참고하세요.

김남도의 이미지

prefork의 경우 생성되는 프로세스의 갯수를 조정하기가 힘들더군요.

2* 형태로 늘어나니 512개에서 제한이 되기는 합니다만,

500개를 초과하는 프로세스의 생성으로 인하여.....

fork를 사용한 테스트의 경우 '자원부족' 메세지가...큼큼.....나더군요.

한개의 쓰레드를 올리고, fork를 300여개 진행할 즈음에서 나옵니다.

말씀하신 것처럼 서버의 업그레이드를 적극 고려하여 보아야겠습니다.

도대체가 'free memory 40M'로 뭘 할 수 있는지...프로세스 500개 올라갈 수나 있는지..

하드의 스왑영역을 확장하여 구성하는 것도 생각해보았습니다만,

퍼포먼스면에서 그다지 안정성을 보일것 같지도 않고,

근본적인 해결책이 아니라는 생각이 들어 일단 미루어둔 상태입니다.

......아는것이 워낙적다보니 방법은 많을 것 같은데, 딱히 '이거다'라고 떠오르는 것이 없네요.

답글 주신것에 대하여 감사하게 생각합니다.

또 삽질하러 가야겠습니다.

좋은 하루 되세요.

kane의 이미지

[문1]과 관련해서, 저라면 작업의 편의성을 위해서 소켓을 사용하겠습니다. 퍼포먼스 차이가 크지 않으리라고 생각하고, 어느 정도 차이가 있더라도 중요한 부분은 아니라고 생각합니다. 그 부분만을 위해 특별히 FIFO를 사용할 필요는 없을 것 같습니다.

쓰레드 풀을 이용할 때, 하나의 쓰레드가 하나의 클라이언트를 전담하면 쓰레드의 수가 너무 많아집니다. 쓰레드를 클라이언트 단위 대신, 작업 단위로 분배하면 좋습니다.
즉, 1번 클라이언트가 'ㄱ'작업을 요청했을 때, A 쓰레드를 할당합니다.
작업이 끝나면 A 쓰레드를 반환합니다.
2번 클라이언트가 'ㄴ' 작업을 요청했을 때, 다시 A 쓰레드를 할당합니다.
그 와중에 1번 클라이언트가 'ㄷ'작업을 요청했을 때, B 쓰레드를 할당합니다.
이런 식으로 구성하는 거지요. 그러면 더 적은 쓰레드 수로도 많은 클라이언트를 서비스할 수 있습니다.

김남도의 이미지

말씀하신 작업요소 단위의 역할분담의 경우,

클라이언트의 환경이 여유가 있다면 그렇게 하겠지만,

클라이언트가 카드리더이고, 전용 단말이라 부하를 줄이기 위하여

상당부분의 비즈니스 프로세스가 서버로 들어와 있는 상태입니다.

안그래도 단말에 기능이 너무 많이 들어갔다고 궁시렁대는 ...때문에

커넥션을 확인하고, 이것을 확립하기 위한 로직을 단말로 넘기는 것조차

말을 꺼내기가 ...한 상황입니다.

서버의 상태도 구리구리한데 말입니다...쩝.

네트웍 상태는 저도 잘 모르겠습니다...런칭하는 시점이라..

혹 이부분에 대한 정보를 가지고 계신것이 있다면 알려주시면 감사하겠습니다.

참고로 신용카드 단말기와 유사한 형태이나, 서비스가 '많이' 들어갑니다.

kane의 이미지

작업요소 단위로 역할을 분담한다는 게 작업 요소 단위로 커넥션을 재연결한다는 뜻은 아닙니다. 클라이언트는 원하는 기간동안 서버에 연결된 상태로 있을 수 있습니다. 클라이언트가 연결되었다고 해도 연결된 기간내내 쉼없이 작업을 요청하는 경우는 드뭅니다. 연결된 상태 하에서 작업 요청이 있을 경우 쓰레드를 할당해서 작업을 처리하고, 작업이 끝나면 쓰레드를 반환합니다. 하나의 작업이 끝났다고 연결을 끊을 필요는 없습니다. 따라서 클라이언트 쪽은 별로 변경할 부분이 없습니다. 대신 서버 측은 좀 변경을 가하셔야 할겁니다.

서버는 업그레이드 해달라고 졸라보세요. ^^; 메모리도 가능한 팍!팍! 꽂으시구요. 컴퓨터는 메모립니다. ㅎㅎ

김남도의 이미지

말씀하신 점에 대하여 쓰레드 생성의 오버헤드는 어느정도일까 궁금해집니다.

클라이언트에서 어떤 사태가 발생하지 않기를 바랄뿐입니다.

.....변경...이 아니라 뒤집어야 할 것 같네요...

서버의 업그레이드는 내일 오후에 미팅잡혔을 때 '강력하게' 어필을 해볼 생각입니다.

다만...400만원짜리 프로젝트에서.....얼마나..-_-;;;

kane의 이미지

(쓰레드 풀을 사용한다고 하면) 한 번 생성한 쓰레드를 재활용하는 것이기 때문에, 쓰레드 생성 오버헤드는 서버 구동시에 한 번 발생하는 것외에는 없습니다. 쓰레드를 할당하는 것은 새로 쓰레드를 만드는게 아니라, 이미 생성된 쓰레드에 정보를 전달하고 실행을 재개하도록 하는 겁니다.

400만원짜리 프로젝트면...... 쓰레드는 '원래' 250개 밖에 안 생긴다고 버티......면 안되겠죠? 안되려나요? 안될지도 모를까요? 안되지만은 않을지도 모르지 않을까요? ㅡ_ㅡ;;

김남도의 이미지

말씀하신대로 해보려고 하는데, 클라이언트 정보를 담는
구조체 접근에 있어 안정성을 확보하려면, 뮤텍스나 세마포어를
사용해야 할 것 같더군요.
뮤텍스 사용과 세마포어간의 특이점이나 큰 차이점이 발견되지
않는다는 글들을 보아서인지....

귀차니즘의 압박을 억지로 누르고..사실은 졸린 눈을 비비며..
이것저것 자료를 찾아보고 있습니다.

그 400만원의 비용에 웹프로그래머 두명, 저. 기간 한달내.....
거기에 서버 업그레이드 요청하면 뭐가 남을런지...
그래도 업그레이드 하자고 우기면 될까요? 되려나요? 될 수도 있지 않을까요? 될수도 있지도 않을까요?
업그레이드 할 수 없나요?......우울해지네요..

이런 프로젝트 들어가라고 등떠민 오너가 싫어집니다.
대체 계산기는 두드려보기나 한건지 원...
이런 프로젝트 들어가라고 등떠민 오너를 믿어야 하는건지...
앞으로도 이런 프로젝트가 또 떨어지면 어찌해야 할지......

비도 오는데 오늘은 일찍 들어가 웹사이트를 배회해야 할지도 모르겠습니다.
또....구직인가...ㅠ_ㅠ

댓글 주셔서 감사합니다.

IsExist의 이미지

pthread_create() 호출시 stack 사이즈를 줄여서 테스트 해봐서 스택 사이즈가 작을시에 생성이
늘어난다면 실제 스레드 메인 함수가 사용하는 스택사이즈를 감안해서 줄여보시기 바랍니다.

---------
간디가 말한 우리를 파괴시키는 7가지 요소

첫째, 노동 없는 부(富)/둘째, 양심 없는 쾌락
셋째, 인격 없는 지! 식/넷째, 윤리 없는 비지니스

이익추구를 위해서라면..

다섯째, 인성(人性)없는 과학
여섯째, 희생 없는 종교/일곱째, 신념 없는 정치

---------
간디가 말한 우리를 파괴시키는 7가지 요소

첫째, 노동 없는 부(富)/둘째, 양심 없는 쾌락
셋째, 인격 없는 지! 식/넷째, 윤리 없는 비지니스

이익추구를 위해서라면..

다섯째, 인성(人性)없는 과학
여섯째, 희생 없는 종교/일곱째, 신념 없는 정치

김남도의 이미지

답글 주셔서 감사합니다.

스택사이즈는 정의된 최소한의 MIN까지 줄여서 테스트해 본 것입니다.

그러나, 256개의 한계를 극복하기 위하여 커널을 재컴파일 하는 방법이 최선이겠더군요.

리눅스 초보자인 저로서는 모험삼아 시도해 보았다가......

OS를 날리는...-_-a

그래서, 커널 컴파일은 포기하였습니다.

IsExist의 이미지

좀더 도움될만한 답변을 얻을 수 있습니다.

다음 링크도 참조 하세요. http://kldp.org/node/57555

---------
간디가 말한 우리를 파괴시키는 7가지 요소

첫째, 노동 없는 부(富)/둘째, 양심 없는 쾌락
셋째, 인격 없는 지! 식/넷째, 윤리 없는 비지니스

이익추구를 위해서라면..

다섯째, 인성(人性)없는 과학
여섯째, 희생 없는 종교/일곱째, 신념 없는 정치

---------
간디가 말한 우리를 파괴시키는 7가지 요소

첫째, 노동 없는 부(富)/둘째, 양심 없는 쾌락
셋째, 인격 없는 지! 식/넷째, 윤리 없는 비지니스

이익추구를 위해서라면..

다섯째, 인성(人性)없는 과학
여섯째, 희생 없는 종교/일곱째, 신념 없는 정치

김남도의 이미지

커널 2.4 레드햇 9.0
그냥 있는거 그대로 설치한 것 같습니다.

다른 부분은 제가 잘 모르는부분이라.

일단 해본것은 1. 2번은 시도해 보았다는 것입니다.

1. 스택사이즈를 최소로 조정하여 시도해 보았습니다.
pthread_attr ....소용없더군요.

2. limits.conf 변경하고 해보았습니다.
......기억하기로는 부팅중에 멎는 현상이..있었던 듯합니다.

------------------------------
더운 날씨지만, 화이팅 하십시오!!

wfellow의 이미지

만약 thread나 fork로 한다면, stdin, stdout, stderr을 close()하심 일단 MAXFILES가 많이 확보가 될겁니다. thread시작후 동작을 하면서 open()하는 것들을 주의 깊게 한번 보셔요.. /proc/PID/fd... 주로 열린 파일의 갯수제한에 일차적으로 걸려서 좌절을 하곤 하지요.

FIFO를 사용하려 하셨나본데요, performance를 이야기 하시면서 FIFO는 맞지 않습니다. FIFO 퇴출!

위의 kane님이 귀띔을 해주신 작업단위로 분리하여야 한다는 말에 동감합니다. 저도 채팅서버 만들때 이렇게 해서 톡톡히 재미를 보았지요. 마치 아파치 웹서버와 비슷한 방식이라 말할 수 있습니다. 그리고 모든 질의의 형태를 메세지처럼 처리를 했었죠. 공통으로 사용하는 메모리에다가(shm) client들의 접속정보를 가지고 있고, 메세지 구조체를 작성하여 client의 고유 ID와 작업 메세지를 더하여 작업단위의 thread에게 보내면, 작업단위의 thread는 이를 처리하고 client의 fd에 직접 결과를 알려주죠. shm에 있는 내용은 write시에 semaphore를 사용하여 자료의 무결성(?)을 지켰구요. (Read시에는 wait없이 진행을 하도록 합니다.)
(다수의 client가 semaphore의 사용으로 속도가 느린건 사실이지만 Read/Write를 구분하면 문제 없고 또한 작업단위로 구성하면 하쿠나 마타타!)

여담이지만, 다수의 thread를 이용하는 것에도 한계가 분명 있습니다. work단위로 thread를 사용하면 쉽고도 효율적으로 할 수 있는데 어렵게 하지 마셔요. 저도 전에 Solaris7에서 몇개 안되는 thread를 구동하다가 작업단위로 변경하고나서 그뒤로 3년동안 밤에 두발뻗고 잘 잤던 기억이 있습니다.^^

저도 지금 졸려서리 뭐라 쓰는건지도 헷갈리네요^^.

-----[꼬릿말 절취선 시작]-----
삽질전에 먼저 구글신께 기도하자.
-----[꼬릿말 절취선 끝]-----

-----[꼬릿말 절취선 시작]-----
삽질전에 먼저 구글신께 기도하자.
-----[꼬릿말 절취선 끝]-----

김남도의 이미지

코딩 열심히 했었는데.....

작업기능단위 쓰레드분할 방식에 대하여 두분께서 조언을 주셨습니다.

감사하게 생각하구요.

또 다시 몇일을 투자해서 테스트 해보아야 하겠네요...

마지막 방법으로 시도해 보려고 합니다.

이 방법으로 해결이 안되고, 서버의 업그레이드도 안된다고 한다면,

막! 가보렵니다......사장실에 가 보렵니다......

Window 프로그래밍 하다가 리눅스 C, C++ 하려니....

다시 한 번 '돌깨는' 느낌입니다.

돌깨러 가세~~..돌깨러 가세~~~♪...ME.Stone.OTL

wfellow의 이미지

제가 지금까지 윈도즈나 유닉스, 메인프레임에 MCU보드등 여러 플랫폼에서 코딩을 해 왔는데요, 누가 어떻게 시작을 하더라도 man 하나 믿고서 작업을 시작할 수 있는 것은 유닉스(리눅스)가 유일합니다. 게다가 우리의 든든한 후원자인 구글신까지 굽어보고 계신데 못할건 또 없지요.

포기는 이릅니다. 다만 재작업이 있을뿐~

-----[꼬릿말 절취선 시작]-----
삽질전에 먼저 구글신께 기도하자.
-----[꼬릿말 절취선 끝]-----

-----[꼬릿말 절취선 시작]-----
삽질전에 먼저 구글신께 기도하자.
-----[꼬릿말 절취선 끝]-----

김남도의 이미지

윈도계열로 넘어오기 전에 그 man의 강력함에 매료된 적이 있었습니다.
단 몇개월에 불과했습니다만..

그 후 몇년간 'F1'에 익숙해지니 이것 참.....습관적으로 'F1'을 찾고 있습니다.
툴의 무서움은 역시나 스스로를 안주하는 상태로 빠뜨려
'데워지는 솥안의 개구리'처럼 만든다는 사실이더군요.

물론, 툴을 강력하게 사용하시는 분들이 많다는 사실은 알고 있습니다.
제 노력이 불성실했음도 인정하구요.

......지금까지의 능력과 지식을 또 다시 더듬어봐야 한다는 것은
지식탐구의 고통처럼 느껴지면서도 한편으로는 '목구멍이 포도청'이라는 것이지요.

날씨가 우중충하니까 기분도 우중충해지는 것 같습니다.
기분전환삼아 일찍 퇴근해야 할 것 같습니다....(곧 정시군요.)

혹, 들어보신 적이 있으신지 모르겠습니다만, man페이지 찾는 것에 어려움을 느껴
유닉스,리눅스 계열을 포기한 윈도우 프로그래머도 있더군요.
데브피아에서 그분의 글을 잠깐 본 것 같습니다.

생각을 구체화시키는데에 앞서다보니 라이브러리를 참조하는 것을 가끔 잊기도 하고
삽질을 하다보면 옆에서 '왜 그 함수를 만들고 있는건데?'라는 질문을 받았다더군요.
비슷한 경험이 있는 저에게는 와 닿는 말이었습니다.

답글 주셔서 감사합니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.