• puma配置的worker、线程数其实是不能太大的。worker数等于核心数,最大线程数等于4倍于核心数就已经很多了。如果并发比较均匀,最小和最大线程数可以保持一致。虽然线程数增加是有利于几乎都在等阻塞IO的应用,但是内存会受不了,等完阻塞IO的GIL竞争也会很严重。所以一般worker数 = 核心数。保守一点,例如机器还跑数据库之类的,也可以核心数减去1、2,留点资源给他们。最小最大线程数都锁在 核心数 * 2 (或者最小是核心数,最大是2倍核心数)会更加合适一些。头铁,对内存占用有自信的话,可以4倍。买服务器的时候都买2核4GB,不够用了,就多买一台,做负载均衡(注意国内云的内网速度)。

    其实先不提Ruby的GC有没有锅, puma是有bug可能导致内存溢出的。例如3.x http1.1 persistent连接溢出。但是代码没有严格控制风格,现在已经很乱了,找个bug很费劲。另外MRI也没有像JProfiler那么好的性能调优工具,找起来几乎靠片面的数据去直觉推断,挺麻烦的。如果真要用puma,弄个nginx在puma前面挡一下,可能可以改善一点。如果应用并发比较高,还是建议上passenger, unicorn这些有商业背景的(并发模型也很耿直的)。 虽然损失了一堆并发,但是长期运行的话,会稳一点。:)

  • 截止到现在,主要gem包对全局开启(--enable=frozen-string-literal)的支持依然不是特别好。

    建议还是使用魔法评论局部启动。可以使用rubocop帮助自动添加这个评论。以后deprecated后还能自动删除。:)

    对性能的提高主要跟GC的实现有关。如果不严谨地总结的话,对象这玩意,当然是创建得越少越好啦!尤其是字符串这种,代码逻辑里到处都在用的数据类型。不仅省内存,还省了对分配内存内核API的调用。万一有多线程,使用这种字符串的话,也不用考虑竞态条件了,因为这对象都不变的。

    如果学习过C的话,估计能更加体会到冻结字符串的好处。 :)C的数据结构里有一个叫做原子(Atom)的玩意。根据字符串内容唯一对应一块内存的话。单凭一次指针(内存地址)这样的整型比较,就能完成任意长度字符串的比较了

  • 翻得不错。 CSRF token在使用http only cookie的场景里起到了保护会话的作用。避免攻击者在别的域名下使用用户的会话发起带副作用的POST请求 如果简单总结这个模块干嘛的话:

    1. CSRF模块会给每个session生成一串随机字节,为了讨论方便,称为A。
    2. 要拿这个token的时候(例如调用form_authenticity_token),再生成另外一串随机字节,称为B。让A和B做一下做一下位异或操作,得到C。最后把B和C拼接在一起得到D。D就是返回的csrf token。由于用了B做了异或,这样每次请求里的csrf token都不一样了。
    3. 要判断浏览器发过来的token对不对时,假设发送过来的是E,这E其实就是第二步的D,把E分开得到第二步所述的B和C。再做一次异或操作,A就回来了!最后做一下比较,就得到结果啦。

    关于最后的比较(secure_compare),额外的TIP:为了防止Timing Attack这种旁道攻击,一般来说,都会对字符串做同长比较。rails会对字符串做个摘要,这样不管字符串多长,生成出来的摘要都是一样长的。这样就可以做同长比较了。

努力在国内普及ruby :)