Monthly Review 2015-06

  1. 用 Angular Material 写了个管理平台,体验很赞。
  2. Gin 改写了部分接口,现在是 Python+ngx_lua+Go,目前情绪稳定。
  3. Gin 是个不错的框架,够轻量,middleware 扩展,封装适度,性能也不错。另一个是 Goji,两个都是我比较喜欢的。
  4. gorm 不错,目前项目比较简单,就直接通过 gorm 新建表结构,之前一个项目 Python+Go 都会涉及数据库,采取的策略是手动建表,ORM 只负责读写。
  5. 前两天看《非你莫属》,20岁小哥,完全没有互联网从业经验,就因为看现在 O2O 火了,自以为有很多 ideas,要转投移动互联网,应聘产品经理。PM 就是这么被毁的啊。
  6. 6月24日,六六一岁了。

Angular Material

又尝试了点新东西,Angular Material,写了一个的管理后台。

  1. Angular Material 是基于 Flexbox 做布局,在此基础上添加了 layout HTML 属性,写起来非常清爽:layout="row" 横向,layout="column" 纵向。
  2. build-in directives 很丰富,一整套界面写下来,目前最欠缺一个日期时间选择器。
  3. material-start 快速上手包,完整的 Angular Material 实例。
  4. 迭代更新很快,相对来说文档更新差一步,有时候需要看 demo 源码。
  5. 自带主题支持。
  6. 体积较大,min css+js 将近 400K。

5 Years in Beijing

5 years in Beijing. 5 years in Appwill.

Monthly Review 2015-05

  1. 线上环境加上 InfluxDB 作为日志存储,可以实时查看缓存命中率,在线用户数,关键请求数量,但是还没想好日志数据的进一步挖掘,所以说技术没有转化成产品前,并没有什么卵用。
  2. InfluxDB 还是有不少坑,0.9+ 在无限 RC 中,配套工具比如 Grafana 还不支持。0.8 疑似有内存泄漏,数据量稍大的查询很慢(百万级总量,10m 粒度)。还需要一些摸索,然后转化为产品指标。
  3. 又一次写前端,完整项目,这次简化开发流程,放弃 Yeoman/Grunt/Bower 等工具,过于强大到很多功能都用不上,只用 npm 作为包管理和构建工具,npm run 完全可以满足需要。
  4. 给六六做了图片 blog,按时间顺序贴照片,时间过的真快,马上就一岁了。
  5. Google Photos 是个好产品,almost the best,存储了过去十年我几乎所有照片。

避免 rm 误操作

规避 rm -rf * 操作:

目录下新建 -i 文件, touch -- -i or touch ./-i

