@ruohanc 我非常想帮助别人,但你这样的说法真让人寒心。
如果你觉得我的位置太高,会不会因为你的位置太低?如果你觉得每个人都在教育我,会不会因为你太敏感了,为不存在的事情替我着急?如果你觉得我的反应有些偏激,会不会因为你承受别人指出(别人的)错误的压力阀太低了?
ETag 应该前置校验,这样除了减少网络传输外,(基本)不会产生性能下降。另外,你不要偷换概念,这不是“这点”,不进行前置校验,绝不会是“这点”。
当然,如果我设计一个 WebFrame,应该也会引入类似Rack::ETag
的中间件,作为通用组件,它的局限性是可以被容忍的。
对于动态请求来说,etag 和 last modified 都是需要后置校验
@ruohanc 我非常希望你也能明白,@quakewang 类似的说法是错误的,这并不是基础知识,而是错误的知识。
@quakewang 进行分享,这是好的事情,分享的意义,并不单纯帮助了别人,也给了别人帮助自己的机会。
另外,需要请教下的:实际上 last_modified 就是字符串,并非一定要时间戳或者其它什么格式,因为 HTTP 处理的是超文本;真有限制,也是各种 WebFrame 内建的限制。我这样的理解是不是错误的?
貌似没有人能帮助我,为了回复 @ruohanc 你的这个帖子,我仔细翻阅了http://www.ietf.org/rfc/rfc2616.txt
的协议,这个论述,我估计会在某些浏览器中不支持。好吧,也算你帮助了我。
我已经到了俯首而为孺子牛的年纪,所以,并不太容易有类似生气的过激反应,倒是高中时,同学跑过来问问题,然后辅导之,然后她开心地说自己就应该不耻下问
,这不是耍流氓么……
我在文前的反问,并非 troll 行为,只是当年自己跟下属说类似的话时,那时没有人告诉我,这样是错的。
@aptx4869 测试的前提比结果更重要些,比如确保 status 回来的都是 200,确保 GZip 压缩的 level 是一致的,比如 text 类型的 js/css/html 几个分开比对一下;另外,结果还是感觉不科学,再看看 Rails 对 Gzip 的实现是纯 Ruby 还是用了 C。如果,结果还是不科学(这就真的太不科学了),哈哈,欢迎来笑话我。
一说真话,就遭人嫌,继续感受下吧。
nginx 只用 gzip_static on 发送静态资源就够啦,绝大部分动态内容都是不压缩的比较快
gzip_static 是预压缩,就是 Nginx 会检测.gz 的对应已经压缩好的文件是否存在……
gzip on 的话也可以配置哪些内容 gzip 哪些不 gzip
这个是必须要配置的。
像压缩过的 js, png 图片,gzip 对瘦身效果很不明显,但是耗费很多服务器和客户端的 CPU, 还是不 gzip 的好
压缩过的 js
如果是指自己下面这句话的,呃,有效果才奇怪…… png 图片怎么敢用 GZip?不,不,没有特殊情况下,text 类的都应该开启 GZip,它的效率还是很高的。
用 gzip_static 还有个好处:在编译 asset 时就比较压缩效果,压缩比少于一定量就不 gzip
唉,Nginx 有个gzip_min_length
参数可以设置……
还是那句话,希望对大家有所帮助。 但坦率地说,有点后悔参合进来。
Rack::ETag 不是累赘,对于非性能瓶颈的请求,没必要手工加 fresh_when/stale 等判断,就算多生成一次 response body,浪费一些服务器资源也无所谓,客户端还是能够享受到 304 带来的好处.
是如此,我当然知道……
相信看到这里的朋友对 304 有了更好的理解。
如果真要做优化,这种通用的 MiddleWare,确实非常鸡肋。我保留这个看法,因为这是正确的。
但多数的产品用通用的就可以了,因为性能问题不会如此突出;如果要针对自己产品做类似Rack::ETag
的处理,就需要确定自己的规则,当然,代码并不会增加太多,估计就 10 行内的事情。
好了,我该说的都说完了。希望对诸位有所帮助。
不仅仅是 markdown 转 html,就是单纯的 rails helper 生成 html,或者复杂页面 view template 渲染,也需要花费 10ms 级别的时间(没办法,ruby 不够快),对于访问量大的页面,片段缓存能够节约掉这部分时间也是相当可观的
评论可以修改的,所以刚才没有看到这段。其它方式生成 HTML,这个怎么做缓存都不过分,脚本语言,没有办法的;我特指 Markdown 转 HTML,这个真的没有必要。
对于动态请求来说,etag 和 last modified 都是需要后置校验,没办法提前到 nginx 这层面校验.我不选择用 last modified 是因为 etag 更加灵活,可以用更新时间+其他参数,比如我文章中提到过的当前用户 id,评论数等来做.
前置校验,不是指放在 Nginx 中处理,而是指 request 过来的时候,先校验头部信息,如果 match cache 的,直接 status=304,并且返回空内容;而不需要再继续运算完整的 response
我总感觉有些奇怪的,是动态请求来说
这样的前提把自己画地为牢了?
我不选择用 last modified 是因为 etag 更加灵活
另外,需要请教下的:实际上 last_modified 就是字符串,并非一定要时间戳或者其它什么格式,因为 HTTP 处理的是超文本;真有限制,也是各种 WebFrame 内建的限制。我这样的理解是不是错误的?
我始终觉得,因为 ETag 跑去改 Nginx 的源码,太草率了。当然,实际自己遇到这样的问题,可能也会类似的做法,dirty but quick. 但当做知识进行分享,感觉不是很好。
我可能表达不够清楚,ETag 本身的作用是节省带宽(就是下载时间),但是校验 ETag 如果是这种后置的算法,那这个就很难算上优化的手段。
但是很多人会有这样的误解(304意味着)直接用客户端的缓存,而无需在服务器端再生成一次内容
,程序没有特殊处理,不是这样的。
@quakewang 所以我才说在知道可以用last_modified的前提下,实在没有必要去修改Nginx源码;再则,Nginx处理Gzip的性能高很多,不是么?
in 查询一般都是主键查询,或者是有 index,不会有全表查询问题.
这个你是对的,不过建议还是说明下,因为 ORM 的调用还是很容易进入子查询的逻辑,这个时候,对于那些还没有完全理解索引概念的朋友们,优化优化,结果越来越糟。
@huacnlee @quakewang 提个建议,应该能看出我并不是一名新手或者不知所以的人,所以,一些基本的概念,不用说明的。
楼主是在传播错误的知识,为什么没有人指出呢?
(304)直接用客户端的缓存,而无需在服务器端再生成一次内容。
这个表述不严谨,如程序内没有特殊处理,照样会生成一次内容(楼主自己后面也举了用例,但未说明原因),只是 status=304 而非 200,这个区别。而 HTTP 在传输的时候,是先给状态,再传内容的,304 的则是空内容,从而节约网络传输的时间。
Gzip 之后,etag 就变了,这个 Nginx 处理得是复合逻辑的,并且在知道可以用last_modified
的前提下,实在没有必要去修改 Nginx 源码;再则,Nginx 处理 Gzip 的性能高很多,不是么?
自动 etag 能够节省的只是客户端时间,服务器端还是一样会执行所有的代码
如果 etag 是这样被中间件处理的,实是累赘至极,它或许为某些特殊场景设计的吧,如果通用场景这样使用,实际上必然带来性能的下降。
HTTP 本身的协议允许各种 Headers 的定制,etag 和 last_modified 能起到缓存校验的作用,是因为它们属于默认的 Headers,浏览器基本上都是支持的。
节约了生成 markdown 语法转换到 html 时间,这里用文章最后更新时间作为 cache key 的一部分
Markdown 转 HTML,这种结果接近固定值的逻辑,为什么要用 cache?
另外数据查询缓存
这段,传统的 SQL,如果用 IN 查询,会不会有潜在的全表扫描的可能?
个人意见:ORM 的缓存应该信任 ORM 本身,因为本来比较难处理,通过外部调用的缓存颗粒度控制,可控性反倒更高。比如下面所言,在多 Unicorn 同时运行的前提下,如果请求周期
过长(不知道你们实际场景下是多久),那么数据的不一致性会十分离谱... 如果请求周期是偏短的,那应该是 ORM 设计的一个标配,短时缓存,实在不算是应用场景下优化的手段。
rails 内置了 query cache( https://github.com/rails/rails/blob/master/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb ),在同一个请求周期内,如果没有 update/delete/insert 的操作,会对相同的 sql 查询进行缓存,如果文章类别都是相同的话,真正去查询数据库只会有 1 次。