2013-09-04 7 views
0

느린 쿼리를 실행할 때 MongoDB PHP 드라이버 (v1.3)에서 반쯤 이상한 동작이 발생합니다. 운전자는 요청이 느릴 때 연결을 유지하는 것처럼 보이고 이유를 완전히 이해하지 못합니다. 어쩌면 여기에 몇 가지 제안이있을 것입니다.PHP MongoDB 드라이버가 느린 쿼리에서 많은 연결을 엽니 다.

  • 웹 사이트와 데이터베이스를 실행 한 우분투 13.04 서버
  • 서버입니다 하이 엔드 8 코어 16 기가 바이트 RAM 서버
  • MongoDB를의 v2.2.4
  • 웹 사이트 실행에 : 여기

    먼저 몇 가지 사실입니다 PHP 5.4
  • 웹 서버로 아파치 2
  • PHP 몽고 드라이버 1.3.x (최신 1.3이어야 함)
  • 웹 사이트 교리 ODM
  • 웹 사이트는
  • ulimit를 열려있는 파일 (ulimit를 NOFILE) = 64000

하루 Memcache의 기록이 만료되면 및 느린 쿼리가 어떤 순간에 약 50 ~ 100 명의 동시 사용자를 보유하고 사용 끝난. 이로 인해 PHP는 MongoDB에 최대 800 개의 연결을 열게됩니다 (일반적으로 로그에 따라 10 개의 연결이 열려 있습니다). 우리의 웹 사이트는 Memcached를 거의 완벽하게 갖추고 있으므로 데이터베이스에 다른 중요한 부하가 없습니다. 800 개의 연결을 열면 웹 사이트가 처음에는 30 초의 로딩 시간을 가지게되고 나중에 여러 유형의 MongoExceptions (너무 많은 연결/소켓 예외)가 발생합니다.

그룹별로 다음과 같은 추한 검색어가 있습니다. 명확하게 말하자면,이 쿼리는 느리고 바보 스럽습니다. 우리는 오늘이 쿼리를 제거하고 있습니다. 왜 그것이 전체 웹 사이트를 망쳐 놓는 지 명확하지 않습니다. 로그에 따라) : 우리는 추상화 계층으로 교리를 사용하지만, 이것은 20 만 문서 데이터베이스 (ID/제품/날짜 문서 당 3 개 필드)의 실제 쿼리입니다 쿼리가

{"group":true,"keys":{"product":1},"initial":{"count":0},"reduce":"function (obj, prev) { prev.count++; }","options":[],"db":"Orders","collection":"History"}

후 완료되면 결과가 Memcache에 24 시간 동안 기록됩니다. 따라서 모든 새로운 요청은 MongoDB가 아닌 Memcache에서 가져옵니다. 그러나 여전히 약 800 개의 연결을 고수하고 있지만 문제는 해결되지 않으며 잠시 후 웹 사이트가 더 이상 응답하지 않습니다. 이 800 개의 연결을 열려면 약 10 분이 걸립니다.

일반적인 경쟁 조건처럼 느껴집니다. 쿼리는이로드로이 서버에서 실제로 경쟁 조건을 일으킬 정도로 무거울 것 같지 않습니다. 내 말은,해서는 안되는 것처럼 느껴진다.

좋아, 질문은 다음과 같습니다

  1. 왜 PHP는 너무 많은 연결 개방을 유지합니까?
  2. MongoDB에서 처리 할 수없는 이유는 무엇입니까? (그다지 큰 문제가 아니어야합니다.)
  3. 다른 제안 사항은 무엇입니까?
  4. 이 문제를 해결하기 위해 연결 및 쿼리에 시간 초과를 설정해야합니까 아니면 다른 것입니까?

이유 나는 우리 웹 사이트가 정말로 빠르게 성장하고 있으며 앞으로 더 많은 트래픽과 MongoDB로드가 필요할 것으로 예상하고 있습니다.

미리 감사드립니다.

답변

1

기본 읽기 쿼리를 수행하는 대신 group 명령을 실행한다고 가정하면 MongoDB 2.2의 JavaScript 인터프리터와도 대치 할 수 있습니다. 2.4까지는 JavaScript 인터프리터가 동시 실행을 지원하도록 향상되었습니다. 이 그룹 작업들 각각에 대해 JS 평가가 필요하다면 (적어도 reduce 함수의 경우) 광범위한 자원 고갈을 기대할 수 있습니다.

"너무 많은 연결"예외에 대한 설명이 없습니다. 심지어 800 개의 동시 연결도 MongoDB의 제한 인 20,000보다 훨씬 낮습니다 (참고 :이 값은 SERVER-8943에서 2.6으로 제거됩니다).

응용 프로그램을 리팩터링하고 group 경쟁 조건을 피하는 한 가지 아이디어는 결과를 다시 계산하고 캐시를 다시 채우기 위해 단일 문서를 PHP 프로세스의 잠금으로 사용하는 것입니다. findAndModify을 사용하면 문자열이 _id 인 단일 문서 (예 : 'Order.History 그룹')와 다른 active 필드를 가질 수 있습니다. PHP 프로세스가 캐시 미스를 얻었을 때 결과를 다시 계산해야 할 경우 먼저 findAndModify을 실행하고 을 찾으십시오. activefalse이고 을 true으로 업데이트하는 것은 동일한 원자 적 연산입니다. group 명령을 사용하여이 잠금 문서를 다시 가져온 후에야합니다. 잠금 문서를 찾을 수없는 다른 PHP 프로세스 (activefalse이 아니기 때문에)가 잠자기 상태로 돌아가거나 오래된 데이터를 반환하거나 웹 요청을 중단하도록 지시 할 수 있습니다.