Tweet

Make every detail perfect and limit the number of details to perfect.

via Jack

What Apple has done

Zsh Shared History

You can share every commands between all terminals with Zsh shared history. In your .zshrc:

# enable shared history
setopt inc_append_history
setopt share_history

# disable shared history
unsetopt inc_append_history
unsetopt share_history

Two Hard Things

There are only two hard things in Computer Science: cache invalidation and naming things. – Phil Karlton

Monthly Review 2014-09

选择

月初一个项目计划是客户端+服务端都由我负责,项目进行中我把客户端交了出去,保证进度是一个原因,毕竟是完全新的业务功能,服务端要做东西还挺多,主要原因是面对客户端开发,忽然手生,表现在这个东西我知道,着手代码的时候要愣一愣。

算下来有一年多没有 系统 的写 iOS,正好 iOS 7 一代。这一年 iDev 相关的学习一直没落下,但缺乏实际项目锻炼,解决问题的思路还有,具体到某一个技术点,比如写一个毛玻璃模糊效果,就要愣一下,需要查文档了。

出现这种情况也在意料之中,虽说要做全栈开发,终究是要有些侧重,目前还是以服务端为主。服务端开发现在主要是业务驱动,技术长进有限,最近在看 nsq,争取在业务和技术上都能有进步。客户端方面还是技术关注+学习,具体开发上给我一点时间还是有信心回到之前的熟练水平 :D


最后还是选择把六六留在老家。走这一步我和老婆俩人没少哭,就现阶段条件,执意带六六到北京的结果可能更糟,北京的居住条件六六和妈是否适应,爸一个人在家的生活,妹妹也还没毕业,就算狠狠心带过来也不能长久,这些都让人头大。六六在家爸妈肯定能照顾好,就是想孩子受不了,尤其是大了越来越好玩,真心舍不得。每个月多往家跑跑吧。

六六健康成长。

租房小事

因为自己的犹豫,错过了一套条件非常不错的房子。房东同时把房子挂在链家和我爱我家,链家带我看房的时候我在想看看别的房子再说,等一天应该没问题,结果就被我爱我家出手。所以说:你越担心某种情况发生,那么它往往就是会发生,墨菲定律:

Anything that can possibly go wrong, does. via

这事对我来说是个教训,做事太瞻前顾后,不够果断。不过我想记的不是这件事,是下面这件,不知道我做的是对是错还是很傻逼的事。

带我看房的中介哥们,90 年的,人特老实,不像其他中介满嘴跑火车。在确定租房意向后,房东很直接的提议私单,就是我和房东直接签,然后出一半中介费给哥们作为辛苦费,这样他能拿到比提成多一倍的钱,我也能省一半中介费。我当然是愿意,不过哥们支吾半天说不行,说知道这样是来钱快,但是他不想这么干,圈子里这么做的人很多,但他不喜欢,要按原则来。当时房东还说我俩可以把他踢开直接签,这样连一半中介费我都不用出。中介哥们当时很憋屈,感觉眼圈都是红的,又很无力。房东离开后我俩单聊,他说理解,只是自己不喜欢。然后,有那么一瞬间,我决定按照正规流程来办,当然我要出全部中介费。签合同的时候才发现,这是他入行一个多月的第一单。能看出他很紧张,写字手都在抖,我不知道这第一单对他有多深的意义,也许若干年后他回想起来依然会激动?或者骂自己傻逼为什么没有直接拿钱?或者笑话有个傻逼居然答应出全部中介费?我只记得当时那一瞬间我的想法:

不要做让自己讨厌自己的事情。 1 2

Monthly Review 2014-08

工作上把一个去年就想过的设计码成并上线,目前状况良好,说明当初的设计思路是没有问题的。之所以拖了这么久是因为项目时间比较紧(是我比较懒),最主要的原因是一直没有下狠心去重构。这部分功能运行正常,可能在某些情况下会有性能问题,但绝大数情况下完全不用担心性能,而新的设计和之前的实现不同,作为一个线上服务首先要考虑的是服务的稳定性,其次是新设计的兼容性,所以一直拖到现在。现在回头看开发要有点魄力,有时候自己过于小心了。

