2017-12-29 39 views
0

60 초마다 모든 사용자에 대해 최근 메시지를 가져 오는 루비 앱이 있습니다. 메시지가 원격 API에서 호스팅되는대로, 이것은 지금이 할 수있는 가장 실용적인 방법입니다 새로운 스레드 수가 많아서 (매 10 초당 60 초) 메모리 문제가 발생합니다.

while true 
    fetch_recent_messages do |result| 
    # Handle result 
    end 

    sleep 60 
end 

def fetch_recent_messages() 
    Thread.new do 
    sleep_duration = 60/@fetch_users.count 

    for fetch_user in @fetch_users 
     Thread.new do 
     @api_manager.fetch_recent_messages_for_user(fetch_user) 
     yield result 
     end 

     sleep sleep_duration 
    end 
    end 
end 
  1. fetch_recent_messages()

    는 60 초마다 호출된다.
  2. @fetch_users이 순환되므로 각 반복마다 적절한 시간 동안 잠자기를 유지해야 함수가 약 60 초 걸려 모든 사용자가 fetch_recent_messages_for_user()에 전화 할 수 있습니다. 이렇게하면 네트워크와 CPU로드가 분산됩니다.
  3. 루프는 @fetch_users 루프가 새 스레드를 초기화하고이 스레드에서 API 호출을 수행 한 다음 결과로 while 루프를 반환합니다.

요점은 새 스레드가 서로 비동기 적으로 발생하도록하기 위해 모든 API 요청에 대해 초기화된다는 것입니다. 많은 사용자 (예 : 10k)가있을 수 있으므로 모든 사용자에 대한 가져 오기 메시지 요청을 동일한 60 초 내에 처리 할 수 ​​있어야합니다. 내 서버의 CPU/메모리 사용량에 문제가 없습니다.

이 응용 프로그램의 메모리 사용량이 자발적으로 상당한 시간 동안 위 또는 아래로 뛰었으며 특정 동작에 링크 할 수 없었습니다. 이것은 CPU 사용량의 15 %에서 24 시간 이상 실행 한 후에 발생할 수 있습니다. 갑자기 30 %로 점프하고 나중에 다시 40 %까지 또는 다시 내려갈 수 있습니다. 그것에 패턴이있는 것 같지 않습니다. 성능을보기 위해 새로운 스레드를 만드는 것을 제외하고 모든 것을 주석 처리 했으므로 메모리 문제를 일으키는 것으로 보입니다.

많은 양의 스레드를 유지하는 데 Ruby에 문제가 있는지, 내가 다르게 처리해야하는지 아니면이 작업을 다르게해야하는지 궁금합니다.

답변

2

스레드를 구현하는 대부분의 언어의 경우, 추가 스레드에 문제가있는 것보다 놀랍게도 낮은 임계 값 (많은 경우에 따라 수백 가지가있을 수 있음)이 있습니다. (얼랭/엘릭서 프로세스는 극적인 예외입니다.)

한 번에 몇 개의 스레드가 활성화되어 있는지 주기적으로 시스템을 들여다 보며 작업하는 것이 좋습니다.

또한 프로그램 수명 기간 동안 많은 스레드가 사용되는 곳에서는 스레드 풀이 일반적으로 스레드 생성 및 삭제시 발생하는 오버 헤드를 줄이는데 사용됩니다. 이러한 풀을 사용하면 작업이 완료되면 다시 사용할 수 있도록 고정 된 수의 스레드가 있습니다.

다음은 Ruby의 스레드 풀 구현에 대한 설명서 링크입니다 : https://github.com/ruby-concurrency/concurrent-ruby/blob/master/doc/thread_pools.md.