Rails는 비공유인가요, 아니면 별도의 요청이 동일한 런타임 변수에 액세스할 수 있나요?

StackOverflow https://stackoverflow.com/questions/1025432

문제

PHP는 비공유 환경에서 실행됩니다. 이는 모든 웹 요청이 깨끗한 환경에서 실행된다는 의미입니다.별도의 지속성 계층(파일 시스템, 데이터베이스 등)을 통하지 않고는 다른 요청의 데이터에 액세스할 수 없습니다.

루비 온 레일즈는 어떻습니까?방금 읽었어 블로그 게시물 별도의 요청이 동일한 클래스 변수에 액세스할 수 있음을 명시합니다.

이것은 아마도 웹 서버에 달려 있다는 생각이 들었습니다. 잡종의 FAQ Mongrel은 요청당 하나의 스레드를 사용한다고 명시하며 이는 공유되지 않는 환경을 제안합니다.FAQ에서는 계속해서 RoR이 스레드로부터 안전하지 않다고 말하며, 이는 새로운 요청이 이전 요청에서 생성된 메모리 내 개체를 재사용하지 않는 한 공유 환경에 RoR이 존재하지 않을 것임을 시사합니다.

분명히 이것은 보안에 큰 영향을 미칩니다.그래서 두 가지 질문이 있습니다.

  1. RoR 환경은 공유되지 않습니까?
  2. RoR이 실행되는 경우(또는 ~할 것 같다 어떤 상황에서 실행) 공유 환경에서 편집증을 느껴야 하는 변수 및 기타 데이터 저장소는 무엇입니까?

업데이트:더 자세히 설명하겠습니다. Java 서블릿 컨테이너에는 여러 요청에 걸쳐 지속되는 객체가 있을 수 있습니다.이는 일반적으로 여러 사용자가 액세스할 수 있는 데이터 캐싱, 데이터베이스 연결 등을 위해 수행됩니다.PHP에서는 이 작업을 애플리케이션 계층에서 수행할 수 없으며 Memcached와 같은 별도의 지속성 계층에서 수행해야 합니다.따라서 두 가지 질문은 다음과 같습니다.어떤 시나리오가 PHP 또는 Java와 같은 RoR이고 Java와 같은 경우 어느 데이터 유형이 여러 요청에 걸쳐 지속됩니까?

도움이 되었습니까?

해결책

간단히 말해서:

  1. 아니, 레일즈 절대 비공유 환경에서 실행됩니다.
  2. 편집증에 빠지다 클래스 변수 그리고 클래스 인스턴스 변수.

더 긴 버전:

Rails 프로세스는 프레임워크와 애플리케이션을 로드하여 수명 주기를 시작합니다.일반적으로 단일 스레드만 실행하며 수명 동안 많은 요청을 처리합니다.따라서 요청은 엄격하게 발송됩니다. 순차적으로.

그럼에도 불구하고 모든 클래스는 요청 전반에 걸쳐 지속됩니다.이는 클래스 및 메타클래스(예: 클래스 변수 및 클래스 인스턴스 변수)에서 참조되는 모든 개체를 의미합니다. ~ 할 것이다 요청 전반에 걸쳐 공유됩니다. 이것은 당신을 물릴 수 있습니다, 예를 들어 메소드를 메모하려고 하면(@var ||= expensive_calculation) 당신의 수업 메서드는 현재 요청 중에만 지속될 것으로 예상합니다.실제로 계산은 첫 번째 요청에서만 수행됩니다.

표면적으로는 캐싱이나 요청 간 지속성에 의존하는 기타 동작을 구현하는 것이 좋아 보일 수도 있습니다.일반적으로 그렇지 않습니다.이는 대부분의 배포 전략이 다음을 사용하기 때문입니다. 여러 개의 Rails 프로세스는 자체 단일 스레드 특성에 대응합니다.느린 데이터베이스 쿼리를 기다리는 동안 모든 요청을 차단하는 것은 좋지 않으므로 더 많은 프로세스를 생성하는 것이 쉬운 방법입니다.당연히 이러한 프로세스는 아무것도 공유하지 않습니다(눈에 띄지 않는 일부 메모리는 제외). 이것은 당신을 물릴 수 있습니다 클래스 변수나 클래스 인스턴스 변수에 내용을 저장하는 경우 요청 중.그러다가 왠지 그 물건이 있는 것처럼 보일 때도 있고, 없어진 것처럼 보일 때도 있습니다.(물론 실제로는 데이터가 일부에 존재할 수도 있고 존재하지 않을 수도 있습니다. 프로세스, 다른 것에는 없음).