但是对于 rm -rf ./* 无效。

safe-rm 加持保护。

不要 alias rm='rm -i',一旦习惯后在没有 alias 的机子上很容易误伤,可以新建别名,比如 alias del='rm -i',然后习惯用 del 代替 rm.

最后,不要偷懒而滥用 root

One-Time Password

两步验证是基于 HOTP/TOTP 算法的验证方案,在登录的时候除了密码,也需要提供动态数字(一般是六位数)验证。其中 HOTP(HMAC-based One-time Password) 是计数器令牌,一定次数内有效,TOTP(Time-based One-time Password) 只是一定时间内有效。

可以用两步验证的思路做一个没有固定密码,只有动态密码的注册登录流程:

  1. 发送用户邮箱到服务器,检查邮箱对应的用户是否存在。
  2. 用户不存在,新建用户,根据邮箱生成密钥并保存,引导用户通过 Google Authenticator/Authy 等保存密钥,可以验证一次确保密钥成功保存,注册成功并登录。
  3. 用户存在,提示用户填写 Google Authenticator/Authy 生成的验证码,服务器验证是否有效。
  4. 如果用户密钥忘记或被盗,可以通过邮件进行验证,然后重新设置密钥并保存。

整个流程和手机短信验证类似,不同的是通过软件保存密钥并生成验证码,而不是手机短信获取。其中 根据邮箱生成密钥是关键,如果算法过于简单,别人知道邮箱后很容易就能猜出密钥,进而得到验证码。初步想到的算法:邮箱+时间戳,SHA/MD5/AES/RC4 等加密计算。

当然这套验证的前提条件是没有物理接触:如果服务被攻陷或拿到密钥算法,整个就完蛋。如果用户手机被拿到,自然就能随便登录。

Nginx/OpenResty 指令的执行顺序

  1. http, 可以通过 init_by_lua 加载公共函数,比如 lua-resty-core.
  2. server selection,listen,server_name.
  3. post read, ngx_realip.
  4. server rewrite, set, rewrite, return, set_by_lua.
  5. server rewrite tail, rewrite_by_lua.
  6. server access, allow, deny.
  7. server access tail, access_by_lua.
  8. server try_files.
  9. location:
    1. prefix strings 遵循 最长子串匹配原则
    2. regular expressions 遵循 先定义优先匹配原则
    3. location = {exact_url} 精准匹配
    4. location ~ {case-sensitive regex} 区分大小写
    5. location ~* {case-insensitive regex} 不区分大小写
    6. location ^~ {prefix_string_if_any} 一旦字符匹配成功,就不再正则匹配
    7. 尽量不要 if,换用 try_files
    8. -f 检测文件是否存在,-d 目录,-e 文件/目录/符号链接,-x 可执行文件
  10. location rewrite, set, rewrite, return, set_by_lua.
  11. location rewrite tail, rewrite_by_lua.
  12. preaccess, degradation, limit_zone, limit req, ngx_realip.
  13. location access, allow, deny, auth_basic.
  14. location access tail, access_by_lua.
  15. content, ngx_echo, proxy_pass, content_by_lua.
    1. 请求具体处理阶段,只能有一个 内容处理程序(content handler)
    2. 多个 echo 可以共存,因为同属于 ngx_echo 模块,但 ngx_lua 限制只能有一个 content_by_lua.
    3. ngx_echo 的 echo_before_body/echo_after_body 可以和其他模块共存
    4. 如果没有 ngx_echo, proxy_pass, content_lua 这些 content handler,Nginx 会根据 URL 将请求映射到静态资源服务模块,依次是 ngx_index, ngx_autoindex, ngx_static.
    5. ngx_index/ngx_autoindex 处理以 / 结尾的请求,ngx_static 正好相反。
  16. output header filter, more_set_headers 输出 Headers.
  17. output filter echo_before_body, echo_after_body, body_filter_by_lua.
  18. log, access_log, error_log, log_by_lua.
  19. post action.

Nginx log to InfluxDB

InfluxDB 是一个支持时间序列的数据库,自带 SQL-like 查询语言,很适合用作日志存储。配合 Grafana 面板展示,非常方便。

接下来要做的就是将 Nginx 日志写入 InfluxDB。常见的方法是用 Logstash 等工具收集 access.log/error.log 通过 filter 处理后写入 InfluxDB。这种方法对服务没有任何侵入,数据完全从 log 获取,缺点就是数据源单一,nginx.log 能纪录的东西比较有限。

再一个方式就是通过 ngx_lua 的 log_by_lua。log 阶段在 content 后,请求已完成,这时候做一些处理不会拖累服务。相对 nginx.log 可以通过 ngx_lua 获取更多信息,比如 ngx.req 获取请求信息,过滤 ngx.var.uri 将同一类请求合并,ngx.var.http_cookie 读取 cookie 针对登录用户做特殊纪录等。然后通过 InfluxDB 的 HTTP API 写入存储。

需要注意的是在 log_by_lua 里不能直接用 Cosocket,需要做一些特殊处理:创建 0 延时的 ngx.timer,在 timer 回调中用 Cosocket 发请求,参考 lua-resty-logger-socket 的实现,文档里也是建议这个方法 Cosockets Not Available Everywhere.

InfluxDB 初步用下来还不错,HTTP API 方便不同服务接入,拿来做数据存储分析挺好。现在的问题是看 InfluxDB 的性能、稳定性如何。

Monthly Review 2015-04

  1. 维护开发外,一个小功能模块尝试用网页代替 native 实现。在体验可接受的前提下开发效率确实比原生要好,而且现在前端开发框架+辅助工具井喷,可以多做尝试。
  2. 前端水平 JS 刚刚够用,还不时需要 Dash 查文档,ES6 什么的不懂,CSS 是硬伤。
  3. 又十个 iOS 面试,不行,我得多写几句:
    • 遇到硬件网络转型互联网开发,似乎硬件现在日子不太好过?
    • “用大众点评 API 实现了一个美团应用”,似乎是一个培训机构的题目?
    • 现在的移动开发过火,整个行情都被抬高。基础一般,又看不到学习能力,没办法上手项目的开口就是 15K+,这钱真好赚。
    • 做产品开发首先是产品的热爱,基础差没问题,展示出学习能力,很多时候公司更愿意内部培训。
  4. 感兴趣的东西过多,同时并行的效果不好,需要有计划的去学习。
  5. 这次回去六六对爸爸的依赖更多了,基本上自己一个人带一天都没问题。
  6. 牛牛:哞…… 六六:eng……

Cache Pattern

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

Read-Through/Write-Through

App-Cache-DB 结构,App 不直接访问 DB,由缓存间接操作。读的时候先从缓存取数据,有就直接返回,没有的话由缓存负责从 DB 读取并更新到 Cache,然后返回数据。写的时候先写缓存,然后由缓存负责更新到 DB,只有 DB 更新完成才算写成功,返回操作结果。好处是缓存数据更新及时,适合读多写少,缺点就是写操作慢。

Write-Around

跳过缓存直接写数据到 DB。相比 Write-Through 避免了写数据时候对缓存数据的冲洗,缺点是缓存数据不能及时更新。

Write-Back/Write-Behind

数据写到缓存后操作立即返回结果,然后缓存系统延时+异步的将数据更新到 DB,一般配合队列处理。这种写操作是最快的,也能避免大量写数据对 DB 的压力。

Cache-Aside

App 读的时候检查数据是否在缓存中,有就返回,没有的话 App 直接读 DB 返回,同时将数据写入缓存。写操作的时候直接写入 DB,如果缓存中有对应数据,将缓存设置无效或删除,如果数据读取频繁的话也可以直接更新缓存中的数据,保证数据一致性。这种模式更多是有 App 进行数据检查,缓存只做存储。

一些参考:

  • https://msdn.microsoft.com/en-us/library/dn589799.aspx
  • http://www.computerweekly.com/feature/Write-through-write-around-write-back-Cache-explained
  • http://www.infoq.com/cn/articles/write-behind-caching/
  • http://docs.oracle.com/cd/E15357_01/coh.360/e15723/cache_rtwtwbra.htm#COHDG5177
  • https://www.v2ex.com/t/180474