동시성을 처리하기 위해 파이썬을 고수하거나 포기해야합니까?


31

Django 로 작성된 10K LOC 프로젝트를 필요에 따라 비동기 및 백그라운드 작업에 대해 Celery ( RabbitMQ ) 로 처리 했으며 시스템 부분 이 Django 가 아닌 다른 언어 로 다시 작성 하면 더 나은 동시성을 얻을 수 있다는 결론에 도달했습니다 . 이유는 다음과 같습니다.

  • 신호 처리 및 가변 객체. 특히 하나의 신호가 다른 신호를 트리거 할 때 ORM을 사용하여 Django에서 신호를 처리 하면 인스턴스가 변경되거나 사라질 때 놀라 울 수 있습니다. 전달 된 데이터가 처리기에서 변경되지 않는 메시징 방법을 사용하고 싶습니다 ( Coljure의 COW ( Copy-On-Write) 방식은 올바르게 설정하면 멋지게 보입니다).
  • 시스템의 일부는 웹 기반이 아니며 작업을 동시에 수행하기 위해 더 나은 지원이 필요합니다. 예를 들어, 시스템은 NFC 태그를 읽고 , 태그를 읽으면 몇 초 동안 LED가 켜지고 (셀러리 작업), 소리가 재생되고 (다른 셀러리 작업) 데이터베이스가 쿼리됩니다 (다른 작업). 이것은 Django 관리 명령으로 구현되었지만 Django와 ORM은 본질적으로 동기화되어 메모리를 공유하는 것이 제한적입니다 (우리는 NFC 리더를 추가하려고 생각하고 있으며 Django + Celery 접근법이 더 이상 작동하지 않을 것이라고 생각합니다. 더 나은 메시지 전달 기능을보고 싶습니다).

Erlang 또는 Clojure 와 같은 언어를 사용하는 것과 비교할 때 Twisted 또는 Tornado 와 같은 것을 사용하는 장단점은 무엇입니까 ? 나는 실질적인 혜택과 손해에 관심이 있습니다.

시스템의 일부가 다른 언어로 더 잘 사용될 것이라는 결론을 어떻게 얻었습니까? 성능 문제가 있습니까? 그 문제는 얼마나 심각합니까? 더 빠를 수 있다면 더 빠를 필요가 있습니까?

예 1 : HTTP 요청 외부에서 작업중인 장고 :

  1. NFC 태그를 읽습니다.
  2. 데이터베이스 (및 LDAP)가 쿼리되고 데이터를 사용할 수있게되면 (빨간색 또는 녹색 표시 등, 소리 재생) 무언가를 수행하려고합니다. 이것은 Django ORM 사용을 차단하지만 셀러리 작업자가있는 한 중요하지 않습니다. 더 많은 스테이션에서 문제가 될 수 있습니다.

예 2 : Django 신호를 사용한 "메시지 전달":

  1. post_delete이벤트는, 처리하는 다른 개체는이 때문에 변경되거나 삭제 될 수 있습니다.
  2. 결국, 사용자에게 알림을 보내야합니다. 통지 핸들러에 전달 된 인수가 삭제되거나 삭제 될 오브젝트의 사본이고 핸들러에서 변경되지 않도록 보장하는 것이 좋습니다. (물론 ORM이 관리하는 객체를 핸들러에 전달하지 않고 수동으로 수행 할 수도 있습니다.)

결론에 도달 한 이유에 대해 더 설명하면 더 나은 답변을 얻을 수있을 것입니다
Winston Ewert

5
언어 선택 질문이 주제에 맞지 않다고 말하는 사람이 있기 전에, 나는 이것이 특정 요구 사항에 대한 실질적인 문제이기 때문에 이것이 괜찮다고 생각합니다. 자세한 비교가 이루어지기를 바랍니다.
Adam Lear

