Play 框架手册(22) – 生产部署

为了优化生产环境的应用程序,这里有一些小建议。

22.1. application.conf

首先, 最好的方式就是给你的应用程序框架指定的一个 id。 让我们以 production 为例。参考 manage application.conf in several environments 节以了解如何实现。

设置框架为 prod 模式

%production.application.mode=prod

在这种模式下,框架将预编译所有的 java 源代码和模板。如果在这步发生错误,应用程序将不能启动。对源代码的修改将不能进行热加载。

定义一个真实的数据库

 

如果你使用的是开发数据库(如 db=mem 或 db=fs),你应用配置真正可长期使用的数据库,如 mysql:

%production.db.url=jdbc:mysql://localhost/prod
%production.db.driver=com.mysql.jdbc.Driver
%production.db.user=root
%production.db.pass=1515312

禁止 JPA 的自动结构更新

如果使用了 hibernate 提供的数据库结构自动更新特性, 那么你应该在生产模式下禁止该特性。 

对生产服务器来说, 让 hibernate 自动修改生产环境下的数据库结构和数据是个坏主意!

进行初始化部署是另一个潜在的问题。在这种情况下只需要进行如下定义:

%production.jpa.ddl=create

定义一个安全的 secret key:

Play secret key 将用于安全密码功能,比如 session 签名。你的应用程序必须保证这个 key 十分安全可靠。

%production.application.secret=c12d1c59af499d20f4955d07255ed8ea333

可以使用 play secret 命令来生成一个新的安全的随机 key (至少在某个 OS 上是安全的)。如果计划把应用程序发布到多个服务器上,请记住一定要在所有的应用程序实例上使用同一个 key!

22.2. 日志配置

在生产模式下, 使用循环日志文件是个好主意。 一定不要发送日志信息到控制台,这是因为这此日志信息将会写入 logs/system.out 文件,而且大小不受限制!

在 conf/目录创建一个定制的 log4j.properties 文件:

log4j.rootLogger=ERROR, Rolling
log4j.logger.play=INFO

# Rolling files
log4j.appender.Rolling=org.apache.log4j.RollingFileAppender
log4j.appender.Rolling.File=application.log
log4j.appender.Rolling.MaxFileSize=1MB
log4j.appender.Rolling.MaxBackupIndex=100
log4j.appender.Rolling.layout=org.apache.log4j.PatternLayout
log4j.appender.Rolling.layout.ConversionPattern=%d{ABSOLUTE} %-5p
~ %m%n

22.3. 前端 http 服务器(Front-end HTTP server)

把应用程序作为独立服务器部署到 80 端口非常容易:

%production.http.port=80

但是, 如果你计划在同一台服务器部署多个应用程序,或者为应用程序的多个实例实现负载平衡(以实现可伸缩性部署或故障容错),可以使用前端 http 服务器实现这个功能。

注意,如果使用前端服务器和和直接使用 play 服务器相比,前者将不能提供更好的展现效果!

部署到 lighttpd 服务器的设置 

本示例将向你展现如何配置 lighttpd 作为前端 web 服务器。注意,本配置同样适用于 Apache,但如果你只需要虚拟化或负载平衡功能, lighttpd 是最好的选择,而且非常容易配置!

/etc/lighttpd/lighttpd.conf 文件的配置示例如下(linux):

server.modules = (
      "mod_access",
      "mod_proxy",
      "mod_accesslog"
)
...
$HTTP["host"] =~ "www.myapp.com" {
    proxy.balance = "round-robin" proxy.server = ( "/" =>
        ( ( "host" => "127.0.0.1", "port" => 9000 ) ) )
}

$HTTP["host"] =~ "www.loadbalancedapp.com" {
    proxy.balance = "round-robin" proxy.server = ( "/" => (
          ( "host" => "127.0.0.1", "port" => 9000 ),
          ( "host" => "127.0.0.1", "port" => 9001 ) )
    )
}

部署到 Apache 服务器的设置 

下面的示例显示了如何在 Apache httpd server 下 进行配置: 

LoadModule proxy_module modules/mod_proxy.so
...
<VirtualHost *:80>
  ProxyPreserveHost On
  ServerName www.loadbalancedapp.com
  ProxyPass / http://127.0.0.1:9000/
  ProxyPassReverse / http://127.0.0.1:9000/
</VirtualHost>

Apache 作为前端代理服务器,可以允许透明更新你的应用程序一个基本的例子,就是让前端代理服务器负载平衡两个 play 应用程序,如果其中一个失效,那么另外一个将自动承担全部任务。

让我们在 9999 和 9998 两个端口分别启动相同的应用程序。

把应用程序复制一件,修改其 application.conf 文件中的端口号。

在每个应用程序目录下分别运行如下命令:

play start mysuperwebapp

现在,让我们对 Apache 服务器进行配置,让其实现负载平衡。

在 Apache 里,我们使用如下配置:

