《High Performance Django》阅读笔记(二)

第三章:The Deployment

先决条件

操作系统

作者推荐使用 Ubuntu。同时作者给出了选择其他操作系统时,需要考虑的事情:

  • 能够很容易的就使用 Python 2.7+ 。有些操作系统要安装 2.7+ 版本的 Python 非常的麻烦,如果是这样的话你就要慎重考虑了。
  • 有长久的安全更新支持。

配置管理

  • Chef, Puppet, Ansible, Salt 都是比较好的配置管理工具
  • Fabric 不是配置管理工具,如果你把它当作配置管理工具的话,会有你头疼的时候。你可以在 Fabric 的基础上 构建你自己的配置管理工具。

进程管理

  • 系统默认的工具:upstart, systemd
  • 第三方软件:deamontools, supervisord, circus

更新代码

更新代码一般需要进行下面几步:

  1. 从版本控制服务器上拉取最新的代码
  2. 更新依赖
  3. 合并数据库更改(migrate)
  4. 收集,压缩,推送静态文件到 CDN
  5. reload WSGI 服务器
  6. 重启后台 workers

推荐写个脚本自动执行这些操作,这样不容易出错。如果要更新多台服务器的话,可以使用远程执行 框架来做这种事情,比如: Salt, Fabric。

有一点特别要注意的是,一旦服务上线就应该尽可能的使用平滑 reload 的方式来代替重启进程的暴力方式。

多个远程环境

至少要有两个环境吧:打包/开发环境,生产环境。 同时多个环境尽量保证一致性,尤其是多个生产环境之间(设置,软件,系统,等等)。 不过有些东西还行要区分的,比如:

  • 第三方服务配置。比如,你肯定不希望在开发环境下触发支付操作或发送文件到生产环境下的 CDN 上。
  • 获取数据的问题。经常看到某些人在开发环境下使用线上数据库的副本,但是这里有几个问题要考虑:
    • 你的开发环境更生产环境一样安全吗?监控松散的开发机器是黑帽黑客经常会攻击的目标。
  • 有可能会从你的应用中发送邮件或通知吗?从你的开发环境下向你的用户发送数千封邮件不仅是非常 尴尬的事情,同时也会影响你们的商业。

避免单点故障

要经常备份,确保你知道所有存储的数据(数据库,用户上传的数据,等等)都有备份。这样出现故障的时候 其他其他机器的时候丢失的数据会少一点。

高可用是一个可以考虑的方法,如果对你的商业来说他是非常重要的话。 HA 可以保证在出现服务挂掉 的情况下能够无缝自动切换到备用服务或者说不用手动切换。不过需要注意的是通常构建高可用 的花费比服务当掉的花费还高。

在考虑架构的时候要考虑到如何解决单点故障的问题。举个例子,当使用第三方的 Amazon EC2 的时候, 你是否能够接受某些区域的设备宕机,整个地区呢?如果服务商 Amazone 当了怎么办? 越早考虑这些问题就能在灾难实际发生的时候更好的应对。

服务器布局

  • 负载均衡器: 可以使用云服务商提供的负载均衡服务或者使用 nginx, Haproxy。对于负载均衡器网络 带宽是个非常重要的注意点。
  • Web 加速器:网络带宽和内存是值得关注的点
  • 应用:CPU 和内存值得关注。
  • 后台运行的 workers:后台运行的任务通常都是 CPU 密集型的任务并且运行在独立的服务器上。一个服务器上可以运行 多个 workers。
  • 缓存:你的缓存服务器需要更多的内存。另一个需要注意就是网络带宽,它可能会在内存之前成为瓶颈。如果网络开始 拥堵的时候, Django 可以配置多个缓存服务器。
  • 数据库:足够的内存非常重要,最用是足够把你的数据都装载在内存里。 如果你预期会有 64GB 的数据,那么至少要有 64GB 的内存。 磁盘速度也非常重要。购买你能够负担得起的最快的磁盘。 如果你用的是虚拟机的话,你需要留意你其实是在跟你的邻居共享一个物理磁盘,常规的实践是尽可能的买最大的虚拟机。

优化技术栈

优化数据库

优化 uWSGI

优化 Django

CACHES

如果你使用 Memcached,使用 pylibmc 这个库会有更高的性能。 redis 的话可以使用 django-redis

缓存过期是第一个需要面临的问题,一个缓存 key 过期或者被刷新都有可能摧毁你的数据库。 幸运的是有个简单包可以解决这个问题: django-newcache

还有一个问题就是如果缓存服务器宕机了会到期用户收到 “500 Server Error”的响应。 将使用一个缓存服务器改为三个可以降低出错的几率。 你需要考虑当缓存服务器宕机的时候,你是需要你的网站也跟着宕机,还是希望你的应用继续 运行良好只是把它当作缓存未命中来处理?作者创建了一个 django-ft-cache 包用来 解决这个问题,它会将任何的 memcached 操作用 try/except 包裹,捕获这里的异常, 这样缓存服务器当掉时请求依然可以被正确处理。

SESSION_ENGINE

把 session 保存在数据库中非常影响性能,一个好的办法是保存在缓存中。如果用 redis 的话 可以使用 cache backend, 用 memcached 的话 cached_db backend 也还行。 另一个办法就是使用 signed_cookies backend, 让客户端存储 session 数据。

