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

第四章:预备

使用 Jmeter 进行负载测试

这一部分主要讲解了 Jmeter 的各种是否方法及配置。

启动计划

启动的时候有些东西需要考虑

  • 使用负载均衡器在新的和旧的之间分流
  • 使用“dark launch”,这样用户就不会感觉到他们访问的是新的服务器
  • 使用代理功能分一部分流量到新的服务器
  • 使用特性标志来发布一个新的特性。

发送流量到一个新的没有缓存的服务器可能会导致临时的高负载 从而在缓存热和起来前击垮你的服务器。预热你的缓存可以解决这个问题。一个比较简单的办法是使用一个脚本在有真实请求前去抓取你的网站上的热门 URLs。

不要在一天的最后时间段或周五的时候升启动,除非你想让你的 整个团队在晚上或周末加班。 你应该在大家都在并且有几个小时或几天的时间来处理 启动过程中出现的问题时候启动,同时也要确保你的成员有时间休息。 如果你的网站访问量比较高的话,尝试在访问量比较低的时间段进行升级操作。

启动前的检查事项

Django 配置项

  • DEBUGTEMPLATE_DEBUG 都设为 False
  • SECRET_KEY 是个非常大的随机字符串并且保密
  • ALLOWED_HOSTS 包含了访问者可能会使用的有效域名
  • TEMPLATE_LOADERS: Cached template loader 已启用
  • SESSION_ENGINE 比默认设置更快
  • CACHES: 使用 Memcached 或 Redis 后端
  • MEDIA_ROOTMEDIA_URL 接受并显示文件上传
  • 管理员账户被限制并且有一个强壮的密码

部署

  • 通过点击各种页面和链接的方式来确认网站是否按预期的结果 工作(没有挂掉的图片和链接)
  • Django 日志是否正常工作
  • 监控平台是否接收到数据。确保你能看到整个技术栈中各级 的错误信息。
  • 错误被汇报并且触发了通知
  • 第三方服务能够接收到数据(支付,分析等等)
  • 从你的应用服务和 Celery workers 中发出邮件的功能 能够正常运行
  • 自定义的错误页面(400,500)已经在各个级别中被设置(负载均衡器,web 加速器,Django)
  • Django admin 没法通过 /admin/ 公开访问
  • SSL 证书有效并且设置是安全的。
  • Django-secure 的 manage.py checksecure 运行起来没有错误输出

基础设施

  • 服务器和服务是安全的,已经锁好了大门
  • 有个简单,正式的程序用来部署新的代码
  • 你有一个可以在需要的时候快速水平扩展服务的计划
  • DNS TTL 可以被修改为 5 分钟或更短的时间在需要更改的时候

第五章 The Launch

监控整个 Launch

服务器资源

可以使用如下工具参考服务器资源使用情况

  • htop
  • varnishstat
  • varnishhist
  • varnishtop
  • varnishlop
  • uwsgitop
  • celery inspect
  • celery events
  • flower
  • memcache-top
  • pg_top
  • pg_stat_statements
  • pt-query-digest
  • mytop

当灾难来临的时候

应用服务器过载

最简单的办法就是通过增加服务器的方式进行水平扩展。 不过你需要注意这将导致你的数据库承受更大的压力, 可能会把数据库搞挂。

当你通过增加服务器的方式把负载降低到可以接受的级别后, 你就需要使用你的低级别的工具来查看为什么会出现负载过高的 情况。你的 web 加速器端缓存命中率过低是一个需要考虑的因素。

数据库服务器过载

如果你的网站是 读多写少的话,可以通过增加 replica 的方式来简单解决响应时间问题。 同时也看看是否在数据库优化时遗漏某些可以优化的项。

应用和数据库服务器过载

你可以从自底向上优化你的数据库,减轻数据库的压力可以让你的应用拥有更高的性能。 你也可以通过优化你的 web 加速器从而减轻应用服务器的压力,进而减轻数据库服务器的压力。

前方的路

恭喜你的网站已经启动了!现在你需要确保它能够持续稳定的运行。在这个战争中你需要与下列事物做斗争:

  • 你的用户(流量增长)
  • 你的软件(一点点腐烂)
  • 你(错误的决定)

第一个没啥好惊讶的,最后两个可能会让你惊讶同时也是让你网站宕机的一些因素。

流量增长

正常情况下你的网站不应该在技术栈的任何层次占用 100% 的资源,一旦出现超过 70%(CPU,内存,磁盘等等) 的资源占用,那就说明某些地方需要优化了或者增加更多的资源。当流量突增的时候如果你有额外的资源的话就可以很好 的应对。