<VirtualHost mysuperwebapp.com:80>
  ServerName mysuperwebapp.com
  <Location /balancer-manager>
    SetHandler balancer-manager
    Order Deny,Allow
    Deny from all
    Allow from .mysuperwebapp.com
  </Location>
  <Proxy balancer://mycluster>
    BalancerMember http://localhost:9999
    BalancerMember http://localhost:9998 status=+H
  </Proxy>
  <Proxy *>
    Order Allow,Deny
    Allow From All
  </Proxy>
  ProxyPreserveHost On
  ProxyPass /balancer-manager !
  ProxyPass / balancer://mycluster/
  ProxyPassReverse / http://localhost:9999/
  ProxyPassReverse / http://localhost:9998/
</VirtualHost>

其中最重要的部分为 balancer://mycluster,这里声明加载负载平衡。+H 选项的意思是让第二个Play 应用程序处于待命状态。 当然, 这里也可指示第二个 play 应用程序为 load-balance 负载平衡状态。

当需要更新 mysuperwebapp 时,需要使用如下命令:

play stop mysuperwebapp1

这里,所有的工作都会被 load-balancer 转发到 mysuperwebapp2,与此同时,mysuperwebapp1 进行更新操作,一定操作完成,就可执行以下命令:

play start mysuperwebapp1

这时,你就可以安全更新 mysuperwebapp2 了。

Apache 同时提供了显示服务器集群 cluster 的方法。方法是在浏览器里访问应用程序的/balancer-manager 地址,就可以查看服务器集群的当前状态。

因为 Play 是完全无状态的, 因此, 你不需要在 2 个集群(服务器)间管理 session,事实上,你可以很容易扩展到 2 个以上的 play 实例。

高级代理设置 

当使用 http 前端服务器,需要一个地址作为 http 服务器的统一对外地址,用于接收所有的请求。通常情况下,同一台服务器即作为 play 应用服务器,又作为代理服务器,这时,play 将把所有的请求看成是来自 127.0.0.1 的请求。

Proxy 服务器可以为请求添加一个特定的 header 来告诉被代理的应用程序,这个请求来自哪里。大多数 web 服务器都会远程客户端 ip 地址添加一个 X-Forwarded-For header 作为第一个参数。如果你在 XForwardedSupport 配置里允许 forward 转发支持, Play 会从代理的 ip 至客户端的 ip 更改request.remoteAddress,为了能够正常工作,你就必须列出你的代理服务器的 ip 地址。

然而,这样并不涉及主机头,它将仍旧被代理服务器发布。如果你使用的是Apache 2.x, 你可添加如下指令:

ProxyPreserveHost on

host: header 仍旧是客户端核发的原始 host 请求 header。通过这两种技术的组合,你的应用程序看起来好像是直接暴露出来的单一主机。

22.4. HTTPS 配置 

内建服务器支持 HTTPS 协议,你可以在生产环境中直接使用。它支持证书管理,即可以是传统的 java keystore,也可以是简单的 cert key 文件。为了为你的应用程序启动 HTTPS 连接,只需要在 applictaion.conf 里声明 https.port 配置属性就行。

http.port=9000
https.port=9443

这里需要把你的证书放到 conf 目录。 Play 支持 X509 证书和 keystore 证书。 X509 证书必须采用如下命名方式:host.cert 作为证书命名,host.key 作为 key 命名。如果使用的是 keystore,那么默认命令应该为 certificate.jks。

如果使用的是 X509 证书,那么可以在 application.conf 里配置如下参数:

# X509 certificates
certificate.key.file=conf/host.key
certificate.file=conf/host.cert
# In case your key file is password protected
certificate.password=secret
trustmanager.algorithm=JKS

使用 keystore 时,配置如下:

keystore.algorithm=JKS
keystore.password=secret
keystore.file=conf/certificate.jks

注意,上面采用的是默认值。

你可以使用 openssl 生成自签名 self-signed 证书: 

openssl genrsa 1024 > host.key
openssl req -new -x509 -nodes -sha1 -days 365 -key host.key > host.cert

如果使用的是 Java keystore 机制,那么可以在 application.conf 里配置如下属性:

# Keystore
ssl.KeyManagerFactory.algorithm=SunX509
trustmanager.algorithm=JKS
keystore.password=secret
keystore.file=certificate.jks

上面的值采用的是默认值。

22.5. 不依赖 Python 进行部署 

默认情况下,大多数 Unix 机器都安装了 Python,在 windows 下,play 已经自动植入了 Python。但可能存在你需要部署的服务器并没有安装 Python。

为解决这个问题,play 应用程序里的 build.xml 文件提供了有限的功能。

在应用程序目录下,使用以下命令启动服务器:

ant start -Dplay.path=/path/to/playdirectory

警告: 使用 play 命令时,输出信息将直接转发到 System.out,使用 Ant 时,标准输出将不可访问,因此,提供 Log4j 属性文件是必要的。

停止服务器时,使用如下命令:

ant stop -Dplay.path=/path/to/playdirectory

注意,你可在系统环境变量里为设置 play 框架路径,也可在应用程序的 build.xml 文件里设定。


前一篇:
后一篇:

发表评论