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 年的,人特老实,不像其他中介满嘴跑火车。在确定租房意向后,房东很直接的提议私单,就是我和房东直接签,然后出一半中介费给哥们作为辛苦费,这样他能拿到比提成多一倍的钱,我也能省一半中介费。我当然是愿意,不过哥们支吾半天说不行,说知道这样是来钱快,但是他不想这么干,圈子里这么做的人很多,但他不喜欢,要按原则来。当时房东还说我俩可以把他踢开直接签,这样连一半中介费我都不用出。中介哥们当时很憋屈,感觉眼圈都是红的,又很无力。房东离开后我俩单聊,他说理解,只是自己不喜欢。然后,有那么一瞬间,我决定按照正规流程来办,当然我要出全部中介费。签合同的时候才发现,这是他入行一个多月的第一单。能看出他很紧张,写字手都在抖,我不知道这第一单对他有多深的意义,也许若干年后他回想起来依然会激动?或者骂自己傻逼为什么没有直接拿钱?或者笑话有个傻逼居然答应出全部中介费?我只记得当时那一瞬间我的想法:
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 文档。记几点笔记:
- 用 OpenResty(ngx_lua) 作为前端 Nginx 代理和缓存服务器,好处是可以用
set_by_lua
计算赋值变量,原生 set 语法不够灵活。 proxy_cache_path
指定缓存文件目录,和proxy_temp_path
最好设置在同一文件分区下,缓存内容是先写在 temp_path,然后移动到 cache_path,不同文件分区会影响性能。keys_zone
命名并设置缓存的内存空间大小,要注意的是这个内存空间并不保存缓存文件,而是缓存文件的元信息(meta information),所以不必太大,根据文档 1M 大小可保存 8000 文件的元信息,可以根据缓存文件数量进行设置。inactive=30m
表示 30 分钟没有被访问的文件会被 cache manager 删除,max_size=500m
表示缓存目录最大限制 500M 磁盘空间。proxy_cache
指明用哪个缓存空间,proxy_cache_valid
是缓存的有效时间,可以针对不同响应状态设置不同的有效时间,比如proxy_cache_valid 404 1m;
,默认只对 200/301/302 响应进行缓存。- 缓存文件数量过多会影响 proxy_cache 性能,Nginx 在启动时 cache manager 会检查并读取缓存文件的元信息到内存,这个读取是有限制的,默认情况下 cache manager 每次读取 100 个文件的元信息,每次读取限时 200ms,间隔 50ms 进行下次读取。
- 缓存文件并不是越多越好,所以 cache_key 的设计非常关键。代理或 URL 跳转常常会添加的无用请求参数,这就会出现不同的 cache_key 保存了多份相同的缓存内容,这对缓存效果影响很大。通过 ngx_lua 可以对 URL 参数进行过滤,保证 cache_key 唯一。
table.sort(args)
对 URL 参数重排序,避免/api?page=1&count=10
/api?count=10&page=1
生成两份缓存的情况。$upstream_cache_status
可以获取缓存状态,包括HIT/BYPASS/MISS/EXPIRED
,可以记录到 access_log 和 response header,用以计算缓存命中率。proxy_no_cache
如果有值且不为 ‘0’,该请求的 response 就不会生成缓存。proxy_cache_bypass
如有有值且不为 ‘0’,该请求会忽略缓存。- 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,于是就有了这次迁移。
- 通读 Jekyll 文档,了解新功能特性。
- 本地安装
gem install github-pages
,模拟 GitHub Pages 环境测试。 - 修改
permalink: /blog/:year/:month/:day/:title
保持链接不变。 - 设置 markdown 解析器为
markdown: redcarpet
,支持 GFM。 - 分页设置
paginate: 10 paginate_path: "blog/page/:num"
,保持兼容。 - 配置 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 简单明了),可以在一些项目上试试手。
慎独,又是一个人的一个月,过于宅的日子对自己心态很不好,所以这两周末有意识的让自己出去走走,做一些调整。
心态不好一方面是一个人,一方面是家里,我们这一代人和父母一辈在育儿上确实有很多分歧,尽管目标都一致。得感谢小姨一直在中间劝我妈,现在问题已经化解很多。
看着兄弟们升职买房结婚安定,加上家里、小孩的因素,北漂的不安定很让人心烦,这也是自己心态不好的主要原因,买房已经开始考虑并提上日程,希望自己能处理好这些事情。
Vim Golang 开发环境: vim-go
安装 Golang 并设置 $GOPATH
:
export GOPATH="$HOME"
export PATH="$PATH:$GOPATH/bin"
Golang 官方提供了 Vim 开发工具 $GOROOT/misc/vim
,但功能很弱,所以有很多第三方的辅助开发应用:
这几个是独立的应用,配套相应的 Vim 插件,单独安装很是繁琐。而 vim-go 是一整套的 Golang Vim 开发配置,安装插件后通过 GoInstallBinaries
安装 gocode
, godef
, goimports
, gotags
, golint
, oracle
, errcheck
以及相应的 Vim 插件、配色、代码块,非常方便。
Plugin 'fatih/vim-go'
安装,默认代码补全引擎是 Ultisnips,修改为 neosnippet let g:go_snippet_engine = "neosnippet"
。
我的 vimrc.