트위스트는 동시 의 반대 입니다! 그것은 이벤트 중심의 단일 스레드 서버이며, 진정한 동시성이 필요한 경우 어디에서나 얻을 수 없습니다.

답변:


35

열린 생각

시스템의 일부가 다른 언어로 더 잘 사용될 것이라는 결론을 어떻게 얻었습니까? 성능 문제가 있습니까? 그 문제는 얼마나 심각합니까? 더 빠를 수 있다면 더 빠를 필요가 있습니까?

단일 스레드 비동기

단일 스레드 비동기 및 다중 스레드 동시성의 차이점, 장단점을 이미 다루는 몇 가지 질문과 기타 웹 리소스가 있습니다. I / O가 주요 병목 현상 일 때 Node.js의 단일 스레드 비동기 모델이 어떻게 수행되고 한 번에 많은 요청이 처리 되는지에 대해 흥미 롭습니다 .

트위스트, 토네이도 및 기타 비동기 모델은 단일 스레드를 잘 활용합니다. 많은 웹 프로그래밍에는 많은 I / O (네트워크, 데이터베이스 등)가 있으므로 원격 호출을 기다리는 데 소요되는 시간이 크게 늘어납니다. 이제 다른 데이터베이스 호출 시작, 페이지 렌더링 및 데이터 생성과 같은 다른 작업을 수행 할 수있는 시간입니다. 해당 단일 스레드의 활용도가 매우 높습니다.

단일 스레드 비동기의 가장 큰 장점 중 하나는 훨씬 적은 메모리를 사용한다는 것 입니다. 다중 스레드 실행에서 각 스레드에는 일정량의 예약 된 메모리가 필요합니다. 스레드 수가 증가함에 따라 스레드가 존재하는 데 필요한 메모리 양도 늘어납니다. 메모리는 유한하기 때문에 한 번에 만들 수있는 스레드 수에 한계가 있음을 의미합니다.


웹 서버의 경우 각 요청에 고유 한 스레드가 있다고 가정하십시오. 각 스레드에 1MB의 메모리가 필요하고 웹 서버에 2GB의 RAM이 있다고 가정하십시오. 이 웹 서버는 더 이상 처리 할 메모리가 부족하기 전에 어느 시점에서든 약 2000 개의 요청을 처리 할 수 ​​있습니다.

부하가 이보다 훨씬 높으면 요청이 오래 걸리거나 (오래된 요청이 완료되기를 기다리는 경우) 가능한 동시 요청 수를 확장하기 위해 더 많은 서버를 클러스터에 던져야합니다. .


다중 스레드 동시성

멀티 스레드 동시성은 대신 여러 작업을 동시에 실행하는 데 의존합니다. 즉, 스레드가 데이터베이스 호출을 반환하기 위해 대기하는 것을 차단하면 다른 요청을 동시에 처리 할 수 ​​있습니다. 스레드 사용률은 낮지 만 실행하는 스레드 수는 훨씬 큽니다.

멀티 스레드 코드도 추론하기가 훨씬 어렵습니다. 잠금, 동기화 및 기타 재미있는 동시성 문제와 관련된 문제가 있습니다. 단일 스레드 비동기는 동일한 문제를 겪지 않습니다.

그러나 멀티 스레드 코드는 CPU를 많이 사용하는 작업에서 훨씬 더 성능이 좋습니다. 일반적으로 차단되는 네트워크 호출과 같이 스레드가“수율”할 기회가없는 경우 단일 스레드 모델은 동시성이 없습니다.

둘 다 공존 할 수있다

물론 둘 사이에는 겹치는 부분이 있습니다. 그들은 상호 배타적이지 않습니다. 예를 들어, 멀티 스레드 코드는 각 스레드를보다 잘 활용하기 위해 비 차단 방식으로 작성 될 수 있습니다.


결론