服务端开发的架构设计很重要,前期要多做思考工作,不能上来就去代码,要考虑可能出现的功能需求,思考性能瓶颈,有了好的设计再去代码效率也会更好。

生活上给自己买了一份商业保险,30年寿险,是自己对家庭的责任。核保的时候因为 BMI 超标,每年保费多了 150,体重又一次打击了我,减肥正式开始,从 19 号开始每天晚上锻炼,根据 Nike+ Running 统计已经 66 公里,继续坚持。

由于工作原因老婆打算提前回北京,这几天抽空一直在看房子,打算整租一套,不再合租,不管六六来不来北京。以前老感觉整租花钱多,将就一下也就过了,不要太过于奢侈。现在看对我们自己太辛苦了,自己都过不好拿什么承担其他责任。老婆回去这两三个月,每天也不做饭,周末都在单间里窝着,就算出去转转也是一个人,没人说话,行尸走肉一般,再这样下去怀疑自己就要抑郁症了。

要好好的对待自己,好好生活,好好工作。

Nginx proxy_cache

Nginx proxy_cache 可以将后端动态请求的返回内容进行缓存,原理是 URL 作为 cache_key,将内容缓存到磁盘,新请求符合缓存规则的话直接读取缓存内容返回。

proxy_cache_path /tmp/ngx_cache/proxy_cache_dir levels=1:2 keys_zone=ngx_cache:10m inactive=30m max_size=500m;
proxy_temp_path  /tmp/ngx_cache/proxy_temp_dir;

