今天发现虾米上收藏的音乐下架了一大堆,实在烦躁。作为虾米多年 Vip,今天我终于意识到以后可能真的很难好好听音乐了。
大体上,国内听音乐经过了这么几个阶段:
下载 -> 客户端 -> 云
下载自然不必说。客户端以酷我音乐盒为代表。到了云音乐的时代,客户端只是附属品,代表是网易/虾米/QQ。
曾经我说,音乐不好管,包子难以下手。现在看来,包子还真没怎么动音乐,但是正版化的砍刀却下来了。我不清楚唱片公司具体是怎么把版权卖给在线音乐网站的,就假设他们都愿意卖并且卖了所有专辑的版权好了。问题在于,许多版权是独家的,你网易有了 QQ 就不能有,QQ 有了虾米就不能有。音乐的分散和听音乐的需求有根本性矛盾。为什么人们从一开始上网下音乐逐渐变为使用客户端听音乐?就是因为客户端集中了音乐,让你不用到处找,同时还起了管理音乐的作用。现在呢?音乐资源的割裂让人们陷入困境——我纵然可以下载每一家的客户端,但是我不可能把三家的播放列表融合起来,难道还要在三个客户端之间来回切换?
正版化是必须的,也是不可逆的。另一方面,用户始终希望能在一个地方把音乐集中。这两者的矛盾始于版权,又不止于版权。很明显,资源的割裂来自于云音乐厂商的利益诉求。Apple Music 和 Spotify,国内的几家,谁不希望把音乐“独家”掌握在自己手里?我购买版权的时候,为什么不提出”独家“这个需求呢?站在他们的角度,独家版权才是最优决策。
这个看似无解的死局其实未必无解。一种思路是开发出更强大的 P2P 音乐软件。这种软件过去有,但是想在当下生存,实在太难,基本上是见光死,但是你在地下发展又不可持续。另一种,可能是唯一的解决方案,就是寄希望于上游的那些唱片公司。如果世界上大的唱片公司能够形成同盟,强制要求云音乐厂家在购买版权时打包购买,或是不得设置独家权限,云音乐厂家没有拒绝的权利。这件事未必不可能发生。当年各大唱片公司不也放弃了 DRM 么,因为它们希望这样能增加在线音乐的销量。结果销量的确增加了。所以,促使唱片公司行动的原因还是那个词:利益。当它们发现现有的商业模式妨碍它们赚到更多钱,自然就会采取行动。
那么现在它们会采取行动吗?我认为不会。中国的音乐正版化才刚刚开始,这个阶段唱片公司的收入是在增长的。等到正版化完成,收入放缓的那一天,它们终会发现,云音乐厂商的独家版权造成的资源割裂阻止了用户增长,到这个时候,变化才有可能发生。
现实就是如此残酷,我们可能要忍受很多年,甚至永远。 当然,如果某家云音乐厂商实现垄断也能解决这个问题,目前来看似乎不太可能。
我有一个爱好,就是去看别人的自我介绍。自我介绍存在于很多地方,比如个人网站的 About 页面,知乎的个人主页等等。粗略归类,大致分为三种。
第一种,非常详细地讲述自己愿意展现出来的方方面面。从学校,到职业,到爱好,看完之后,对这个人便有基本了解。
第二种,简短介绍。比如“高中狗”,“药丸党”,“喜欢音乐的码农”等等,展现自己的一两个方面。另有一种标签式的介绍,形如“A/B/C/D”。也有放一个链接的,比如我在知乎的介绍就是本站的网址。
第三种,没有介绍。有的人没有什么可介绍的,或者不想介绍,因此不写。此种情况也见于不少大师的个人网站——他们太有名了,以至于不需要介绍。
我们不是大师,因此需要自我介绍来让别人快速了解自己。而当需要深入了解一个人时,自我介绍就远远不够了。博客里的文章,知乎的回答,豆瓣的影评书评,Bangumi 的吐槽,这些内容为我们深入了解一个人提供了可能性。然而常见的情况却是,很多人除了个人介绍,就没了。这便是我认为羞耻的一件事:个人介绍提供的内容多于其它内容。
大概有人不理解为什么光有个人介绍在我看来是不好的,我来讲一下背后的逻辑:在我看来,既然一个人提供了自我介绍,那么就表明这个人有被互联网上其它人了解的意愿。看了个人介绍之后,如果我希望进一步了解这个人,我必然会寻找他留下的更多信息。即使这些信息因为领域不同我不能看懂,但它们的存在会让我尊重这个人。如果没有,站在他的角度,我会觉得羞耻。就好像你在家门口挂了个牌子,写者几个大字“欢迎来做客”,结果屋子里却没有家具,客人来了连坐的地方都找不到。
每个写下自我介绍的人,我敢保证,都渴望被互联网上的其它人了解。当我看到一个人给自己贴上各种标签 A/B/C/D/E/F/G 的时候,我深刻地理解,这个人希望能有同样属于 A or B or C or D or E or F or G 的同类来发现自己,同时自己也能确认对方的存在,要是能认识就更好了。但就我个人而言,我真的不会因为一个人写上了几个字就对这个人感兴趣,除非标签太抢眼比如 G 家工程师或者头像很好看并且是本人。我也非常怀疑,除我之外的其它人会如此,尤其当这个标签还不是非常小众的时候。摆明了渴望被了解,却因为提供不了更多信息而无法被了解,实在是太羞耻了。
当你无法提供内容或无意被了解的时候,最好是不写自我介绍。我尊重所有不写自我介绍的人。
最后说一种让我看到之后立刻失去兴趣的介绍:MBTI 性格测试结果的四个字母。这种介绍给我的感觉是:他是个无趣的人,除了性格,啥都没有。
去年写过一篇文章《博客性能优化》。
网站搬迁之后,需要重新优化一下。下面的测试结果都来自 webpagetest。
优化之前
对字体开启压缩
按照 FONT MIME TYPES IN NGINX 这篇文章里说的,在 Nginx 的 mime.types
文件中加入下面几行:
font/ttf ttf;
font/opentype otf;
application/font-woff woff;
application/vnd.ms-fontobject eot;
在 nginx.conf
的 gzip 类型中添加
gzip_types [...] font/ttf font/opentype application/vnd.ms-fontobject image/svg+xml;
除了 woff 文件,其它的字体都可以压缩。woff 本身就是压缩过的。
让客户端缓存静态文件
之前静态文件的配置很简单:
location /static {
alias /home/laike9m/static;
}
完全没有客户端缓存。现在加上了:
location /static {
alias /home/laike9m/static;
etag on;
expires max;
add_header Pragma public;
add_header Cache-Control "public";
access_log off;
}
对 /media
作同样配置。
特别地,我希望 css 文件不要缓存那么久,因为我经常修改 css,希望第二天就能看到效果。
location ~* ^/static/(.+\.css)$ {
alias /home/laike9m/static/$1;
etag on;
expires 1d;
add_header Pragma public;
add_header Cache-Control "public";
access_log off;
}
这个 alias
写不对很容易就 404 了。还有就是注意要把 css 的这个 location 放在 /static 之前,因为
Nginx 在正则匹配的时候是 sequential 的,即放在前面的会先匹配,而不是像前缀匹配取最长的那个。
效果
似乎加载时间反而变长了。。。不过缓存对初次加载本来就没啥用。
开启 HTTP/2
如果不是因为想尝试 HTTP/2,我也不会写这篇文章了。Nginx 从 1.9.5 版开始正式支持 HTTP/2。
首先要重新编译 Nginx,在 configure 时加入 --with-http_v2_module
。
然后安装 OpenSSL 1.0.2。官方的说法是“This is required to support the ALPN extension to TLS that our HTTP/2 implementation uses.”。
然后就发现网站没法访问了_(:3」∠)_,出现错误 ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY
。
找到了两篇相关文章:
Guide to Deploying Diffie-Hellman for TLS
Security/Server Side TLS
某论坛的一个回复里说
To use HTTP/2, you need to make sure cipher ECDHE-RSA-AES128-GCM-SHA256 is the first one in your cipher configuration.
首先按第一篇文章说的生成一个新的 "Diffie-Hellman group",作为 ssl_dhparam
的值。
openssl dhparam -out dhparams.pem 2048
然后复制了一个以 ECDHE-RSA-AES128-GCM-SHA256
为起始的值作为 ssl_ciphers
,网站就可以工作了。
效果
HTTP/2 的 Multipexing 在这张图里体现得很明显,不会开多个连接去下载静态资源了。然而速度上似乎并没有提升。
可能的后续优化
Nginx Configuration Snippets
本博客 Nginx 配置之性能篇
另外,webpagetest 给我的 First Byte Time 这一项评分是 B。官方的解释是:
The First Byte time is the time from when the user started navigating to the page until the first bit of the server response arrived. The bulk of this time is usually referred to the "back-end time" and is the amount of time the server spent building the page for the user.
评分标准
The target time is the time needed for the DNS, socket and SSL negotiations + 100ms. A single letter grade will be deducted for every 100ms beyond the target.
这一项没有达标的原因大概是后端现在什么缓存都没开。其实原来是有用 Memcached 缓存全站,但是不够令人满意。
因为我在发布文章之后的一段时间可能会编辑文章,而加缓存之后总是要很慢才能生效。目前还在寻求更好的方法。
理想状况是最新的一篇文章永远不缓存,或者是更新文章之后让缓存失效。这些都需要更精细的代码层面的控制。
这篇文章之后应该还会更新。
2015.10.20
添加 OCSP Stapling
引用 JerryQu 的说法
浏览器可能会在建立 TLS 连接时在线验证证书有效性,从而阻塞 TLS 握手,拖慢整体速度。OCSP stapling 是一种优化措施,服务端通过它可以在证书链中封装证书颁发机构的 OCSP(Online Certificate Status Protocol)响应,从而让浏览器跳过在线查询。服务端获取 OCSP 一方面更快(因为服务端一般有更好的网络环境),另一方面可以更好地缓存。
在 nginx.conf
添加上这三行就可以了:
ssl_stapling on;
ssl_stapling_verify on;
ssl_trusted_certificate /home/laike9m/files/laike9m_com/laike9m_com.chain.crt;
ssl_trusted_certificate
所需要的 pem 文件其实就是 chained crt(问了 gogetssl 员工得知)。
2015.10.30
启用 Session Ticket
Session Ticket 和 Session Cache 一样,也是简化 TLS 握手的方案。我不是很清楚在服务器都支持的情况下浏览器会选择哪一种。
修改 ssl_buffer_size
关于 ssl_buffer_size
,Nginx 文档是这么解释的:
Sets the size of the buffer used for sending data.
By default, the buffer size is 16k, which corresponds to minimal overhead when sending big responses. To minimize Time To First Byte it may be beneficial to use smaller values, for example:
ssl_buffer_size 4k;
然而到底设成多少比较好,网上找不到相关的说明/测试。在 Is TLS fast yet 里 Ilya Grigorik 把这个值设成了 1400:
ssl_buffer_size 1400; # 1400 bytes to fit in one MTU
然后我也学着设成了 1400。不严谨的测试结果表明,TTFB 确实减小了,但是总的 download time 增大了一点。
开启 tcp_nopush
+ tcp_nodelay
+ sendfile
sendfile on;
tcp_nopush on;
tcp_nodelay on;
这篇文章详细讲了为什么要这么配置。简单来说就是 sendfile on
启用了 sendfile(2)
这个系统调用,相比 read()
/write()
有诸多优点;tcp_nopush
和 tcp_nodelay
结合起来保证充分利用 MTU 的同时还能尽快地把数据包发出去而不等 0.2s。
2015.11.1
压缩 png/jpg
神器 tinypng.com。
减小 favicon.ico 的大小
原来的 favicon.ico 竟然有 30KB。上网一查才知道,ico 其实就是多层未压缩的 bmp。本来想用 Photoshop 编辑,但是居然打不开。安了一个插件之后能打开了,然而编辑功能简直糟糕,多图层都没法显示。好在找到一枚神器 IcoFX,花钱买了正版。
按照这篇文章讲的,删掉了 64*64,24 * 24 两个图层。保留 32 * 32 是因为 Disqus 的站点缩略图可能要用。颜色也没有换成 4bit,仍然保留 8bit 256 色,毕竟已经减到 3KB 了。
2015.12.5
参照 sendfile 官方文档加上了 aio on
:
aio can be used to pre-load data for sendfile()
然后我无意之中发现,sendfile on
和 gzip on
无法同时起作用,来自官方的《Tuning NGINX for Performance》 一文:
Note, however, that because data copied with sendfile() bypasses user space, it is not subject to the regular NGINX processing chain and filters that change content, such as gzip. When a configuration context includes both the sendfile directive and directives that activate a content-changing filter, NGINX automatically disables sendfile for that context.
因为 sendfile on
使用的是系统调用 sendfile(2)
,实现了 zero-copy,文件内根本就不会被拷贝到用户态(“bypasses user space”),因此 Nginx 无法进行压缩处理。
上网查了一下,唯一既能利用 zero-copy 又能利用 gzip 压缩的方案是启用 gzip_static
。这个功能并非开箱即用,而是要求使用者先把文件压缩好,这样 Nginx 才能找到,如果没找到,就 fall back 回普通的 gzip。因为比较麻烦,这次先不弄了。计划是添加一个 Django command 实现原来指定 gzip 压缩的那些格式的文件。几个可能有用的链接:
Gzip per request vs static gzip 比较两种 gzip 方式
Nginx Performance Tuning 对于 gzip_static 讲得比官方文档清楚
Nginx中gzip_static模块的使用 使用 gzip_static 的一些注意事项
还有把 gzip_comp_level
从 6 改成了 9,提高压缩的程度,代价是更消耗 CPU,不过感觉 CPU 用的不多,所以无所谓。