pixiv小程序的图片服务器架构
in 默认分类 with 0 comment

pixiv小程序的图片服务器架构

in 默认分类 with 0 comment

最近接触到关于海外图片服务器国内访问提速的操作,记录一下我的过程吧,其中涉及到了nginx代理nginx重定向cloudflare的CDN服务DNS轮询

众所周知,pixiv是一个不存在(被墙)的插画网站,属于日本的一家公司。现在想从国内直接访问pixiv的图片,所以有了以下的操作。

Nginx - 代理

pixiv的图片服务器域名是i.pximg.net,但图片服务器做了防盗链措施,根据header里的Referer值判断是否合法,只有从pixiv相关的网站发出的请求才能被接受。

利用pixiv的代理可以解决这个问题,具体配置看这里:Nginx代理pixiv图片服务器配置,Nginx开启缓存后能加快访问过的资源的速度。

服务器选择国内带宽较大,且延迟较低的。最合适的应该就是阿里云或腾讯云香港地区的轻量应用服务器了,最低配置一个月24元,包含30M带宽峰值和1T流量,国内到香港的延迟一般都不会太高。
架构图如下:
架构图1

瓶颈

此时服务器瓶颈有三个:

Nginx服务器连接到pixiv服务器的速度

我用的是香港节点的服务器,pixiv服务器应该是存放在日本的。尝试在Nginx服务器上通过wget命令下载pixiv图片,非高峰期基本不超过5MB/s,一到晚上则慢得可怜,仅30多KB/s。ping到pixiv服务器的延迟大概54 ms。

wget https://i.pximg.net/img-original/img/2019/07/29/01/04/24/75962623_p0.jpg --header="Referer: https://www.pixiv.net/"

Nginx服务器的带宽

毕竟服务器只有30M带宽峰值,图片往往较大,一张原图往往有好几M大小,例如上面wget下载的原图大小为4.5M。若用户一多,达到了峰值后图片的加载会变慢。

用户到服务器的线路问题

腾讯云的轻量应用服务器,测了下对于电信运营商的网络比较友好,但到了晚上高峰期服务器的网络就会变差,即便是电信网也可能会扑街。

突破点

上述提到的三个瓶颈,第一点和第二点都找到了解决的方案。至于第三点,可能要更换线路更好的服务器了,成本较高。目前pixiv小程序还处于用爱发电状态,只能尽量节省成本,所以重点解决前两点吧~

cloudflare - CDN服务

图片属于静态数据,很适合利用CDN服务来加速,国内的云厂商大多数都有CDN服务,能对国内的用户访问进行优化。

但看了下价格,最低的应该是腾讯云的0.21元/GB,目前小程序图片每天消耗大概70GB流量,算下来一天需要额外14元的支出,小程序一天的收入也才3元,妥妥的入不敷出鸭,于是放弃。

目前国际上最有名的免费CDN服务商就是cloudflare了,如果是国外的业务很适合使用这个,但听说国内访问的话反而成了“CDN减速”。但白嫖怪此时跃跃欲试。

接入cloudflare

前往官网cloudflare,将自己的域名托管在cloudflare,按照流程配置后,需要去域名商控制台,将DNS服务器设置为cloudflare提供的,并前往cloudflare添加解析,这样就完成了接入。
此时架构图为:
架构图2

如果是以前的架构,图片加载速度与并发相关,若访问用户少,则加载快,若访问用户多,则加载慢,甚至可能无法加载图片。

如今则是无论用户多少都能够提供服务,因为请求的目标是cloudflare,仅在CDN节点上没缓存的时候才会回源,带宽峰值没了限制,但缺点也是稳定的慢,毕竟cloudflare的CDN在国内是没有节点的。

给CDN前再套一层

搭好了cloudflare的CDN后,突发奇想,既然我最开始的方案Nginx代理pixiv服务器比较慢,那是不是可以代理cloudflare的CDN呢?
于是尝试用Nginx服务器执行命令:wget cloudflare域名/图片uri,wow发现居然速度可以飙到18MB/s。

注1:代理cloudflare相比代理pixiv还需要加个proxy_ssl_server_name on;的配置,否则会报502之类的错误。
注2:还需要加proxy_ignore_headers Set-Cookie Cache-Control;,否则nginx不会缓存。

于是架构进阶为:
架构图3

这里的Nginx服务器是同一台,只不过配置了两个不同的域名,域名A对用户开放,域名B是托管在cloudflard有CDN的域名。