고려해야 할 다른 많은 문제가 있지만 다음과 같이 두 가지에 대해 생각하고 싶습니다.

  • 프로그램이 I / O 바운드 인 경우 단일 스레드 비동기가 아마도 잘 작동 할 것입니다.
  • 프로그램이 CPU 바운드 인 경우 멀티 스레드 시스템이 가장 좋습니다.

특정한 경우에는 어떤 종류의 비동기 작업이 완료되는지와 이러한 작업이 얼마나 자주 발생하는지 확인해야합니다.

  • 그들은 모든 요청에 ​​발생합니까? 그렇다면 요청 수가 증가함에 따라 메모리가 문제가 될 수 있습니다.
  • 이러한 작업은 주문 되었습니까? 그렇다면 여러 스레드를 사용하는 경우 동기화를 고려해야합니다.
  • 이러한 작업은 CPU를 많이 사용합니까? 그렇다면 단일 스레드가로드를 유지할 수 있습니까?

간단한 대답이 없습니다. 사용 사례를 고려하고 그에 따라 디자인해야합니다. 때때로 비동기 단일 스레드 모델이 더 좋습니다. 다른 경우에는 대규모 병렬 처리를 위해 많은 스레드를 사용해야합니다.

다른 고려 사항

선택한 동시성 모델이 아니라 고려해야 할 다른 문제가 있습니다. Erlang 또는 Clojure를 알고 있습니까? 애플리케이션의 성능을 향상시키기 위해 이러한 언어 중 하나로 안전한 멀티 스레드 코드를 작성할 수 있다고 생각하십니까? 이 언어들 중 하나의 언어를 배우는 데 시간이 오래 걸리고, 배우는 언어가 미래에 도움이 될 것입니까?

이 두 시스템 간의 통신과 관련된 어려움은 어떻습니까? 두 개의 개별 시스템을 병렬로 유지 관리하는 것이 지나치게 복잡합니까? Erlang 시스템은 어떻게 Django로부터 작업을 받습니까? Erlang은 이러한 결과를 어떻게 Django로 다시 전달합니까? 추가 된 복잡성이 그만한 가치가있는 성능만큼 중요한 문제입니까?


마지막 생각들

나는 항상 Django가 충분히 빠르다는 것을 알고 있었고, 매우 많은 인신 매매 사이트에서 사용되었습니다. 동시 요청 수와 응답 시간을 늘리기 위해 수행 할 수있는 몇 가지 성능 최적화가 있습니다. 분명히, 나는 지금까지 Celery로 아무것도하지 않았으므로 일반적인 성능 최적화는 아마도 이러한 비동기 작업에서 발생할 수있는 문제를 해결하지 못할 것입니다.

물론 문제에 더 많은 하드웨어를 던질 것을 제안하는 것이 항상 있습니다. 새로운 서버를 구축하는 비용이 완전히 새로운 서브 시스템의 개발 및 유지 보수 비용보다 저렴합니까?

나는이 시점에서 너무 많은 질문을했지만 그것은 나의 의도였다. 분석과 세부 사항 없이는 답이 쉽지 않을 것입니다. 문제를 분석 할 수 있다는 것은 물어볼 질문을 아는 것입니다.

내 직감은 다른 언어로 다시 쓰지 않아도된다고 말합니다. 복잡성과 비용이 너무 클 것입니다.


편집하다

후속 조치

후속 조치는 매우 흥미로운 사용 사례를 보여줍니다.


1. 장고는 HTTP 요청 외부에서 작업

첫 번째 예는 NFC 태그를 읽은 다음 데이터베이스를 쿼리하는 것입니다. 이 부분을 다른 언어로 작성하는 것이 데이터베이스 나 LDAP 서버에 대한 쿼리가 네트워크 I / O (및 잠재적 인 데이터베이스 성능)에 의해 제한 될 것이기 때문에 유용하다고 생각하지 않습니다. 반면에 각 관리 명령이 자체 프로세스로 실행되므로 동시 요청 수는 서버 자체에 의해 바인드됩니다. 이미 실행중인 프로세스에 메시지를 보내지 않기 때문에 성능에 영향을주는 설정 및 해제 시간이 있습니다. 그러나 각 요청이 분리 된 프로세스이므로 동시에 여러 요청을 보낼 수 있습니다.

