EPOLLOUT처리에 대한 궁금증

linehat의 이미지

epoll_ctl 로 EPOLLOUT이벤트를 등록시켰을때

서버의 CPU점유율이 100%로 올라갑니다.

투코어 일경우도 둘다 100%를 점유한다는...

성능상의 이점은 있다고 판단되지만, 너무나 무시무시한 점유율인데..

사용법이 잘못된건지 궁금하네요.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CentOS 4.6을 쓰고 있구요.

이벤트 처리는 달랑?? 하나의 쓰레드에서 처리하고 있습니다.

sauron의 이미지

당연히 사용법이 잘못된 겁니다.

linehat의 이미지

이벤트 쓰레드는 1개 동작하고 있습니다. 일단.

epoll_wait은 고로 1개의 사용자 쓰레드에서 처리가 되고 있다는 거죠.

EPOLLIN만 감시할경우는 CPU는 10%이하에서 놀고 있습니다.

단, EPOLLOUT을 이벤트에 등록하는 순간부터는 CPU는 100%까지 올라갑니다.

질문을 올릴때는 올린이도 나름대로 고민해보고 올리는 글입니다.

당연히 잘못된겁니다? EPOLLOUT사용 해보시고 올리는겁니까?

어느정도의 CPU점유율이 올라간다고 예상은 했었지만, 너무 올라가서 올리는 질문인데

무슨 대답을 그따우로 하십니까? 차라리 안하니만 못하는거 같은데.

얼마나 잘하시는 분인지는 모르겠습니다만 기본적인 소양이 문제가 있는것 같네요.

-------------------------------

소켓이 Write가능한 상태가 되는것을 EPOLLOUT에서 검사하는건 아시는지도 궁금하네요.

참고로, 님이 질문하신 대답에 다른분이 대답을 이따우로 하면 기분이 참 좋겠죠?

brucewang의 이미지

저의 경우 EPOLLOUT을 사용할때 CPU점유율이 그렇게 급상승 하는 것은 없었지만,
IN의 경우와는 달리 session마다 보낼 데이터들이 완전히 써지고 그 다음 데이터까지도 제대로 쌓이게 하기 위해선 너무 처리가 많아지더라구요.

그래서 IN의 경우만 처리하고 OUT의 경우는 별도로 epollctl로는 처리 하지 않고 있는데...

linehat 님은 어떻게 하셨는지 궁금하네요.

-------------------------------------------------
$yes 4 8 15 16 23 42

-------------------------------------------------
$yes 4 8 15 16 23 42

linehat의 이미지

write able을 검사하기 위해서 EPOLLOUT을 등록한것은 질문의 이유이기도 합니다만,

워커 쓰레드에서 날아온 이벤트를 검사해서 EPOLLOUT일 경우에는 패킷을 쏘아주고 있습니다.

일단 처음에는 IN만 검사했고, 패킷이 날아온 후 부터는 OUT까지 함께 검사해주고 있습니다.

센드시에 완전히 쏘지 못한 패킷들은 따로큐에 저장해뒀다가, OUT이벤트를 받을경우 그전에

큐에 있던 패킷들을 쏘아주는 형태입니다.

brucewang의 이미지

네, 그러시군요. 저도 그렇게 사용했었습니다.

그런데 제 현재 회사 내부에서는 서버당 concurrent 1000 세션만 해주면 된다고 했지만 이왕 할 거 C10k를 붙여볼려고 하다보니까 queue만 해도 필요한 메모리가 엄청나더라구요. 그래서 포기 했지요.

그래도 CPU점유율이 늘어나는것은 발견하지 못했었는데... 저도 왜 그렇게 되는지 궁금하네요. 다른 분들의 말씀을 보면서 저도 좀 배웠으면 합니다.

-------------------------------------------------
$yes 4 8 15 16 23 42

-------------------------------------------------
$yes 4 8 15 16 23 42

linehat의 이미지

EPOLLOUT을 처리를 하는것이 좋다는 식으로 된 글을 웹서핑하다가 보게 된것이 문제의 시발점인듯 ㅠㅠ...

queue문제는, send실패 시에만 넣어주게 되면 신경을 안써도 될 듯하구요.

물론, 이건 제 서버같은 구조에서만 가능하지 않을까 싶네요. 한번에 한개의 client이상은 처리를 하지 않기 때문에.

