背景

在AWS Elastic Beanstalk中,如果选用Ruby with Passenger运行Rails时,会遇到一个问题,就是EB环境中的Passenger的max_pool_size是默认的6。如果EB中的Instance选用的是性能比较高的类型,只起6个Passenger进程会是一个巨大的浪费。下面介绍几个修改EB中Passenger max_pool_size参数的方法。

Passenger官方说明

最新的官方Introduction to configuring Passenger Standalone文档中,Passenger Standalone可以通过如下几种方式来修改启动参数

  • 一、传递参数给启动命令passenger start
  • 二、使用环境变量(从5.0.22开始)
  • 三、通过配置文件Passengerfile.json

EB的限制

EB中的Passenger, 版本还是使用的4.0.60, 因此官网所述的三个方法中,在EB中并不完全适用。

  • 方法二需要在5.0.22以上版本才支持,因此在EB环境中不可用
  • 方法三中所述的Passengerfile.json是在5.0.1中才被正式使用的,在之前的版本中,使用的是passenger-standalone.json。所以在EB环境中,需要使用passenger-standalone.json来修改启动参数。文件命令的变化可参见Passenger 5.0.1的Release Note

实现

通过passenger-standalone.json来实现

在项目代码主目录下,添加文件passenger-standalone.json, 文件内容为

1
2
3
{
"max_pool_size": 10
}

eb deploy完成后,使用EC2的key pair登陆EC2, sudo后运行passenger-status。可以看到max_pool_size已成功修改为10。

passenger-standalone_for_max_pool_size

通过EB中的passenger命令参数来实现

EB环境中的EC2的passenger启动脚本是/etc/init.d/passenger,实际运行的是/opt/elasticbeanstalk/support/conf/passenger

passenger_link_on_EC2_of_EB.jpg

只要通过ebextension配置文件,修改/opt/elasticbeanstalk/support/conf/passenger,添加上对max_pool_size的支持即可。

原始的passenger文件参见origin_passenger

用来修改passenger,支持读取环境变量中的PASSENGER_MAX_POOL_SIZE的extension config如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
files:
"/opt/elasticbeanstalk/support/conf/passenger":
mode: "000755"
owner: root
group: root
content: |
#!/usr/bin/env bash
#
# chkconfig: 2345 80 20
# description: Passenger
#
EB_HTTP_PORT=$(/opt/elasticbeanstalk/bin/get-config container -k http_port)
EB_APP_USER=$(/opt/elasticbeanstalk/bin/get-config container -k app_user)
EB_APP_DEPLOY_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k app_deploy_dir)
EB_APP_PID_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k app_pid_dir)
EB_APP_LOG_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k app_log_dir)
EB_SCRIPT_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k script_dir)
EB_SUPPORT_DIR=$(/opt/elasticbeanstalk/bin/get-config container -k support_dir)
EB_NGINX_VERSION=$(/opt/elasticbeanstalk/bin/get-config container -k nginx_version)
. $EB_SUPPORT_DIR/envvars
. $EB_SCRIPT_DIR/use-app-ruby.sh
if [ -f /etc/elasticbeanstalk/set-ulimit.sh ]; then
. /etc/elasticbeanstalk/set-ulimit.sh
fi
# fixes http://code.google.com/p/phusion-passenger/issues/detail?id=614
export HOME=/tmp
export PASSENGER_DOWNLOAD_NATIVE_SUPPORT_BINARY=0
if [ -d /etc/healthd ]; then
STARTOPTS="--nginx-version $EB_NGINX_VERSION --nginx-config-template $EB_SUPPORT_DIR/conf/nginx_config_healthd.erb"
else
STARTOPTS="--nginx-version $EB_NGINX_VERSION --nginx-config-template $EB_SUPPORT_DIR/conf/nginx_config.erb"
fi
ENV_STAGE=${RACK_ENV:-$RAILS_ENV} # Read from $RAILS_ENV if $RACK_ENV is empty
if [ ${ENV_STAGE,,} = "production" ]; then # Convert $ENV_STAGE to lower case and compare to "production"
# Disable passenger friendly page for production stage
STARTOPTS="$STARTOPTS --no-friendly-error-pages"
fi
GENERALOPTS="-p $EB_HTTP_PORT --pid-file $EB_APP_PID_DIR/passenger.pid"
SELFOPTS="--max-pool-size ${PASSENGER_MAX_POOL_SIZE:-6}"
function start() {
touch $EB_APP_LOG_DIR/passenger.log
if [ -d /etc/healthd ]; then
mkdir -p $EB_APP_LOG_DIR/healthd
chown -R $EB_APP_USER:$EB_APP_USER $EB_APP_LOG_DIR/healthd
fi
chown $EB_APP_USER:$EB_APP_USER \
$EB_APP_LOG_DIR/passenger.log
passenger start $EB_APP_DEPLOY_DIR $STARTOPTS $GENERALOPTS $SELFOPTS\
-d -e ${RACK_ENV:-$RAILS_ENV} --user $EB_APP_USER \
--log-file $EB_APP_LOG_DIR/passenger.log
}
function stop() {
passenger stop $GENERALOPTS
}
function status() {
passenger status $GENERALOPTS
}
case "$1" in
start)
start
;;
stop)
stop
;;
status)
status
;;
restart|graceful)
stop
start
;;
reload)
su -s /bin/bash -c "touch $EB_APP_DEPLOY_DIR/tmp/restart.txt" $EB_APP_USER
;;
*)
echo "Usage: $0 {start|stop|restart|reload|status}"
exit 1
;;
esac
exit 0