일부 배포 구성(특히 JRuby + Glassfish) ~이다 실제로는 멀티스레드입니다.Rails는 스레드로부터 안전하므로 이를 처리할 수 있습니다.그러나 귀하의 응용 프로그램은 스레드로부터 안전하지 않을 수 있습니다.모든 컨트롤러 인스턴스는 각 요청 후에 폐기되지만, 우리가 알고 있듯이 클래스는 공유됩니다. 이것은 당신을 물릴 수 있습니다 클래스 변수나 클래스 인스턴스 변수에서 정보를 전달하는 경우.동기화 방법을 제대로 사용하지 않으면 경쟁 조건 지옥에 빠질 수도 있습니다.


참고 사항:Ruby의 스레드 구현이 형편없기 때문에 Rails는 일반적으로 단일 스레드 프로세스에서 실행됩니다.운 좋게도 Ruby 1.9에서는 상황이 조금 더 나아졌습니다.그리고 많은 JRuby에서 더 좋습니다.

이 두 가지 Ruby 구현이 모두 인기를 얻으면서 멀티스레드 Rails 배포 전략도 인기와 숫자가 늘어날 것으로 보입니다.멀티스레드 요청 디스패치를 ​​염두에 두고 애플리케이션을 작성하는 것이 좋습니다.

다른 팁

다음은 공유 객체 수정에주의를 기울이지 않으면 발생할 수있는 일을 보여주는 비교적 간단한 예입니다.

  1. 새 레일 프로젝트 만들기 : rails test

  2. 새 파일을 만듭니다 lib/misc.rb 그리고 이것에 넣습니다 :

    class Misc
      @xxx = 'Hello'
      def Misc.contents()
        return @xxx
      end
    end
    
  3. 새 컨트롤러 생성 : ruby script/generate controller Posts index
  4. 변화 app/views/posts/index.html.erb 이 코드를 포함하려면 :

    <%
      require 'misc'; y = Misc.contents() ; y << ' (goodbye) '
    %>
    <pre><%= y %></pre>
    

    (이것은 우리가 암시 적으로 공유 된 객체를 수정하는 곳입니다.)

  5. 편안한 경로를 추가하십시오 config/routes.rb.
  6. 서버를 시작하십시오 ruby script/server 페이지를로드하십시오 /posts 여러번. 당신은 수를 볼 수 있습니다 ( goodbye) 각 연속 페이지에서 하나씩 증가하는 문자열.

승객을 사용한 평균 배포에는 아마도 요청에서 요청으로 (정적) 상태를 유지하는 각 프로세스 내에서 클래스를 공유하는 여러 앱 프로세스가있을 수 있습니다. 그러나 각 요청은 컨트롤러의 새로운 인스턴스를 만듭니다.

이것을 뚜렷한 공유 상태 환경의 클러스터라고 할 수 있습니다.

Java 유추를 사용하려면 캐싱을 수행하고 요청에서 요청으로 작동하도록 할 수 있습니다. 모든 요구.

아무것도 공유하지 않는 것이 때로는 좋은 생각입니다.그러나 모든 요청에 ​​대해 대규모 애플리케이션 프레임워크와 대규모 도메인 모델 및 많은 양의 구성을 로드해야 하는 경우에는 그렇지 않습니다.

효율성을 위해 Rails는 애플리케이션 수명 동안 모든 요청에서 공유할 수 있도록 일부 데이터를 메모리에 유지합니다.이 데이터의 대부분은 읽기 전용이므로 걱정할 필요가 없습니다.

앱을 작성할 때 공유 객체(예를 들어 우수한 동시성 제어 기능을 기본으로 제공하는 데이터베이스 제외)에 쓰지 마십시오. 그러면 괜찮을 것입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top