Apache Passenger的配置通常有以下5类,需要协同工作:
- 程序加载
- 性能优化
- 安全
- 请求/应答定义化
- 日志和定位问题
我以工作的项目的配置文件为例来进行参数(包含案例中的参数但不仅限于案例中参数)讲解。
# security
PassengerDefaultUser apache
# application loading
PassengerRoot /opt/rh/rh-passenger40/root/usr/share/passenger/phusion_passenger/locations.ini
PassengerRuby /opt/rh/rh-ruby22/root/usr/bin/ruby
# performance tuning
PassengerMaxPoolSize 60
PassengerPoolIdleTime 150
PassengerMinInstances 20
PassengerMaxRequests 1000
# application loading
RailsEnv staging
RackEnv staging
User Account Sandboxing
--> Passenger切换用户的一个特性
假设在一个server上我们有多个应用,有了这个特性,我们就可以给不同的应用执行不同的用户,以提高系统整体的安全性。
例如一个server上有两个应用,一个应用可能是A的,一个是B的,如果以同一用户去运行所有应用,则B可以读到A的敏感数据。这是很不安全的。User account sandboxing就解决了这个问题。该特性很容易给每个应用指定一个用户。只要不同应用的文件权限设置无误,则该特性就降低了或着消除一定的安全隐患。B无法查看A的数据,反之亦然。
PassengerDefaultUser
--> 给应用配置特定用户, 且在切换用户失败的情况下,都切换到默认用户
PassengerRoot
--> Passenger 自身数据目录
如果你使用Debian或者RPM包去装Passenger的话,PassengerRoot会自动配置,而无需手动配置。
如果你使用Homebrew, tarball或者RubyGems去安装Passenger, 在安装过程中,就会被要求给其设置正确值,并且会插入Apache的配置文件。
如果这个选项没有配置,Passenger无法启动,也将导致Apache无法启动
如果这个选项配置错误,Passenger会尝试自己的一些配置,如果失败,则无法启动,也将导致Apache无法启动
PassengerRuby
--> 给Ruby web application指定Ruby解释器
如果该值没有指定,则其值默认会指向PassengerDefaultRuby. Passenger可以同时管理不同的应用,则该参数可以用来为不同的应用指定不同的Ruby解释器。Passenger是支持多种语言, 例如Python和Nodejs。下图就是Passenger配置多应用的典型。
# Use Ruby 2.1 by default.
PassengerDefaultRuby /usr/bin/ruby2.1
# Use Python 2.6 by default.
PassengerPython /usr/bin/python2.6
# Use /usr/bin/node by default.
PassengerNodejs /usr/bin/node
<VirtualHost *:80>
# This Ruby web app will use Ruby 2.1
ServerName www.foo.com
DocumentRoot /webapps/foo/public
</VirtualHost>
<VirtualHost *:80>
# This Rails web app will use Ruby 2.2.1, as installed by RVM
PassengerRuby /usr/local/rvm/wrappers/ruby-2.2.1/ruby
ServerName www.bar.com
DocumentRoot /webapps/bar/public
# If you have a web app deployed in a sub-URI, customize
# PassengerRuby/PassengerPython inside a <Location> block.
# The web app under www.bar.com/blog will use JRuby 1.7.1
Alias /blog /websites/blog/public
<Location /blog>
PassengerBaseURI /blog
PassengerAppRoot /websites/blog
PassengerRuby /usr/local/rvm/wrappers/jruby-1.7.1/ruby
</Location>
<Directory /websites/blog/public>
Allow from all
Options -MultiViews
# Uncomment this if you're on Apache >= 2.4:
#Require all granted
</Directory>
</VirtualHost>
<VirtualHost *:80>
# This Flask web app will use Python 3.0
PassengerPython /usr/bin/python3.0
ServerName www.baz.com
DocumentRoot /webapps/baz/public
</VirtualHost>
PassengerPoolIdleTime
--> 应用没有traffic(请求负载),shutdown该应用时的等待时常。默认为5分钟。
设置该值时是为了在系统很长时间没人使用时,可停掉应用,以节省资源(内存)。这个值设置的过少,会使得应用需要经常启动,而使用户体验会有一定的影响。
这个值的大小取决于用户在一个动态界面的停留的平均时间,若该值为X,则建议该值为2X。
当该值设置为0,该应用进程会一直存在除非必须停掉应用。一个典型的场景为:Passenger同时支撑了2个应用, foo和bar。如果用户想访问foo, 但是进程池被bar进程占满,这时Passenger就会等到bar的一个进程不再处理进程的时候就把它停掉,而把启动foo进程。
通常,如果这个程序的宿主机不是共享的,则该值建议设置为0。
PassengerMaxPoolSize
--> 可同时存在的最大的应用进程的数据。默认值为6.
通常,该值越大,应用可处理的并发量就越大,相应的CU的利用率也就越高,相应的内存的消耗也越高。
该值的设计取决于你系统的硬件和负载情况,但该值不宜过大,因为过大,系统的进程过多,会吃尽CPU和内存而使系统崩溃。
另外,有以下亮点需要注意:
- 无论PassengerMinInstances和PassengerMaxInstances的值,进程总数都不会超过PassengerMaxPoolSize
- Passenger可以同时服务于不同的应用,这个值是对所有应用的进程总数
PassengerPreStart
--> 在启动Apache时提前启动应用进程
通常,在启动Apache时并不会立即启动应用进程,而在用户第一次访问Web应用时才会启动。所以第一个访问该应用的用户需要等待Passenger启动应用所带来的延迟。如果想要避免这种情况,则可以使用该参数。
需要注意的是:
- 该参数的值是一个web application的URL而非on/off. 且该值需要:
- 该值应等于ServerName的值
- 该值应包含应用端口,如不设置端口,则使用默认值80
- 这个URL必须web application的有效URI
PassengerMinInstances
--> 该应用最小的进程数
如果该值为0,则和PassengerPoolIdleTime一起工作时,等程序长时间没有人访问,则就会出现应用被停掉的情况。所以如果,不希望进程停掉,除了设置PassengerPoolIdleTime外还可以配置PassengerMinInstance的值大于0.
需要注意的是:
- 这个参数本身不会对Apache的启动过程有任何影响。它只是保证当这个应用被第一次访问的时候:
- 最少有这么多进程被启动
- 这些进程不会被clean掉
- 如果你想保证在Apache启动的时候就同时有多个应用进程被启动,则可以同时配置PassengerPreStart.
PassengerMaxRequests
--> 一个应用进程在重启之前处理的最大请求数
若该值设为1000,则一个应用进程在处理1000个进程后就会停掉,然后Passenger会重新启动一个进程。
若该值为0,则意味着没有最大请求数。如果这个进程长时间没有被访问,则也有被PassengerPoolIdleTime影响,而被当成Idle进程而停掉。
如果应用程序有内存泄露,则这个参数可以部分解决这个问题。在处理一些请求就被关掉后,则这个进程所有的内存都会被释放掉。防止内存泄露还有一个方法就是配置PassengerMemoryLimit
我们在使用该参数出发点应该是将其仅做为系统被误用时的变通方法。系统的内存泄露的问题应该通过提高代码质量解决而不应该过分依赖于该参数。
PassengerAppRoot
--> Passenger管理的应用程序的根目录。默认同 DocumentRoot.
当应用程序的根目录不同于DocumentRoot时,则可以使用该参数覆盖。当你的应用程序强制化,而Passenger默认许多约定都不同时,这个参数可能用的到。
PassengerAppGroupName
-->设置当前应用的所属的应用用户组。
Passenger 以per-app--group-name的基础存储大多数应用启动时的配置--例如环境变量,进程限制等。如果你同时启动同一个应用的两个版本,如果不同的版本有不同的环境变量,则你必须将他们分配到不同的应用组下。这个场景有点复杂,这里不详细讲解。
RAILS_ENV/RAKE_ENV
--> 同PassengerAppEnv,默认值为production
一些web框架,例如Rails和Connect.js, 根据不同的环境变量会有不同的行为。例如你想做开发,则可指定该值为development。如果你设置其他的环境变量,则可以用SetEnv。这个值结合PassengerAppGroupName可以支持同一应用不同版本等复杂场景。对于该场景,本文不涉及。
综上,我们项目的配置是:
- 默认程序用户为apache
- 程序的Ruby解释器为Ruby2.2
- 最大应用进程池为60
- 150Mins无人访问则停掉应用进程
- 最少保留20个应用进程
- 当该进程处理完1000个请求,则停掉该进程
- 当前的环境为staging