워커 스레드는 cond계열로 동작하고 있구요.

윈도우를 하다가 리눅스를 하니...모르던 부분이 너무 많습니다. 괴롭습니다. 솔직히..

signal관련 오류라던가...지금처럼 이런 오류는 생각도 못하다가 ㅡㅡ;;;

brucewang의 이미지

메인 코드만 한번 올려봐 주세요, 저도 잘 모르지만 혹시 저같은 제 3자의 눈에 뭔가 발견될지도 모르고, 다른 분들께서도 더 정확하게 문제 원인을 파악하실 수 있을것 같습니다.

-------------------------------------------------
$yes 4 8 15 16 23 42

-------------------------------------------------
$yes 4 8 15 16 23 42

linehat의 이미지

이벤트 쓰레드에서는
while(m_bRun)
{
nEvents = epoll_wait(efd, pEpollEvents, poolsize, -1);

if( nEvents == -1 )
{
// EBADF 9 EINVAL 22 EFAULT
if(( nEvents == EBADF ) || ( nEvents == EINVAL ) || ( nEvents == EFAULT ))
{
//char szStrError[128] = {0, };
//strerror_r(errno, szStrError, sizeof(szStrError));
cSingleton::GetInstance()->PushLogFmt("epoll_wait errorcode %d, %s", errno, strerror(errno));
}
else if( nEvents == EINTR )
{
cSingleton::GetInstance()->PushLogFmt("epoll_wait errorcode EINTR");
}
else
{
cSingleton::GetInstance()->PushLogFmt("epoll_wait errorcode UNKNOWN");
}
continue;
}

======================
이벤트 등록하는 부분입니다.
int cServerSocket::Modify_Epoll_fd(
int cfd, /**< 클라이언트 소켓값 */
bool useoneshot)
{
struct epoll_event ev;

ev.events = EPOLLIN;
ev.events |= EPOLLET;
ev.events |= EPOLLOUT;
if (useoneshot)
ev.events |= EPOLLONESHOT;
ev.data.fd = cfd;

int res = epoll_ctl(m_nEpollfd, EPOLL_CTL_MOD, cfd, &ev);

return res;
}

brucewang의 이미지

우선 epoll_wait의 return code가 0보다 작을경우, 그원인은 return code자체가 아니라 errno 값으로 확인하셔야 합니다.. 위 코드에서 nEvents 로 바로 비교 하시면 안되구요.

그 외에는 저 코드만으로는 제가 짐작을 못하겠네요. 코드를 더 올리시기가 좀 뭐하시다면, epoll_wait의 결과 EPOLLOUT인 경우를 처리하시는 서브루틴의 코드를 모두 지우시고, 하나씩 원래 코드를 붙여가시면서 CPU 점유율 변화를 보시면 어떨까요. 네.. 너무 성의없는 답변이죠? ToT

하지만, 적어도 EPOLLOUT을 추가한다고 CPU점유율이 확 늘어날 것 같지는 않으니까, 그 base에서 나머지 진짜 원인을 찾아보실 수는 있을것 같습니다.

-------------------------------------------------
$yes 4 8 15 16 23 42

-------------------------------------------------
$yes 4 8 15 16 23 42

linehat의 이미지

epoll_wait쓰레드에 슬립을 넣으시는지가 궁금하네요. 저는 넣지를 않고 사용중인데

구글링 해보니 코드중에 epoll_wait쓰레드에, CPU99%를 피하기 위해 슬립을 넣는 경우를 보았습니다.

주석도 그렇게 달려있었고..

슬립을 넣게 되면 반응속도가 아무래도 떨어질거 같은데...

아무리, 어플리케이션이 사용자가 적절히 사용해야 한다지만, 단지 슬립하나 차이로

이런차이가 생기지는 않을거 같은데...

4way cpu에서 테스트 했을경우도 300% 가깝게 먹어버립니다. 한마디로 괴물이네요 ㅠㅠ 260%를 쳐묵네요 ㅡㅡ;;

brucewang의 이미지

저의 경우는 Sleep은 사용하지 않습니다.

epoll_wait 자체가 '처리가능한 뭔가' 가 있을때까지 기다려주니까요. 뭔가 찾았다... 하고 이벤트가 생기면 바로 그 이벤트에 대한 처리를 마치고, 다시 기다립니다.. Windows에서 WaitForSingleObject와 같다고나 할까요?

그 예제 쓰래드에서 Sleep을 사용한 이유는 epoll_wait 말고 다른 이유때문일 것 같습니다..

-------------------------------------------------
$yes 4 8 15 16 23 42

-------------------------------------------------
$yes 4 8 15 16 23 42

linehat의 이미지

WaitForSingleObject 일경우는 쓰레드가 블럭되자나요?

하지만 epoll_wait일 경우 EPOLLOUT을 검사하게 되면 바로바로 리턴을 해버리게 되죠.

while이 쉼없이 돌아가는 상태와 비슷하다고 생각됩니다만,

brucewang의 이미지

아, 그건 제가 잠시 잘못 생각했던 것 같네요. linehat 님 말씀이 맞습니다.

-------------------------------------------------
$yes 4 8 15 16 23 42

-------------------------------------------------
$yes 4 8 15 16 23 42

linehat의 이미지

nano 10정도의 슬립으로 처리능력의 큰 저하 없이 어느정도는 점유율을 하락시킬수는 있네요..

근본적인 문제해결이 아닌것 같아 좀 안타깝지만,

언젠가는 해답을 찾지 않을까 싶습니다.

brucewang님 일본에서도 항상 건강하시길 ^0^.

brucewang의 이미지

별말씀을요, 제가 감사합니다.

그런데 linhat님께서도 너무 잘 아시겠지만 쓰래드에서의 Sleep이야 그 해당 쓰래드를 잠시 idle하게 해서 다른 쓰래드에게 제어권을 주기 위한 것일 뿐이고, EPOLLIN 만을 감시하실때는 동일 구조인데도 CPU점유율이 낮으셨죠?

EPOLLOUT 를 추가로 처리한다고 해도, 실제 아무 코드가 없이 수행하시면 CPU점유율의 확연한 차이는 없을것 같고, 그러니까, 아마 EPOLLOUT 과는 별도의 이유가 있지 않을까.... 하는 생각이 잠시 스칩니다...

좋은 소식 기다립니다~

-------------------------------------------------
$yes 4 8 15 16 23 42

-------------------------------------------------
$yes 4 8 15 16 23 42

linehat의 이미지

nano 100으로 테스트 중이구요.

서버쪽의 네트웍부하는 테스트 해보지 않았지만 더미 클라 대략 40여개로 테스트 했습니다.

윈도시스템인데 네트웍 이용률이 100%가까이 나옵니다.

듀얼코어 일경우 단지 소켓하나만 EPOLLOUT에 등록했을경우라도 200%를 먹던것이 현재 겨우 5%만 먹습니다.
(이경우는 서버단끼리 물린경우라 소켓1개만 검사했었습니다.)

4way에서는 121%를 먹는군요.. 거의 반이상 CPU부하가 낮아졌습니다.

결과적으로만 보면, 성능상의 큰차이는 없는것 같아 보이네요.

epoll_wait에서 무한 감시하던걸 nanosleep으로 약간 지연시켰다는것뿐이지만,

이상태로는 만족스럽긴한것 같습니다.

이상 보고 마칩니다...거듭 감사 드립니다.

brucewang의 이미지

감축드립니다~

-------------------------------------------------
$yes 4 8 15 16 23 42

-------------------------------------------------
$yes 4 8 15 16 23 42

jinyeong의 이미지

작성하신 것 처럼 EPOLLOUT을 항상 check하는 것이 어떤 측면에서 장점이 있는지 궁금합니다.
굳이 sleep을 넣을 정도로 cpu 점유율을 높히는데 말이죠.

Send socket의 경우엔, 보낼 수 있는 경우는 많은 반면 보낼 data가 없는 경우가 많을 것 같은데, 이 경우 send queue 등에 data를 넣고 epoll_ctl 등으로 EPOLLOUT을 check하게 하고 해당 data의 send가 _모두_ 끝난 후 EPOLLOUT을 delete하는 방법이 더 낫지 않을까요?

I thought what I'd do was,
I'd pretend I was one of those deaf-mutes.. or should I?

linehat의 이미지

jinyeong님 말씀처럼. 거의 하는일 없이 리턴하게 되죠.

적용해본 이유는, 클라이언트의 writeable을 체크할 필요가 없다는 이유가 되겠습니다.

무조건, send하고 에러에 따른 처리보다는 이 경우는 저것을 사용해보는것이 어떨까 해서 적용시켜 본 것이구요.

send쓰레드를 따로 작동시킨다면 필요 없는 부분이겠네요.

말씀하신대로, 처리하면 CPU부하도 생각할 필요가 없겠죠..처리할때마다 잠깐씩 올라갈려나 ㅡㅡ;;

저는 EPOLLOUT을 등록해서 사용하고 싶구요..

EPOLLOUT이벤트를 등록할경우에 너무 큰 CPU부하가 생기는게 궁금해서 질문을 드린겁니다..

sauron의 이미지


-- 이벤트 쓰레드는 1개 동작하고 있습니다. 일단.
-- epoll_wait은 고로 1개의 사용자 쓰레드에서 처리가 되고 있다는 거죠.
-- EPOLLIN만 감시할경우는 CPU는 10%이하에서 놀고 있습니다.
-- 단, EPOLLOUT을 이벤트에 등록하는 순간부터는 CPU는 100%까지 올라갑니다.
-- 질문을 올릴때는 올린이도 나름대로 고민해보고 올리는 글입니다.
-- 당연히 잘못된겁니다? EPOLLOUT사용 해보시고 올리는겁니까?

어, EPOLLOUT 은 사용해 보기는 했지만...

-- 어느정도의 CPU점유율이 올라간다고 예상은 했었지만, 너무 올라가서 올리는 질문인데
-- 무슨 대답을 그따우로 하십니까? 차라리 안하니만 못하는거 같은데.

이따위의 대답을 했다니 저는 참 모지란 놈입니다.

-- 얼마나 잘하시는 분인지는 모르겠습니다만 기본적인 소양이 문제가 있는것 같네요.
--
-- 소켓이 Write가능한 상태가 되는것을 EPOLLOUT에서 검사하는건 아시는지도 궁금하네요.

저, EPOLLOUT 이란게 Write 가능한 상태를 검사하는 거였나요.

-- 참고로, 님이 질문하신 대답에 다른분이 대답을 이따우로 하면 기분이 참 좋겠죠?

현재 기분은 참 좋습니다. 짧게 대답하는 것이 "이따위냐" 고 욕먹을 일이라는 것을
잘 알게 되었읍니다. 역시 사람은 끝없이 배워야 하는 동물인가 봅니다.
사람이 기쁜게 돈을 벌어서이기도 하지만 이렇게 세상이치를 배우게 되는 것도
기쁜 일인 것 같습니다. 공자가 아침에 도를 들어면 저녁에 죽어도 좋다고 했는데
기 기분을 조금 알 것 같은 날이었읍니다.

익명 사용자의 이미지

epoll은 default로 level trigger를 사용합니다.
level trigger 방식은 특정한 상태가 유지되면 무조건 알려줍니다.
level trigger 방식에서 EPOLLOUT은 send가 가능하면 즉시 리턴하게 됩니다.

만일 내가 전송할 데이터가 없는데 EPOLLOUT을 설정하게 된다면
소켓은 write가 가능한 상태이기 때문에 epoll_wait는 즉시 리턴하게 되고,
전송할 데이터가 없기 때문에 다시 epoll_wait로 돌아가게 되서,
공루프를 돌면서 cpu 100% 상태가 되었을 것으로 생각됩니다.

데이터가 있을 시에만 EPOLLOUT을 설정하시거나,
비동기 소켓 + edge trigger(EPOLLET)를 사용하시면
문제가 해결 될것입니다.

익명 사용자의 이미지

EPOLLOUT을 사용하여 writeable을 검사하다는 생각 자체가 위험하다고 봅니다.

ojang의 이미지

위에 말씀하신 것처럼 writeable 이란얘기는 송신큐가 1byte라도 비면
리턴하는가 봅니다. 만약 송신큐가 반 이하로 비었을 때 리턴을 해달라고
설정하는 부분은 없나요?

익명 사용자의 이미지

궁금하면 net/ipv4/tcp.c 의 tcp_poll 부분을 챙겨보시는 것도 도움되겠네요.
오픈 소스인데 윈도처럼 갑갑해 할 피룡 없죠. 목마른 자가 우물판다고..

글고 윗분 송/수신 워터마크 관련된 질문인 것 같네요. 맨 페이지 잘 찾아보시길

댓글 달기

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
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.