对原passenger脚本进行了两处修改

  • 添加了SELFOPTS
  • 添加SELFOPTSpassenger start命令之后。
1
2
3
4
5
6
7
8
9
10
$ diff origin_passenger passenger_with_selfopt
39a40
> SELFOPTS="--max-pool-size ${PASSENGER_MAX_POOL_SIZE:-6}"
51c52
< passenger start $EB_APP_DEPLOY_DIR $STARTOPTS $GENERALOPTS \
---
> passenger start $EB_APP_DEPLOY_DIR $STARTOPTS $GENERALOPTS $SELFOPTS\
87a89
>
$

该修改参考了如下的两篇帖子:

但这两篇帖子中,都把--max-pool-size放在了GENERALOPTS变量中,但这么设置是存在问题的。
因为脚本里的stop和status也会用到GENERALOPTS这个变量,但passenger stoppassenger status并不支持--max-pool-size这个参数,如果放在GENERALOPTS中,会导致passenger stoppassenger status运行失败。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@ip-172-31-40-19 ec2-user]# passenger stop -h
Usage: passenger stop [options]
Options:
-p, --port NUMBER The port number of a Phusion Passenger
Standalone instance (default: 3000)
--pid-file FILE PID file of a running Phusion Passenger
Standalone instance.
-h, --help Show this help message
[root@ip-172-31-40-19 ec2-user]#
[root@ip-172-31-40-19 ec2-user]# passenger status -h
Usage: passenger status [options]
Options:
-p, --port NUMBER The port number of a Phusion Passenger
Standalone instance (default: 3000)
--pid-file FILE PID file of a running Phusion Passenger
Standalone instance.
-h, --help Show this help message
[root@ip-172-31-40-19 ec2-user]#

所以最终解决方案是额外添加了变量SELFOPTS用来存放参数--max-pool-size, 并且只将SELFOPTS添加到passenger start中。

使用eb deploy发布ebextension到EB中,在EB Console中添加环境变量PASSENGER_MAX_POOL_SIZE并设定所想要的值。

passenger_max_pool_size_env_on_eb_console.jpg

登陆Instance后,即可看到Max pool size已经被设置为PASSENGER_MAX_POOL_SIZE相同的值了。

ebextension_and_env_for_max_pool_size.jpg

相关修改的snippet

原始passenger文件以及ebextension配置文件可参照 https://github.com/jibing57/my-snippet/tree/master/AWS/ElasticBeanstalk/01_increase_passenger_max_pool_size

后记

要修改其他的Passenger启动参数,也可以使用类似的方法来实现。Passenger所支持的参数在官网中都有相关说明,Configuration reference for Passenger Standalone。 唯一要注意的是,EB中的Passenger版本是4.0.60的,版本要求大于4.0.60的选项在EB中是无效的。

Reference

留言