三余无梦

冬者岁之余,夜者日之余,阴雨者时之余也

2016年展望

简单回顾下2015

技术(YES) vs 技术(NOT yet done)

  • 项目接口优化 95% api handle time < 100ms
  • 接触postgresql
  • python 处理部分运维工作 vs 没有实现自动化,不少工作仍需手动干预

生活(YES) vs 生活(NO yet done)

  • 3 个马拉松 and 一个越野跑 (run) vs 成绩不理想(run)
  • 组了一辆大轮车开始训练 vs
  • 和同事组了一个乐队:) vs 并没有练习配合
  • 开始联系非洲鼓 vs 节奏没感觉
  • 已订婚

2015年最大的问题是: 工作时间占用了自我学习时间

2016年展望

生活

  • 科学练习跑步(FIRST训练-每周3次训练)
  • 开始学习游泳(4月中旬开始办游泳卡)
  • 骑行(每周保证2次训练)
  • 非洲鼓(找教程练习节奏)
  • 结婚前把车练上路
  • 为结婚存钱:(

技术

  • 深入Python(阅读2-3个python库),写干净清晰的代码
  • 深入使用Postgresql, 年底写篇使用经验
  • 深入理解tcp/ip,socket等网络知识
  • github 开源项目做贡献
  • 工作上 成立数据部门/架构扩展
  • 运维工作 –> 自动化
  • 接触一些基本算法层面的东西
  • 写高质量的技术博文(可考虑英文)

更好的管理时间,更好的自己!

Nginx Use

Nginx config description (注意事项)

  • proxy_buffer_size
1
2
3
Syntax: proxy_buffer_size *size*;
Default: proxy_buffer_size 4k|8k;
Context: http,server,location

把代理服务器传来的第一部分(通常是response header)放在proxy_buffer里

  • proxy_buffers
1
2
3
Syntax: proxy_buffers *number size*;
Default: proxy_buffers *8 4k|8k*;
Context: http,server,location

设置buffers的个数和大小(单一链接).默认size等于一个内存页,取决于平台

  • proxy_buffering
1
2
3
Syntax: proxy_buffering *on | off*;
Default: proxy_buffering on;
Context: http,server,location

开启/关闭 proxy_buffering, buffering on , nginx接受到代理服务器的返回就会将其存入buffers.如果回复内容超过设置的大小,会将回复内容存入临时文件(temporary file)硬盘里

  • proxy_temp_path

Syntax: proxy_temp_path *path*; Default: proxy_temp_path proxy_temp; Context: http,server,location

定义一个文件夹存储proxy server传来的数据

nginx use 问题

  • proxy server 为django, django返回的文件5m左右,但是最后下载下来的只有69k,最后跟了下nginx error log, 看到如下错误

open() "/***/nginx/proxy_temp/0/12/00001213420" failed (13: Permission denied) while reading upstream,

问题就很明显了,这就是proxy_buffering里的返回内容大了,会先将其存入硬盘,但运行nginx的用户对临时文件无权限,所以将临时文件夹的用户权限改下问题就解决了

  • proxy server 为django, 访问服务器出现django出现如下错误:

Invalid HTTP_HOST header(you may need to set ALLOWED_HOSTS): 127.0.0.1:3456

这个问题就是django在请求来的时候会检查request header 里的 host.如果host不是预设的xxxx.com那么就会报500错误,一般是因为nginx没有加proxy_set_header Host $host;, 加上这个说明就好了 ip proxy_set_header X-Real-IP $remote_addr 也是同样的道理

Use Redis in Production - Redis Config Set

redis config set

  • since redis 2.0.0, u can use this change setting in redis running
  • config set可以修改哪些配置: config get *

注意事项

  • config set 只能在redis运行时改变配置,但不能改变配置文件里的配置,所以当你在redis运行时,使用了config set,必须在对应的配置文件里做修改,否则下次启动时配置又会改变

实战

  • 最近的项目里需要对redis数据库做迁移,从系统盘->数据盘,场景是只使用了RDB持久化
  • 使用config set dir 需注意
1
2
3
4
5
6
7
rdb将内存中的数据库以RDB格式保存到磁盘中,如果RDB文件已存在,那么新的RDB文件写好将会替换为已有的RDB文件。
在保存RDB文件期间,主进程会被调用rdbsave函数 
bgsave过程fork出一个子进程,子进程负责调用rdbSave,并在保存完成之后向主进程发送信号,通知保存已完成
save过程直接调用rdbSave,阻塞Redis主进程,知道保存完为止。在主进程阻塞期间,服务器不能处理客户端的任何请求。
这里有两个坑
1. fork是有延迟的 [](http://blog.nosqlfan.com/html/3903.html)
2. RDB在写入过程中,会连内存一起Fork出一个新进程,遍历新进程内存中的数据写RDB. 注意fork的时候一定要注意当前机子的内存,保险的话是2倍现有redis所占内存.
  • dump.rdb 从 /var/lib/redis/ , 转存到/mnt/lib/redis/
  • redis-cli
  • config set dir /mnt/lib/redis #这里要注意redis进程是属于哪个用户的, 要把/mnt/lib/redis设为此用户可写可读的
  • bgsave #当看到/mnt/lib/redis 里有dump.rdb(默认)文件时就表明操作成功
  • 此时再修改 redis.conf 将 dir –> /mnt/lib/redis
  • 如果下次重启的话, redis将会从 /mnt/lib/redis/dump.rdb 读入数据到内存中 #注意如果要重启,最好先把业务逻辑相关的redis处理关掉,防止数据丢失,并且通过shutdown 关闭,不要kill -9。

config set 还可以修改很多参数这里不一一解释等以后用到再做解释TBC

Cookie Intro and Cookie Share

cookie intro

  • how cookie come

    • when you first visit xxx.com, the website produce a cookie and sent you on http response header you may find the field Set-Cookie.
  • why cookie

    • make website recongize client
    • website according the cookie know you and give you different website or advertisement. or remeber your login status …
  • cookie attribuate

1
Set-Cookie:BAIDUID=17EFBEC8FFD5F79747775326540CB66C:FG=1; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
  • HttpOnly
    • this atribute directs browsers can not expose the cookie through channels other http(s), so if httponly ,alert(document.cookie) should output null.
  • secure
    • It’s also a flag, it meant browsers transfer cookie through secure methods even if it’s not https request. more detail at here
  • domain
    • domain value for cookie share, if a.xxx.com and b.xxx.com need share the cookie, domain=‘.xxx.com’ is ok. more detail 1
  • path
    • path easy to understand, cookie is effective in which path
  • expires
    • the time the cookie will be deleted
  • max-age
    • the seconds cookie get delete, the differences between max-age and expires, can ref difference
  • name=value
    • easy to understand, you want to save what value in cookie, the example BAIDUID=****

ps the cookie is produced by server

‘Unicode’介绍系列1

Unicode系列目前有准备有2篇文章

  • 介绍Unicode
  • Unicode在python(2.x)中的应用(让人头疼有么有)

好的下面开始

what Unicode

  • Unicode 是一种字符集, 规定字符对应的二进制代码
  • 平常所说的ASCII码呢,就是英语的128个字符对应的二进制代码

why Unicode

  • 如其名,统一编码,所有的字符都有对应的独一无二的二进制代码, 这样就能一统天下

unicode 缺陷

  • Unicode 规定了符号的二进制代码, 却没有规定这个二进制代码如何存储
  • 如’严’的Unicode为4E25, 至少需要两个字节来表示, 就是说这个字符需要两个字节, 问题就来了,计算机不知道怎么区分2个字节表示一个符号,计算机也可以认为1个字节一个字符, 如果统一都用4字节表示每个字符,那么对于一个字节就可以表示的字符, 就是浪费,这是不能忍的
  • 所以需要一种比较号好的实现模式,去解决…

UTF-8

  • UFT-8是在互联网上使用的最广的一种Unicode的实现方式。
  • 这是一种可变长度的编码方式, 可以使用1~4个字节表示一个符号
  • 编码规则:
  • 对于单字节的符号, 字节的第一位设为0, 后面7位是个符号的Unicode码, 因此对于英语字母, UTF-8和ASCII码相同
  • 对于n字节的符号(n > 1), 第一个字节的前n位都设位1, 第n+1位设为0, 后面字节的前两位一律设为10, 剩下的二进位,全部位这个符号的Unicode

TBC

First 5 Minutes Troubleshooting Server Translate

原文

服務器遇到問題,從何下手?

不要急着衝向你的服務器, 在這之前, 你對它和具體的問題了解多少?

必須知道的

  • 問題的確切症狀? 丟包? 錯誤?
  • 問題什麼時候被發現?
  • 可以重現麼?
  • 有什麼規律(例如每小時發生一次)?
  • 在服務器的最後一次改變(代碼, 服務配置, 內存)?
  • 問題會影響客戶的哪個部分(登錄, 註銷, )?
  • 有監控平臺麼? Munin, Zabbix, Nagios, NewRelic..
  • 日志(集中化)? Loggly, Airbrake, Graylog

上面的最後兩項是最方便直觀的信息來源, 但也別期望太多;爲了搞定問題,繼續往下看

誰登陸了?

1
2
$ w
$ last

不是很重要, 但是你在找問題時不希望還有其他人在擺弄的服務器。廚房裏一個廚師足矣

之前做了哪些操作?

1
$ history

看歷史記錄總是好的;配合之前誰在操作的命令.

快速回憶一下, 你也許小要升級環境變量 HISTTIMEFORMAT 去跟蹤那些命令運行的時刻.沒什麼比調查一個過期命令列表更讓人沮喪的了。

正在運行哪些程序i?

1
2
$ pstree -a
$ ps aux

如果覺得ps aux太羅嗦, pstree -a會給你一個漂亮的展示關於什麼正在運行以及誰調用了它

監聽服務

1
2
3
4
5
$ netstat -ntlp  # t: tcp
$ netstat -nulp  # u: udp
$ netstat -nxlp  # x: unix socket
$ netstat -ant|grep EST|wc -l #这条命令是很有用的能看到多少连接
$ netstat -ant|wc -l  #看到有多少tcp,udp链接

我更傾向分開運行這些命令, 主要是因爲不喜歡同時看所有的服務。雖然netstat -nalp以可以做到。甚至我會省略數字化選項(IPs是易讀點的)

確定正在運行的服務以及他們是否應該運行。尋找多個監聽端口。通過ps aux的輸出匹配進程ID;這個是很有用的特別當你同時結束2~3個Java 或者 Erlang進程

CPU 和 RAM

1
2
3
4
$ free -m
$ uptime
$ top
$ htop

這些命令回答以下問題: – 還有空閒的內存? 還是正在交換區 ? – 還有CPU剩餘麼? 服務器有多少CPU核心可用? 這些核心中是否有超載的? – 哪個項目負載最多? 平均負載多少? – 詳細了解命令man,你懂的 – 这里还有一点如果cpu不高,但是服务里面响应时间很大,那么就是程序里的代码卡住,怎么找出哪里卡住,可以通过strace -p yourpid先查看你的程序pid然后用此命令

Hardware

1
2
3
$ lspci
$ dmidecode
$ ethtool

TODO: explain commands

IO 性能

1
2
3
4
$ iostat -kx 2
$ vmstat 2 10
$ mpstat 2 10
$ dstat --top-io --top-bio

這幾個是非常有用的命令去分析後臺性能;

  • check 硬盤使用:
  • 交換區目前有沒有使用
  • 什麼程序再使用CPU: 系統? 用戶? stolen ?
  • dstat 一直是我的最愛. IO消耗? mysql 阻塞資源? php進程在使用的你io…

掛載點和文件系統

1
2
3
4
5
6
7
$ mount
$ cat /etc/fstab
$ vgs
$ pvs
$ lvs
$ df -h
$ lsof +D / /* 
  • 多少文件系統被掛載
  • 過期的文件系統
  • 硬盤空間是否有剩餘
  • 大文件還沒有清除
  • 如果硬盤有問題還有空間去加個分區?

內核,中斷, 網絡使用情況

1
2
3
4
5
$ sysctl -a | grep ...
$ cat /proc/interrupts
$ cat /proc/net/ip_conntrack
$ netstat
$ ss -s

TBC

Expressjs/finished Code Reading

* finished

  • 功能: 在请求关闭,完成, 或者出错时执行回调
  • 用例: 清除传输流。例如为了防止文件描述符泄漏,在socket出错时, 你会想要将文件流摧毁

从一个koa例子开始

1
2
3
4
5
6
7
var onFinished = require('finished');
function* () {
    var stream = this.body = fs.createReadStream('thingie.json');   
    onFinished(this, function(err) {
        stream.destroy();    
    })
}

再看finished的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
module.exports = function finished (thingie, callback) {
    /*
     * 主要需要監測socket和res的事件 
     */
    var socket = thingie.socket || thingie;    
    var res = thingie.res || thingie; 

    /*
     * res完成或者socket不可寫的時候, 直接執行callback, 返回thingie
     */
    if ( res.finished || !socket.writable) {
        defer(callback);    
        return thingie;
    };  

    /*
     * 第一次運行時listener 和 res.__onFinished 是不存在的
     */
    var listener = res.__onFinished;

    if (!listener || !listener.queue) {
        listener = res.__onFinished = function onFinished(err)  {
            if (res.__onFinished === listener) res.__onFinished = null; // 這句表明每次給listener 賦完值, res.__onFinished = null;
            var queue = listener.queue || [];
            while (queue.length) queue.shift()(err)
        }   
        listerner.queue = [];

        first([
            [socket, 'error', 'close'], 
            [res, 'finish'],
        ], listener); // 看[first](https://github.com/jonathanong/ee-first)模块解析: 主要功能在监听到指定的事件的第一件时,触发响应回调, 并清除移除所有的监听。
    }

    listener.queue.push(callback);

    return thingie;
}

想要具体看finish的应用场景,其实在单元测试里有很多具体的例子

  • 下面具体理解下其中的一个单元测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 describe('when the request finished', function () {
    it('should execute the callback when called after finish', function(done){
        var server = http.createServer(function(req, res){
            onFinished(res, function(){
                //第4步
                onFinished(res, done); // 第5步   
            }) // 第2步   
            setTimeout(res.end.bind(res), 0); // 第3步
        })  // 第 0 步  
        server.listen(function(){
            var port = this.address().port;    
            http.get('http://127.0.0.1:' + port, function(){
                res.resume();
                res.on('close', server.close.bind(server));
            }) //第1步
        })
    })    
 })
  • 测试步骤
  • 先创建服务器 第0步
  • 监听端口,做出请求 第一步
  • 服务器收到请求, 执行回调函数 onFinished(res, function(){}) 第2步
  • 第3步的话 结束请求 res.end.bind(res)
  • 第4步 监听到结束, 执行回调 onFinished(res, done)
  • 第5步 完成done

  • 测试结论:当服务器完成请求后,有onFinished()的话, 直接执行回调, 然后结束

WWDC14

WWDC14 观后感

WWDC苹果全球开发者大会. 看完10小时,列下我能记住的几点

  • mac 在手机在旁边的情况下,可以拨接电话,收发短信
  • spotlight 可以联网搜索
  • touchId 指纹解锁
  • instant hotspot: mac 和 iphone ipad 即时同步
  • swift 语言,新的apple开发语言
  • heathKit 监测健康信息,包括心率、胆固醇等

mac打电话

  • just cool, convenient

spotlight

  • Alfred堪忧了,从接触的朋友来看, 接触MAC OS的比Windows的用此功能的多。可能windows中本地搜素太慢了吧,其实联网搜索聚合windows8就有了,但是…

TouchId

  • 还是方便快捷, 从一个侧面反映未来的互联网安全是更加被看重了,因为一个账号,可以牵一发而动全身。可以预见安全研究员之类的工作会越来越多。

instant hotspot

  • 体验不间断

swift

  • 新的即视编程语言, 语言的发展就是向着更方便,更快。更方便就是对于程序员更好上手, 更快是对于编译器的要求, 从事编译器工作的同学要求会更高, 对于普通程序员在我看来是应用创意的提高!

HeathKit && HomeKit

  • heathKit 是我觉得最牛的东西了, 直接体现apple的态度, 专做软件和服务, 与硬件厂商合作, 与第三方开发者合作, 提供接口, 连接各种硬件。但是Iphone 始终是中枢系统。 heathKit重点是健康类的监控, 这与医药公司合作, 对于病人的各方面数据监控, 而改善人们的生活….(PS:未来越来越多的硬件厂商会与移动网络连接,而中间的通信安全会有越来越多的人在关注)

企业市场

  • 大会中提到500强企业中498家都在用苹果的设备。个人觉得苹果会慢慢渗入企业,包括其软件服务,not only 大众消费品

(PS: 此文是用马克飞象 挺好用的~~)

Koa-compose Code Reading

compose

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function compose(middleware) {
   return function *(next) {
        var i = middleware.length;   
        var prev = next || noop ();
        var curr;
        
        while (i--) {
            curr = middleware[1];    
            prev = curr.call(this, prev); // 
        }

        yield *prev;
   } 
}

看下例的运行效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var co = require('co');

var stack = [];
var arr = [];
stack.push(function *(next) {
    arr.push(1);    
    yield next;
    arr.push(3);
});
stack.push(function *(next){
    arr.push(2);    
    yield next;
    arr.push(4)
});

co(compose(stack)) (function (err) {
    if (err) throw err;   
    console.log(arr); // 输出 [1, 2, 3, 4], 从输出可以看到其执行顺序
});

从上例的程序可以看到koa。koa在加载中间件时是通过co 和 compose来按次序拨开一层一层的middleware。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
co (function *() {
    var arr = []
    var funa = function *(next) {
        arr.push(1);    
        yield *next;
        arr.push(3);
    };
    var funb = function *(next) {
        arr.push(2);
        yield *next;
        arr.push(4)
    };
    funa ();
    funb ();
    return arr;
})(function (err, items) {
 if (err) {
    console.log(err);     
 }
 console.log(items);    
});