Author Archives: zyanlu

rm -rf 大悲剧!

今天手欠本来想 rm -rf _* 结果敲成了 rm -rf _[空格]* 小半天的代码没有了。。。

以后必须
sudo apt-get install trash-cli
alias rm=’trash’

啊啊啊啊啊啊

twisted + thrift + php client

首先安装twisted 跟 thrift ,这个官方都有文档,注意先装依赖关系就行了

奇怪的是我的thrift-ruby 死活编译不通过,还好我不用ruby,直接–without-ruby就好了

报这个错,不懂ruby,也google不到,烦请大侠们指点迷津:

Making all in rb
make[3]: Entering directory `/home/zyanlu/soft/thrift-0.8.0/lib/rb'
/usr/local/bin/rake
rake aborted!
no such file to load -- spec/rake/spectask

装完以后还需要给语言装扩展,我这里是php做客户端 跟py.twisted通信,所以需要编译一下php扩展跟python扩展

php:

cd thrift-0.8.0/lib/php/src/ext/thrift_protocol
phpize
./configure --enable-thrift_protocol
make
make install

然后配置一下extension=thrift_protocol.so 就可以了
注意要使扩展起作用的话必须使用TBinaryProtocolAccelerated,这个官方tutorial例子里没有

python 装就比较简单了,直接就好使

cd thrift-0.8.0/lib/py
py setup.py build
py setup.py install

现在我们来跑一个demo来看看,python的官网tutorial里直接可以跑通

cd thrift-0.8.0/tutorial
thrift -r --gen py tutorial.thrift
thrift -r --gen py:twisted tutorial.thrift
thrift -r --gen php tutorial.thrift

turial里的PhpClient.php 不能直接运行成功,是include的路径不对(看一下源码跟生成的代码就行了)
把php-gen/* 拷贝到 thrift-0.8.0/lib/php/src/packages

帖一下我的PhpClient.php

$GLOBALS['THRIFT_ROOT'] = '../../lib/php/src';

require_once $GLOBALS['THRIFT_ROOT'].'/Thrift.php';
require_once $GLOBALS['THRIFT_ROOT'].'/protocol/TBinaryProtocol.php';
require_once $GLOBALS['THRIFT_ROOT'].'/transport/TSocket.php';
#require_once $GLOBALS['THRIFT_ROOT'].'/transport/THttpClient.php';
#require_once $GLOBALS['THRIFT_ROOT'].'/transport/TBufferedTransport.php';
require_once $GLOBALS['THRIFT_ROOT'].'/transport/TFramedTransport.php';

/**
 * Suppress errors in here, which happen because we have not installed into
 * $GLOBALS['THRIFT_ROOT'].'/packages/tutorial' like we are supposed to!
 *
 * Normally we would only have to include Calculator.php which would properly
 * include the other files from their packages/ folder locations, but we
 * include everything here due to the bogus path setup.
 */
// error_reporting(0);
$GEN_DIR = $GLOBALS['THRIFT_ROOT'].'/packages';
require_once $GEN_DIR.'/shared/SharedService.php';
require_once $GEN_DIR.'/shared/shared_types.php';
require_once $GEN_DIR.'/tutorial/Calculator.php';
require_once $GEN_DIR.'/tutorial/tutorial_types.php';
error_reporting(E_ALL);

//try {
  if (array_search('--http', $argv)) {
    $socket = new THttpClient('localhost', 8080, '/php/PhpServer.php');
  } else {
    $socket = new TSocket('localhost', 9090);
    $socket->setRecvTimeout(2000);
  }
  $transport = new TFramedTransport($socket);
  $protocol = new TBinaryProtocolAccelerated($transport);
  $client = new tutorial_CalculatorClient($protocol);

  $transport->open();

  $client->ping();
  print "ping()\n";

  $sum = $client->add(1,1);
  print "1+1=$sum\n";

  $work = new tutorial_Work();

  $work->op = Operation::DIVIDE;
  $work->num1 = 1;
  $work->num2 = 0;

  try {
    $client->calculate(1, $work);
    print "Whoa! We can divide by zero?\n";
  } catch (tutorial_InvalidOperation $io) {
    print "InvalidOperation: $io->why\n";
  }

  $work->op = Operation::SUBTRACT;
  $work->num1 = 15;
  $work->num2 = 10;
  $diff = $client->calculate(1, $work);
  print "15-10=$diff\n";

  $log = $client->getStruct(1);
  print "Log: $log->value\n";

  $transport->close();

大功告成,后续测试一下性能是不是有宣传的那么给力

ubuntu server dev setup

ubuntu server的好处是体积小,很快就能下好装上,但是开发常用的包都木有。(我是os x里弄了个linux vm来开发⋯ air的硬盘太小了…)

以下列表,不断更新中⋯⋯

apt-get install zlib1g-dev
apt-get install gcc
apt-get install dpkg-dev
apt-get install libssl-dev
apt-get install libxml2-dev
apt-get install libxslt-dev
apt-get install ntp
apt-get install libpcre3 libpcre3-dev
apt-get install libreadline5-dev
apt-get install exuberant-ctags
apt-get install mysql-client libmysqlclient-dev
apt-get install libbz2-dev
apt-get install zlib1g-dev
apt-get install libjpeg62-dev
apt-get install libfreetype6-dev
apt-get install liblcms1-dev
apt-get install libcurl3-dev

java 小陷阱

下面这段小程序是否输出true呢?

public long countRectangles(int width, int height){
		long x = (width*(width+1)/2)
				* (height*(height+1)/2);
		long a1 = (width*(width+1)/2);
		long a2 = (height*(height+1)/2);
		System.out.println(x == (a1*a2));
}
public static void main(String[] args) {
		new RectangularGrid().countRectangles(592, 964);
	}

结果坑爹了,打印出来x只有38960016,一看就是溢出了⋯
问题就在于 long = int*int的效果等同于long = (long)(int*int)
int*int返回值仍旧是int,所以修改成为long = (long)int*(long)int 就可以了。
这个其实是个很基础的问题,但是有时候敲代码一不留神还是很容易写错。

sqlalchemy utf8 quickstart

先把mysql全都配成utf8,比较坑爹的是table charset貌似没法指定默认utf-8,必须create的时候指定

[client]
default-character-set=utf8
[mysqld]
collation-server = utf8_general_ci
character-set-server = utf8

验证一下:

SHOW VARIABLES LIKE ‘character_set_%’;
SHOW VARIABLES LIKE ‘collation_%’;
# -*- coding: utf-8 -*-
import sqlalchemy
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, BigInteger,String,Text
from sqlalchemy.orm import sessionmaker

Base = declarative_base()
class Node(Base):
    __tablename__ = 'node'
    __table_args__ = {'mysql_engine':'InnoDB','mysql_charset':'utf8'}
    id = Column(Integer, primary_key=True)
    path = Column(String(255), index=True)
    name = Column(String(255))
    data = Column(Text)
    datatype = Column(String(255))

if __name__ == '__main__':
    engine = sqlalchemy.create_engine('mysql+mysqldb://root:123456@127.0.0.1:3306/dbname?charset=utf8', echo=True)

    Base.metadata.drop_all(engine)
    Base.metadata.create_all(engine) 

    Session = sessionmaker()
    Session.configure(bind=engine)
    session = Session()
    session.commit()

    n = Node()
    n.path = "/"
    n.name = "汉字"

    session.add(n)
    session.commit()

__table_args__指定了表编码,这样就可以很好支持中文了⋯ 如果有能在mysql配置里指定编码的方法请留言⋯

nginx配置geoip

按照http://wiki.nginx.org/HttpGeoIPModule就可以了

有一个坑,就是

http {
geoip_country /path/to/GeoIP.dat; #这里一定要写绝对路径
geoip_city /path/to/GeoLiteCity.dat;

查了一下手册,好像没有$nginx_home这样的变量,所以需要写死?..

总结一下:
1.先安装依赖libgeoip-dev
2.去下载需要的ip库http://geolite.maxmind.com/download/geoip/database/
3.重新编译nginx
4.修改nginx配置

python读取arc文件的小脚本

import gzip,re

file = "/arcs/some.arc.gz"

ARC_PATTERN = re.compile("(^.*:[^ ]*)\\s([0-9.]+)\\s(\\d+)\\s(\\S+)\\s(\\d+)$")

def readchunk(fp):
    meta = ARC_PATTERN.match(fp.readline()).groups()
    page = fp.read(long(meta[4])+1)
    return (meta,page)

def main():
    f = gzip.open(file,'rb')
    print readchunk(f)
    print readchunk(f)

if __name__ == '__main__':
    main()

windows下注意加rb,不然会坑。

一个管理ssh tunnel的小脚本

首先在本机跟远程服务器建立信任关系,可以使用这个小脚本。

然后使用这个小脚本来管理ssh tunnel,都放在$HOME/bin下。

用法:

tunnel on
tunnel off

在mac下可以使用脚本来管理链接,这样就不用鼠标去点设置->无线..

alias sock='networksetup -setsocksfirewallproxystate Wi-Fi'
sock on
sock off

两个脚本配合起来使用还是很方便的。

中国特色之APNs connection reset

最近在捣鼓 iPhone Push Notification

基本上就是TLS连一下APNs,但是鉴于TLS连接会受到随机阻断(goo.gl/KCMR8),消息将很难确保一定成功发送。

当APNs收到一条它认为有误的信息时就会立即断开连接,并且放弃后续的所有消息,同时会返回一条消息告诉Povider哪条消息有误。因此我们需要有一个错误恢复机制。

但是在一个TLS连接随时可能被切断的情况下,我们还需要不断恢复TLS连接。如果这时恰好有错误发生,那么我们将无法从APNs获取错误信息,因此也无法进行错误恢复,一部分消息将丢失。实际测试中差不多发送几十到几百条消息时,就会被reset一次,频率还是很高的。

有趣的是我将代码部署到海外服务器的时候,完全没有影响,消息发送速度也要高很多。

解决办法?

如果有条件的话,使用海外服务器来进行你的消息推送, Amazon EC2就是一个不错的选择。结合ssh -D -N,你懂的。

如果没有条件,那么我建议将发送窗口调小点,比如发送100条消息就关闭当前连接,重新与APNs建立连接。这样消息丢失的损失就可以控制在100条以内。当然这么做苹果会很不高兴,苹果官方推荐在一个链接里面尽可能多发送消息以节省资源。

 

入度与出度

前几日QA同学给我们讲代码可测性,提到了一个很好的概念:代码的入度与出度。

入度就是说其他模块调用你的模块的次数,出度就是说你的当前模块调用其他模块的次数。

->  入度 ->  | Module |  -> 出度 ->

简单来说,就是可测性好的模块一定是入度更大,为别的模块提供了丰富的功能,而又很少依赖其他模块。

我们把模块级别拓展到服务级别,这个道理也是一样的。 好的服务一定是提供的丰富的功能及接口,而又没有太复杂的关联关系及服务依赖。

同理,上升到业务级别的时候,如果你的入度更大,很有可能就属于所谓 “核心业务” 那部分。就以amazon云服务为例,amazon把自己的“核心业务”做成公有服务拿出来卖:虚拟化、存储、计算、网络服务,更上层的有消息服务,支付服务等等。 看起来好像这些东西在一个大一点的公司应该都有,前几日的g+上的 “google 工程师大吐槽” 大致的意思就是amazon有的我们都有,为啥人家弄得那么好都可以拿出来卖了而我们却是一团团?

amazon把自己的“核心业务”拿出来晒,在整个业内增加自己的入度,google自然看了着急啊。

代码总是人写的,当具体到一个工程师的时候,这个法则似乎也适用。很多工程师都觉得每天忙到累到不行行,但是却感觉没什么收获,别人对自己的评价也不高呢?为什么只剩苦劳没有功劳呢?

回顾一下自己做的工作,是入度更大,还是出度更大?

那些出度更大的工程师,通常需要经常与各种人沟通,寻求各种帮助,约定各种接口,这通常是一个极消耗精力的过程 —- 比如面对各种异构系统解决自己的问题。

这时候就需要反思了,如何才能增加自己的入度,给别人提供服务?

或许从每一行代码就可以开始增加自己的入度吧:

我的代码是不是可以复用的?

我写的模块是不是可以作为公共库使用?

我目前的业务线是否可以做成公共服务供别人很方便地调用?

我的业务经验是不是可以share的,哪些是对别人有价值的?

….

顺着这个思路,我相信你一定能成为“高入度”的NB工程师。