有些时候的流量激增可能是商业上进行了某些吸引用户的活动,确保开发者知道这些商业活动,以便应对激增的流量。 一个好的主意是像刚启动时那样,大家在桌子上一起讨论分享这些商业信息。

一点点腐烂

由于高性能网站使用了很多不同的服务,所以需要保持这些服务打上了最新的安全补丁。 “如果没出现问题,就不要去修复它”是个非常危险的准则。

跳过几个小版本是没什么问题的,但是不要落下太远,不然的话到时就会失去升级动力。 定期小步升级你的依赖(你的操作系统,主要的服务以及 Python 库)。

作者的小贴士:

当 review 升级的时候,我们通常不会使用最新的版本,一般最新版本也意味着有新的 bug ,我想 你不希望当小白鼠吧。给新版本几个月的成熟期。 升级到第一个稳定的版本或者你已经确保这个版本没什么大的问题了。

错误的决定

意外的刷新了缓存

在流量特别高的时候重启缓存或 web 加速器可能会击垮你的网站。这个问题叫做 dog-piling/cache stampede 所以尽量使用 reload 的方式来更新服务。对于使用 memcached/redis 的缓存可以通过给不同的缓存定义不同的 KEY_PREFIX 的方式来实现逐个清理缓存(通过 VERSION)而不是一下子删除所有缓存的功能。 如果一定要重启的话,进行选择在流量低的时候重启服务。

数据库锁表

数据库锁会临时阻塞主写操作,如果这个操作特别长的话就会成为一个问题。两个比较常见的长时间锁表的场景是: schema migration 和备份。

在开发的时候, South 和内置的 migration 可以很方便的应用 Model 更改, 但是在生成环境下, migrate 操作可能会导致长时间的锁表现象,这个对你的用户来说就是个糟糕的消息了。 对于 ADD COLUMN 操作,如果你使用的是 MySQL 数据库的话你需要留意一下这个,但是 PostgreSQL 很少会出现这个问题。

无论你使用哪种数据库,migrations 都需要被 review 并且使用最近的线上数据的副本数据测试过后才能在生产环境使用。

备份是另一个会导致长时间锁住数据库的操作。最好是在一个只读的 replica 上进行备份操作。

大量的缓存过期

跟刷新缓存差不多糟糕的事情就是有大量的缓存过期,这将导致数据库压力倍增。 如果你不是很确定的话,应该选择在流量比较低的时候进行部署操作,避免击垮你的站点。

昂贵的 admin 视图

构建一个未优化的 admin 视图会导致上千的数据库查询。 如果你正在使用一个查询缓存比如 johnny-cache, 每一次在 admin 中保存都将 导致与所在表相关的缓存都将失效。所以 admin 视图也需要像普通视图那样进行优化。

昂贵的后台任务

未优化,数据库依赖的任务会导致非预期的负载负担。所有应该像优化视图一样优化你的后台任务。

逐渐恶化

随着新功能的增加,网站的性能也在接受不同的考验,你需要随时关注性能问题。

每次发布新版本的时候都关注一下性能的变化,如果响应时间变长了或者负载变高了, 立马去解决它。这样就不会出现在几个月的提交过去后再去查找问题所在的情况。

complexity creep

如果你按照前面所说的步骤做了的话,你已经做的非常好了。 随着你的网站的成长你可能会遇到各种各样的新问题,你可以很容易的就构建自己 独有的解决方法。 构建你自己的工具是件很有乐趣的事情,但是 not invented here 对于长时间运行 的站点是非常危险的。你最好去学习如何让 Varnish 更高效而不是丢弃它转而使用你自己的工具。 这个决定衍生的代价是非常巨大的:

  • 训练新的开发者需要更高的花费。你可以找到一名拥有使用一个比如 Varnish 这种服务经验的开发者, 但是如果使用你自定义的方案的话,你需要训练每一位在门外徘徊的开发者。
  • 开发低级别的基础设施工具将会导致开发时间远离了你的核心产品。使用一个支持良好的开源服务, 你的团队的开发者的效率会很高效。
  • 写你自己的软件代码不是一锤子买卖。所有的软件都需要不断的开发,测试,文档,等等。

最后的想法

现在你可以在看看那个老问题“Django doesn't scale”,你是怎么认为的呢? 如果只用 manage.py runserver,使用 SQLite 在一个非常小的云服务器上跑 当然不会很快。

让我们回到 2012 年,当 Instagram 只有3个的 Django 团队却支撑起了 1千4百多万的用户的时候, 他们在博客上是 这么说的

我们选择一个系统的核心宗旨是:

  • 保持非常简单
  • 不要重复造轮子
  • 可能的话,使用久经考验的成熟的技术

我们非常同意。因此,在你继续你的 Django 旅程的时候,不要忘了你在这里学到的东西。 简单是指导原则。


Comments