이 경우 조사 할 수있는 두 가지 방법이 있습니다.

  1. 데이터베이스가 연결 풀링을 사용하여 한 번에 여러 쿼리를 처리 할 수 ​​있는지 확인하십시오. 예를 들어, Oracle은 Django를 적절히 구성해야합니다 'OPTIONS': {'threaded':True}. 데이터베이스 레벨 또는 Django 레벨에는 자체 데이터베이스에 맞게 조정할 수있는 유사한 구성 옵션이있을 수 있습니다. 데이터베이스 쿼리를 작성하는 언어에 관계없이이 데이터가 반환 될 때까지 기다려야 LED를 켤 수 있습니다. 쿼리 코드의 성능은 차이를 만들 있으며 Django ORM은 번개가 빠르지 않지만 일반적으로 충분히 빠릅니다.
  2. 설정 / 삭제 시간을 최소화하십시오. 지속적으로 프로세스를 실행하고 메시지를 보냅니다. (내가 틀렸다면 나를 고치십시오.하지만 이것이 원래의 질문에 실제로 초점을 맞추고 있습니다.)이 프로세스가 Python / Django로 작성되었는지 아니면 다른 언어 / 프레임 워크로 작성되었는지는 위에 설명되어 있습니다. 관리 명령을 너무 자주 사용한다는 생각이 마음에 들지 않습니다. NFC 리더의 메시지를 메시지 큐로 푸시하는 작은 코드 조각을 지속적으로 실행할 수 있습니까? Celery는이를 읽고 Django로 전달합니다. 작은 프로그램이 파이썬으로 작성 되었더라도 (Django!는 아님) 작은 프로그램의 설정 및 해제는 Django 프로그램을 시작하고 중지하는 것 (모든 서브 시스템이있는 것)보다 낫습니다.

Django에 어떤 웹 서버를 사용하고 있는지 잘 모르겠습니다. mod_wsgiApache의 경우 서비스를 요청하는 프로세스 내의 프로세스 및 스레드 수를 구성 할 수 있습니다. 서비스 가능한 요청 수를 최적화하려면 웹 서버의 관련 구성을 조정해야합니다.


2. Django 신호를 이용한“메시지 전달”

두 번째 사용 사례도 상당히 흥미 롭습니다. 그것에 대한 답변이 있는지 확실하지 않습니다. 모델 인스턴스를 삭제하고 나중에 작업하려는 JSON.dumps경우 직렬화 한 다음 역 직렬화 할 수 있습니다 JSON.loads. 데이터베이스에서 관련 필드가 느리게로드되고 해당 링크가 더 이상 존재하지 않기 때문에 나중에 관련 그래프 쿼리 (객체 관련 모델 쿼리)를 완전히 다시 생성 할 수 없습니다.

다른 옵션은 객체를 삭제 대상으로 표시 하고 요청 / 응답주기가 끝날 때만 (모든 신호가 서비스 된 후) 객체를 삭제하는 것입니다. 에 의존하지 않고이를 구현하기 위해 사용자 정의 신호가 필요할 수 있습니다 post_delete.


1
Erlang과 관련이없는 잠금 및 기타 사항에 대한 많은 FUD와 의문점, 귀하가 나열한 일반적인 공유 상태 문제는 특별히 상태를 공유하지 않도록 설계된 언어 및 런타임에 대한 고려 사항이 아닙니다. Erlang은 아주 작은 램에서 수만 개의 신중한 프로세스를 처리 할 수 ​​있으며 메모리 부족도 문제가되지 않습니다.