server {
    proxy_cache ngx_cache;
    proxy_cache_valid 10m;
    add_header  Nginx-Cache "$upstream_cache_status";

    set $no_cache '';
    set_by_lua $cache_key "
        local no_cache = false
        if ngx.var.http_cookie and string.find(ngx.var.http_cookie, 'user') then
            # 带 cookie 的请求(比如登录用户)忽略缓存
            no_cache = true
        end

        if ngx.var.uri == '/api/test' then
              #某些 URL 的请求强制缓存,不管是否有 cookie
            no_cache = false
        end

        if no_cache then
            #确定忽略缓存就不再计算 cache_key
            ngx.var.no_cache = 'true'

            return ngx.var.uri
        end

        local uri_args = ngx.req.get_uri_args()
        local args = {}
        for k, v in pairs(uri_args) do
            if k and v and type(v) == 'string' then
                if k == 'count' or k == 'sort' or k == 'page' then
                    #过滤掉非法请求参数
                    args[#args+1] = k .. '=' .. v
                end
            end
        end

        if #args > 0 then
            table.sort(args)
            return ngx.var.uri .. '?' .. table.concat(args, '&')
        else
            return ngx.var.uri
        end
    ";

    proxy_cache_key $cache_key;
    proxy_no_cache $no_cache;
    proxy_cache_bypass $no_cache;

    location / {
         proxy_pass http://localhost:8080;
    }
}

配置 proxy_cache 很简单,建议先通读 NGINX Content Caching 文档。记几点笔记:

  1. 用 OpenResty(ngx_lua) 作为前端 Nginx 代理和缓存服务器,好处是可以用 set_by_lua 计算赋值变量,原生 set 语法不够灵活。
  2. proxy_cache_path 指定缓存文件目录,和 proxy_temp_path 最好设置在同一文件分区下,缓存内容是先写在 temp_path,然后移动到 cache_path,不同文件分区会影响性能。
  3. keys_zone 命名并设置缓存的内存空间大小,要注意的是这个内存空间并不保存缓存文件,而是缓存文件的元信息(meta information),所以不必太大,根据文档 1M 大小可保存 8000 文件的元信息,可以根据缓存文件数量进行设置。
  4. inactive=30m 表示 30 分钟没有被访问的文件会被 cache manager 删除,max_size=500m 表示缓存目录最大限制 500M 磁盘空间。
  5. proxy_cache 指明用哪个缓存空间,proxy_cache_valid 是缓存的有效时间,可以针对不同响应状态设置不同的有效时间,比如 proxy_cache_valid 404 1m;,默认只对 200/301/302 响应进行缓存。
  6. 缓存文件数量过多会影响 proxy_cache 性能,Nginx 在启动时 cache manager 会检查并读取缓存文件的元信息到内存,这个读取是有限制的,默认情况下 cache manager 每次读取 100 个文件的元信息,每次读取限时 200ms,间隔 50ms 进行下次读取。
  7. 缓存文件并不是越多越好,所以 cache_key 的设计非常关键。代理或 URL 跳转常常会添加的无用请求参数,这就会出现不同的 cache_key 保存了多份相同的缓存内容,这对缓存效果影响很大。通过 ngx_lua 可以对 URL 参数进行过滤,保证 cache_key 唯一。
  8. table.sort(args) 对 URL 参数重排序,避免 /api?page=1&count=10 /api?count=10&page=1 生成两份缓存的情况。
  9. $upstream_cache_status 可以获取缓存状态,包括 HIT/BYPASS/MISS/EXPIRED,可以记录到 access_log 和 response header,用以计算缓存命中率。
  10. proxy_no_cache 如果有值且不为 ‘0',该请求的 response 就不会生成缓存。
  11. proxy_cache_bypass 如有有值且不为 '0',该请求会忽略缓存。
  12. proxy_cache 不支持手动清除缓存,可以通过第三方模块 ngx_cache_purge 来清除指定 URL 的缓存。

proxy_cache 非常的简单高效,合理使用可以有效的减轻后端服务压力,提升服务访问速度。

Octopress to Jekyll

周末花时间把 blog 从 Octopress 2 迁移到 Jekyll

Octopress 是个非常好的 Jekyll-blog 解决方案,尤其是在 Jekyll 0.x 时代,Octopress 有不错的模版,丰富的扩展功能,缺点就是麻烦,需要在本地生成页面。

Jekyll 在过去一年开发迭代非常快,大量的新功能新特性加入让 Octopress 显得不那么必要。GitHub Pages 最近也升级支持 Jekyll 2.2,于是就有了这次迁移。

  1. 通读 Jekyll 文档,了解新功能特性。
  2. 本地安装 gem install github-pages,模拟 GitHub Pages 环境测试。
  3. 修改 permalink: /blog/:year/:month/:day/:title 保持链接不变。
  4. 设置 markdown 解析器为 markdown: redcarpet,支持 GFM。
  5. 分页设置 paginate: 10 paginate_path: "blog/page/:num",保持兼容。
  6. 配置 Google Analytics,Webmaster Tools 等。

测试没问题推送到 GitHub 即可。

Octopress 3 也改变策略,不再那么复杂,只是对 Jekyll 操作进行二次封装,方便使用。目前来看封装的功能都不太需要,一个简单的 Rakefile 就够了。

Monthly Review 2014-07

从这个月开始会在月底做一次月总结,其实最主要的目的是强迫自己每个月写点什么。

写自己,写给自己,写作技能上力图为读者负责,写作态度上只求为自己负责。

via KDr2.

工作上除了常规业务开发,调研并上线了 nginx proxy_cache,效果很是不错,为后面的访问爆发做准备。

断断续续在线看完《Go Web 编程》,对 Golang 的有了相对全面的了解,相比 OpenResty,Go 在性能上差距不大,开发效率上要比 Lua 高一些(不过 Go 的语法真心没有 Lua 简单明了),可以在一些项目上试试手。

慎独,又是一个人的一个月,过于宅的日子对自己心态很不好,所以这两周末有意识的让自己出去走走,做一些调整。

心态不好一方面是一个人,一方面是家里,我们这一代人和父母一辈在育儿上确实有很多分歧,尽管目标都一致。得感谢小姨一直在中间劝我妈,现在问题已经化解很多。

看着兄弟们升职买房结婚安定,加上家里、小孩的因素,北漂的不安定很让人心烦,这也是自己心态不好的主要原因,买房已经开始考虑并提上日程,希望自己能处理好这些事情。