В Rails нет общего доступа или отдельные запросы могут обращаться к одним и тем же переменным времени выполнения?

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

Вопрос

PHP работает в среде без общего доступа, что в данном контексте означает, что каждый веб-запрос выполняется в чистой среде.Вы не можете получить доступ к данным другого запроса, кроме как через отдельный уровень персистентности (файловая система, база данных и т. д.).

А как насчет Ruby on Rails?Я просто читал сообщение в блоге заявляя, что отдельные запросы могут обращаться к одной и той же переменной класса.

Мне пришло в голову, что это, вероятно, зависит от веб-сервера. Часто задаваемые вопросы о дворняге утверждает, что Mongrel использует один поток для каждого запроса, что предполагает среду без общего доступа.Далее в FAQ говорится, что RoR не является потокобезопасным, что также предполагает, что RoR не будет существовать в общей среде, если новый запрос не будет повторно использовать объекты в памяти, созданные из предыдущего запроса.

Очевидно, это имеет огромные последствия для безопасности.Итак, у меня есть два вопроса:

  1. Является ли среда RoR ничем не разделенной?
  2. Если RoR запускается (или мощь запускаться в некоторых обстоятельствах) общая среда, в отношении каких переменных и других хранилищ данных мне следует опасаться?

Обновлять:Я уточню дальше. В контейнере сервлетов Java вы можете иметь объекты, которые сохраняются при нескольких запросах.Обычно это делается для кэширования данных, к которым имеют доступ несколько пользователей, подключений к базе данных и т. д.В PHP это невозможно сделать на уровне приложения, это необходимо сделать на отдельном уровне персистентности, таком как Memcached.Итак, двойной вопрос:какой сценарий похож на RoR (PHP или Java), а если похож на Java, который типы данных сохраняются в нескольких запросах?

Это было полезно?

Решение

Короче:

<Ол>
  • Нет, Rails never работает в среде без общего доступа.
  • Будьте параноиком в отношении переменных класса и переменных экземпляра класса .
  • Более длинная версия:

    Процессы Rails начинают свой жизненный цикл с загрузки платформы и приложения. Как правило, они будут запускать только один поток, который будет обрабатывать много запросов в течение срока его службы. Поэтому запросы будут отправляться строго последовательно .

    Тем не менее, все классы сохраняются в разных запросах. Это означает, что любой объект, на который ссылаются ваши классы и метаклассы (например, переменные класса и переменные экземпляра класса), будет использоваться совместно для всех запросов. Это может вас укусить , например, если вы попытаетесь запоминать методы ( @var || = дорогая_калькуляция ) в своих методах class , ожидая этого будет сохраняться только во время текущего запроса. В действительности, расчет будет выполняться только по первому запросу.

    На первый взгляд может показаться целесообразным реализовать кэширование или другое поведение, которое зависит от постоянства запросов. Как правило, это не так. Это связано с тем, что в большинстве стратегий развертывания используется несколько процессов Rails для противодействия их собственной однопоточной природе. Просто не круто блокировать все запросы во время ожидания медленного запроса к базе данных, поэтому самый простой выход - порождать больше процессов. Естественно, эти процессы не разделяют ничего (кроме некоторой памяти, которую вы не заметите). Это может вас укусить , если вы сохраняете вещи в своих переменных класса или переменных экземпляра класса во время запросов . Затем, так или иначе, иногда материал кажется присутствующим, а иногда, кажется, ушел. (На самом деле, конечно, данные могут присутствовать или не присутствовать в одном процессе , а в других - отсутствовать).

    Некоторые конфигурации развертывания (особенно JRuby + Glassfish) являются фактически многопоточными. Rails является потокобезопасным, поэтому он может справиться с этим. Но ваше приложение не может быть потокобезопасным. Все экземпляры контроллера выбрасываются после каждого запроса, но, как мы знаем, классы являются общими. Это может вас укусить , если вы передадите информацию в переменные класса или в переменные экземпляра класса. Если вы не используете методы синхронизации должным образом, вы вполне можете оказаться в аду состояния гонки.

    <Ч>

    В качестве примечания: Rails обычно запускается в однопоточных процессах, потому что реализация потоков в Ruby отстой. К счастью, в Ruby 1.9 дела обстоят немного лучше. И намного лучше в JRuby.

    Поскольку обе эти реализации Ruby набирают популярность, представляется вероятным, что многопоточные стратегии развертывания Rails также получат популярность и количество. Хорошая идея - написать приложение с учетом многопоточной диспетчеризации запросов.

    Другие советы

    Вот относительно простой пример, иллюстрирующий, что может произойти, если вы не будете осторожны с изменением общих объектов.

    1. Создайте новый проект Rails: 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. Добавьте маршруты RESTful в config/routes.rb.
    6. Запустить сервер ruby script/server и загрузите страницу /posts несколько раз.Вы увидите количество ( goodbye) строки увеличиваются на единицу при каждой последующей перезагрузке страницы.

    При обычном развертывании с использованием Passenger у вас, вероятно, есть несколько процессов приложения, которые не разделяют между ними ничего, кроме классов внутри каждого процесса, которые поддерживают свое (статическое) состояние от запроса к запросу. Каждый запрос, тем не менее, создает новый экземпляр ваших контроллеров.

    Вы можете назвать это кластером отдельных сред общего состояния.

    Чтобы использовать аналогию с Java, вы можете выполнить кэширование и заставить его работать от запроса к запросу, вы просто не можете предположить, что оно будет доступно при каждом запросе.

    Разделили - ничего, иногда хорошая идея. Но не тогда, когда вам нужно загружать большую прикладную инфраструктуру и модель большого домена и большое количество конфигурации при каждом запросе.

    Для эффективности Rails хранит некоторые данные, доступные в памяти, для совместного использования всеми запросами в течение всего срока службы приложения. Большая часть этих данных доступна только для чтения, поэтому не стоит беспокоиться.

    Когда вы пишете свое приложение, держитесь подальше от записи в общие объекты (например, за исключением базы данных, которая поставляется из коробки с хорошим контролем параллелизма), и у вас все будет в порядке.

    Лицензировано под: CC-BY-SA с атрибуция
    Не связан с StackOverflow
    scroll top