@Jarrod, 나는 개인적으로 Erlang을 알지 못하므로 그 점에서 당신이 말하는 것을 받아 들일 것입니다. 그렇지 않으면 언급 한 거의 모든 것이 관련이 있습니다. 비용, 복잡성 및 현재 도구의 올바른 활용 여부
Josh Smeaton


이것은 내가 정말로 읽는 것을 좋아하는 서사시의 일종입니다 ^^. +1, 잘 했어!
Laurent Bourgault-Roy

또한 DJango 템플릿이있는 경우 Erlydtl
Zachary K

8

미국의 주요 ISP를 위해 매우 정교하고 확장 성이 뛰어난 개발을 수행했습니다 . 우리는 Twisted 서버를 사용하여 심각한 tranasaction 수를 만들었습니다 .Python / Twisted를 CPU 바인딩 된 것으로 확장하는 것은 복잡한 악몽이었습니다 . I / O 바운드 는 문제가되지 않지만 CPU 바운드는 불가능했습니다. 우리는 시스템을 신속하게 구성 할 수 있었지만, 수백만 명의 동시 사용자로 확장 할 수있게하는 것은 CPU에 묶인다면 구성과 복잡성의 악몽이었습니다.

나는 그것에 대해 블로그 게시물을 작성했다 .Python / Twisted VS Erlang / OTP .

TLDR; 얼랭이 이겼다.


4

Twisted의 실제 문제 (약 5 년 동안 사랑하고 사용해 왔음 ) :

  1. 문서는 원하는 것을 남겨두고 모델은 어쨌든 배우기가 매우 복잡합니다. 다른 Python 프로그래머가 Twisted 코드에서 작업하는 것이 어렵다는 것을 알았습니다.
  2. 좋은 차단 API가 없기 때문에 차단 파일 I / O 및 데이터베이스 액세스를 사용했습니다. 이로 인해 실제로 성능이 저하 될 수 있습니다.
  3. Twisted를 사용하는 거대한 커뮤니티와 건강한 커뮤니티는없는 것 같습니다. 예를 들어 Node.js 는 특히 웹 백엔드 프로그래밍을 위해 훨씬 더 활발한 개발을하고 있습니다.
  4. 그것은 여전히 ​​파이썬이며 적어도 CPython 이 가장 빠른 것은 아닙니다.

CoffeeScript 와 함께 Node.js를 사용하여 약간의 작업을 수행했으며 동시 성능이 걱정된다면 도약 할 가치가 있습니다.

인스턴스 간에 클라이언트를 분산시키기 위해 Django의 여러 인스턴스를 실행하는 것을 고려 했습니까 ?


1
일반적으로 잎 뭔가 파이썬 문서가 필요합니다 : / (말을하지 그건 나쁜하지만 언어에 대한 인기가 있다는 것이 훨씬 더 좋을 하나는 기대).
루크

3
파이썬 문서, 특히 장고 문서는 모든 언어에 대한 최고의 문서 중 하나입니다. 많은 타사 라이브러리는 원하는 것을 남겨 둡니다.
조쉬 스 메이 턴

1

다른 언어로 전환하기 전에 다음 사항을 제안합니다.

  1. 페이지 결함, 컨텍스트 전환 및 시스템 호출 대기와 같은 시스템 이벤트를 기록 하려면 LTTng 를 사용하십시오 .
  2. C 라이브러리를 사용하는 데 시간이 너무 많이 걸리는 곳을 변환하고 selectI / O에 적합한 원하는 디자인 패턴 (멀티 스레딩, 신호 이벤트 기반, 콜백 비동기 또는 Unix Traditional )을 사용하십시오.

일단 응용 프로그램의 성능이 우선되면 Python에서 스레딩을 사용하지 않습니다. 위의 옵션을 사용하면 소프트웨어 재사용, Django 와의 연결 , 성능, 개발 용이성 등과 같은 많은 문제를 해결할 수 있습니다 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.