DATABASES

可以通过 DATABASES 设置增加 CNN_MAX_AG key 选项来定义重用数据库连接。 比如 300, 这将告诉 Django 保持打开和重用数据库连接 5 分钟。

LOGGING

不要定义 LOGGING 将日志保存到文件中,而是应该输出到 STDERR ,让进程管理器来处理日志。

MIDDLEWARE_CLASSES

不要轻易自定义中间件,因为中间件会在每个请求中执行。所以确保你知道每个中间件都做了什么, 以及尽可能的不要在中间件中执行数据库查询操作。

常规安全问题

需要注意 clickjacking 和 XSS(Cross Site Scripting)。最简单的方法是使用 django-secure 项目来检查安全问题。 另一个安全问题是,确保你的 admin 后台处于保护中,如果你把它开放出去了,确保使用了非常 复杂的管理员密码。最好是把它变成一个内网服务,让它不能从外部互联网访问。

配置你的服务器

安全

  • 调整 SSH 配置:禁用 root 登录,禁用密码登录,更改默认端口。
  • 应用安全补丁:关注一下系统安全问题,及时更新 zer-day 补丁(比如,Hearbleed)
  • 使用私有网络:大多数云服务器都提供私有网络服务,只允许访问你帐号下的服务。在私有网络 中访问你的服务器可以加大被人攻击你的难度。
  • 保护内网服务:内网服务包括控制台,开发服务器,持续集成系统。它们会成为你安全网络的一道暗门。 将它们用 VPN 或认证代理锁起来,如果你没有使用 VPN 的话,确保传输数据以及登录时总是使用 SSL/HTTPS。 锁住你的开发环境可以确保 google 不会抓取它从而伤害你的 SEO)
  • 防火墙:只允许指定端口和 IP 访问你的服务器。硬件防火墙很棒,软件防火墙比如 iptables 也不错。
  • 不要在 root 下运行:不在 root 下运行可以防止某些人运用 RCE(remote code execution)获取你服务器的 root 访问权限。使用标准用户登录服务器,只在必要时使用 sudo。
  • 保护你的第三方服务的账户:使用强壮的密码,尽可能的开启两步验证。

备份

对于数据库,有一个运行的 replica 可以很方便的执行全备份。推荐在半夜执行全备份。 进行备份的时候有几个问题需要问一下你自己:

  • 如果有人黑进了你的服务器,他们能够删掉或破坏你的备份吗? 基于这个原因拉取到备份服务器比推送要更好。
  • 如果有人拿到了你的备份会有多糟糕?加密备份文件并且确保黑客没法在同一个服务器上找到解密的方法(注:比如可以使用公钥进行加密,同时服务器上不要存有私钥,这样就不会被黑客在服务器上找到解密的方法)。
  • 你有测试过备份是否可用吗?定期测试你的备份,验证它们是否真的有效。

监控

没有监控的话,线上网站就会成为一个大黑盒。你没法知道实际情况是怎样的,也就没法进行性能优化了。

instrumentation

对于应用,你需要知道下面这个问题:

  • 我的系统中最慢的部分是什么?
  • Django 处理响应的平均耗时是多少?
  • 哪个视图是最慢的?或者花费最多的时间?
  • 哪个数据库查询是最慢的?或者花费最多的时间?
  • 这些数据一段时间内是如何变化的?

NewRelic 是个探测这些问题的比较好的服务,它可以很方便的安装。 然而, NewRelic 是闭源的,专有的系统,同时也非常的贵。有一些开源产品可以替代它。 比如:Graphite

服务器资源

关于服务器资源需要监控如下数据:

  • 平均负载
  • CPU 负载
  • 物理内存使用情况
  • 磁盘相关数据
  • 网络 I/O

告警

下列情况需要发送告警:

  • 超过 X% 的请求出现错误
  • 服务器宕机
  • 服务器资源占用过高:负载,虚拟内存,磁盘等等
  • 服务未响应

日志

需要收集如下日志:

  • 从你的负载均衡器都应用的 Apache 风格的日志
  • 任何应用内的日志
  • 相关服务的 syslog 日志
  • 数据库慢查询日志,以及在不会导致数据库连接的 I/O 问题(尤其是磁盘或网络)的前提下收集所有数据库查询的日志。

错误汇报

在生成环境下 Django 默认会在出现异常时给网站管理员发送异常邮件。这个功能有时也会导致一些问题:

  • Email 不利于追踪错误
  • 如果你的错误发生在一个高访问的页面的话,你实际上是在 DoS 你的邮件服务器, 可能导致被加入黑名单,或者你的邮件服务商会关掉你的服务(他们不想在几秒内发送超过 10K 的邮件)。

幸运的是,更好的错误汇报方式已经存在了,开源的 Sentry 项目是个非常好的解决方案。 Sentry 并不会发送 10K 的邮件,它之后在第一次出现错误时邮件通知你,之后收集并在 Web 页面上 暂时其他时候的错误用于分析问题。

还有一个关于错误的主题就是确保有一个漂亮的不引来应用服务的 500.html 文件,并且已经在服务器上配置好了出错是使用 这个页面。


Comments