Avatar Cache:做最好的头像缓存

Author Avatar
黎明余光 8月17日
  • 在其它设备中阅读本文章

Avatar Cache 的历史与前身

2017.10.28,Avatar Cache 第一版公开,基于 已经停止维护的 XPHP 框架和 File-based 缓存开发,使用 fastcgi_finish_request() 在 PHP-FPM 下实现伪异步更新缓存。就我个人感觉,这种更新方式应该比其他的要好很多,说的就是某些亿年不更新、缓存用到死的镜像。

第一版有很多问题,比如 MIME 不正确、缓存更新时间的判断写反了(跑),再加上面向过程的大量冗余代码,难以继续维护。因此,2018.3.5 在原版上稍做优化,起码不会把所有操作扔进 Controller 里了,大体上属于能用的级别。

2018.6.19 完全地基于 XPHP 重构了,分离 Meta 和 Data,将参数对应的 Meta 存储在 MySQL 中,再通过 key 查找存储在文件中的数据,这样数据就可以包含更多额外内容,比如 MIME 之类,Internet Explorer 就不会因为 MIME 不正确无法打开了。

这个版本沿用至今,基本功能都能用,也挺稳 ,除了遇到两次猪队友删服务器、删文件,之后就完全托管在我自己可控的服务器上了,SLA 不说 100%,起码 99% 是有的,折影轻梦的博客和 起始页 也一直在使用这个服务,他没报告问题的话应该说也没出什么问题。

但中途还是遇到过一次不愉快的域名更新,mixcm.cn 申请注销了备案,因此之后域名都是 avatar.dawnlab.me 了。

现在,就是今天文章的主角,新版 avatar-cache 了。

新版 Avatar Cache

Github:idawnlight/avatar-cache

高性能

这一版本为了追求最高的性能,完全放弃使用现有框架,改用 Native PHP + Swoole 编写,把所有能提高性能奇技淫巧都用上了,比如:

  • 路由组件选用 nikic/FastRoute
  • 缓存组件选用 Stash
  • 能静态化的方法就静态化
  • 能类型声明就类型声明
    • PHP 7.4 会允许变量类型声明,等正式版我会跟进的
  • 严禁阻塞行为,耗时操作全部扔异步

高灵活性与拓展性

  • 允许同时作为 PHP-FPM 和 Swoole 框架运行,且行为一致
  • IDE 友好
    • 有些地方实在是没法优化了,比如 Cache::getCache() 方法,不能预判返回哪个类型
  • 缓存组件遵循 PSR-6
  • HTTP 组件遵循 PSR-7
    • 算了,这个没法替换
  • 可扩展的组件和服务基本上都有 interface abstract class trait 之类
    • 新增一个服务直接实现 interface,可以迅速完成拓展

性能测试

在我的 PC 上跑的测试,尽量保证相对一致的测试环境。使用 Apache Bench Version 2.3 <$Revision: 1843412 $>,32 线程总计 1000 次请求,多次测试取最佳值。(注:结果和 GitHub 上的版本有出入,但均为实测值,考虑到影响因素太多,还是取最佳值合适)(再注:所有请求中,缓存均有效。)

$ ab -c 16 -n 1000 http://localhost:9501/gravatar/605f8c6c64b8fcd514a0b53c6cc3680c

Avatar Cache: Swoole Mode (WSL) (PHP 7.3.7)

Server Software:        NodeName
Server Hostname:        localhost
Server Port:            9501

Document Path:          /gravatar/605f8c6c64b8fcd514a0b53c6cc3680c
Document Length:        12931 bytes

Concurrency Level:      16
Time taken for tests:   1.070 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      13338000 bytes
HTML transferred:       12931000 bytes
Requests per second:    934.30 [#/sec] (mean)
Time per request:       17.125 [ms] (mean)
Time per request:       1.070 [ms] (mean, across all concurrent requests)
Transfer rate:          12169.67 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   0.7      1       5
Processing:     2   16   3.6     15      33
Waiting:        1    9   4.5      9      28
Total:          3   17   3.7     16      34

Percentage of the requests served within a certain time (ms)
  50%     16
  66%     18
  75%     19
  80%     20
  90%     22
  95%     24
  98%     27
  99%     29
 100%     34 (longest request)

Avatar Cache: PHP-FPM (Windows) (PHP 7.3.0)

Server Software:        NodeName
Server Hostname:        avatar.test
Server Port:            80

Document Path:          /gravatar/605f8c6c64b8fcd514a0b53c6cc3680c
Document Length:        12910 bytes

Concurrency Level:      16
Time taken for tests:   4.980 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      13312000 bytes
HTML transferred:       12910000 bytes
Requests per second:    200.81 [#/sec] (mean)
Time per request:       79.678 [ms] (mean)
Time per request:       4.980 [ms] (mean, across all concurrent requests)
Transfer rate:          2610.52 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    4   3.9      2      19
Processing:    31   75  12.2     74     116
Waiting:       21   73  12.0     72     114
Total:         32   79  12.0     77     117

Percentage of the requests served within a certain time (ms)
  50%     77
  66%     82
  75%     85
  80%     88
  90%     95
  95%    100
  98%    108
  99%    113
 100%    117 (longest request)

LoliLin/One: NodeJS v12.8.0 (Windows)

PHP + Swoole 貌似还要快一点,即使 NodeJS 这个缓存写的很轻量(

GitHub 上的版本每次请求会有详细日志输出到 stdout,严重阻塞进程影响响应时间,因此我在测试前将这些输出全部注释掉了。
不注释掉的话性能只有 PHP-FPM 的水平。

Server Software:        Node
Server Hostname:        localhost
Server Port:            3000

Document Path:          /avatar/605f8c6c64b8fcd514a0b53c6cc3680c
Document Length:        1738 bytes

Concurrency Level:      16
Time taken for tests:   1.133 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      1983000 bytes
HTML transferred:       1738000 bytes
Requests per second:    882.64 [#/sec] (mean)
Time per request:       18.127 [ms] (mean)
Time per request:       1.133 [ms] (mean, across all concurrent requests)
Transfer rate:          1709.25 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   0.6      1       4
Processing:     8   17   2.5     17      27
Waiting:        1   14   2.4     14      25
Total:         10   18   2.5     18      28

Percentage of the requests served within a certain time (ms)
  50%     18
  66%     18
  75%     19
  80%     19
  90%     20
  95%     22
  98%     25
  99%     26
 100%     28 (longest request)

本文链接:https://blog.lim-light.com/archives/brand-new-avatar-cache.html
本文采用 CC BY-NC-SA 3.0 CN 协议进行许可,阅读 相关说明