实际上这幅图和最开始的架构很像,域名A后面的所有部分都可以当成一个整体,也就说只要访问过一次某张图片,下次再访问这张服务器因为缓存所以能直接从cloudflare取到了。相比之下直接代理pixiv服务器速度不超过5MB/s,而现在这种架构代理能跑到18MB/s。

DNS轮询或Nginx重定向

原本接入cloudflare的CDN是为了解决Nginx服务器的带宽瓶颈,但现在的套娃操作却成了解决Nginx服务器连接到pixiv服务器的速度的问题。

所以现在的瓶颈还在与Nginx服务器30M带宽上。但轻量应用服务器最高带宽也就30M无法升级配置,所以大概只能加机器了。

DNS轮询

最低所需资源:域名2个,服务器2个。

这种办法可以很容易扩展图片服务器,只需要将Nginx配置文件拷贝到另一台,再分别到A、B域名服务商添加新服务器的解析即可。

也就是A解析记录为2个服务器ip,B的解析记录也是为2个服务器的ip。
架构图为:
架构图4

但这种方式存在缺点,因为DNS解析也是有缓存的,倘若其中一个服务器挂了,则需要将解析删去。但由于缓存的原因,域名的解析在删掉后的一段时间内还是会解析到不可用的服务器ip去。

Nginx重定向

最低所需资源:域名4个,服务器3个。

重定向的话除了需要新增一个图片服务器,还需要一个服务器单独做Nginx重定向。用Nginx重定向的方法扩容或者删减都很方便,即时生效。

架构图为:
未命名文件 (15).jpg

服务器A配置大概如下,先内部做负载均衡再重定向,重定向需要用302(临时重定向)而不是301(永久重定向):

    # 负载均衡,用uri_hash策略能提高缓存命中率
    # 负载均衡到内部端口,再由端口重定向域名
    upstream pixivs {
        hash $request_uri;
        server 127.0.0.1:8081;
        server 127.0.0.1:8082;
    }
    # 对外域名
    server {
        listen       80;
        server_name  域名A;
        location / {
            proxy_pass http://pixivs;
        }
    }
    # 重定向到域名B
    server {
        listen       8082;
        server_name  localhost;
        location / {
            rewrite ^/(.*) https://域名B/$1 redirect;
        }
    }
    # 重定向到域名C
    server {
        listen       8081;
        server_name  localhost;
        location / {
            rewrite ^/(.*) https://域名C/$1 redirect;
        }
    }

关于服务器D,如果有条件可以买台日本地域的服务器,回源pixiv服务器速度较快。若无条件可以搭建在B或者C上。毕竟仅在未访问过的情况下才会到这一步。

缺点就是这个Nginx重定向服务器可能会成为新的瓶颈(如果到那时可以用DNS轮询 + Nginx重定向),并且客户端请求的话,需要请求两次才能拿到图片,一次是访问Nginx重定向服务器,一次是去真正的服务器取图片。

最后

Nginx重定向的方式会比较好控制,随时都可以进行增减,并且可以根据策略负载均衡。DNS配置起来相对简单,成本也低一些。如果有条件的话优先考虑Nginx重定向的方式,毕竟DNS生效时间非常不可控。

我尝试用了DNS轮询的方式,后来撤掉了一个服务器,一天之后还有部分请求会进入到撤走的服务器里,并且DNS轮询的方式并不能将流量完全均匀分配在两台服务器,因为客户端访问DNS解析过一次域名后就会缓存,所以对于用户来说只进一台服务器。

鉴于上述,我换成了Nginx重定向的方案,好处是即时生效。对于静态文件服务器,缓存十分重要,我们可以配合nginx的uri_hash负载均衡策略,让A图片去A服务器,B图片去B服务器。若是DNS轮询的方式则A图片会从两台服务器随机获取,降低了缓存命中率。

2020-09-28日更新

前前后后折腾了一周多,结果一到晚上服务器炸的真是离谱。这种配置白天图片加载速度能起飞,一到晚上还不如直连Cloudflare。

另外到了晚上,回源pixiv图片服务器也是慢的可怜,竟然不超过100KB/s,白天好歹还能上5MB/s。轻量服务器毕竟便宜,基本上只能靠超售赚钱了。

我放弃了,大概只有钞能力才能解决服务器线路的问题了。。。

2020-10-24日更新

最终的方案是让用户直连cloudflare,但做了CNAME接入,自选ip选了个香港地区的IP,ping的延迟大概是160ms,还算是能接受吧。至少这样即便再多用户也不用担心卡(虽然用户少的时候也不会变快)。

Responses