kenshin

Lua模块化开发

| Comments

定义模块的方式

定义module有两种方式,旧的方式,适用于Lua 5.0以及早期的5.1版本,新的方式支持新发布的Lua5.1和5.2版本。

旧的方式

通过module("...", package.seeall)来显示声明一个包。看很多github上面早期的开源项目使用的都是这种方式,但官方不推荐再使用这种方式。

定义:

1
2
3
4
5
6
7
-- oldmodule.lua

module("oldmodule", package.seeall)

function foo()
  print("oldmodule.foo called")
end

使用:

1
2
3
require "oldmodule"

oldmodule.foo()

编译godns

| Comments

*nix系统编译godns的详细步骤

1.安装golang

1
2
3
4
5
6
7
8
9
10
11
12
13
14

$ sudo  wget https://go.googlecode.com/files/go1.1.1.src.tar.gz

$ sudo tar zxvf go1.1.1.src.tar.gz

$ cd go/src

$ sudo ./all.bash

$ sudo mv go /usr/local/go

$ sudo cp /usr/local/go/bin/*  /usr/local/bin 

$ sudo ln -s  /usr/local/bin/go /usr/bin/goma

2.设置环境变量

1
2
3
4
5
6
7
8
9
10
11
$ vim ~/.bashrc

export PATH=$PATH:/usr/local/go/pkg/tool/linux_amd64/

GOBIN=/usr/local/go/bin

GOROOT=/usr/local/go/

GOPATH=$HOME/godns

export GOBIN GOROOT GOPATH

设置完成后,运行go env, 看设置是否都生效

Godns - Go实现的DNS缓存服务器

| Comments

最近用Go写了一个DNS缓存服务器,主要实现两个功能:

  • DNS缓存
    有缓存失效机制,在cache未命中时,支持设置上层递归服务器。
  • 全局hosts
    维护全局的hosts设置,统一实现解析域名到指定IP的需求。
    另外,支持动态更新hosts记录,而不需要重启服务器进程。

重新造一个轮子的原因

实现了DNS缓存服务器并支持自定义的hosts的开源软件有很多,例如dnsmasq,之所以我们要自己写一个,是因为dnsmasq的hosts记录都是写在本地文件中,更新一条记录后,要重启进程才能生效。而我们需要能在不同的服务器上共同维护一个全局的hosts记录,并在hosts记录修改后能立即生效。目前能找到的实现,包括dnsmasqpdnsddjbdns,还没有一个能完全满足我们需求的。

用Go实现的原因

之所以用Go来实现主要是担心Python的性能问题,刚好最近看了大量Go的开源项目,因此便想要Go来尝试一下。实践证明,Go确实非常适合这类服务器端应用的开发。程序性能还不错,我们在4核2.5G CPU, 46G 内存的服务器上测试,每秒大概能处理1.6W多个请求,这台机器上同时还跑了一些其它应用,如果在干净的机器上测试,数据应该还会更好一些。另外,整个开发效率也没比python慢多少,差不多一个礼拜就完成了所有功能的开发。

目前godns已经部署到了我们的生产系统。
同时把代码放到github上:https://github.com/kenshinx/godns , 欢迎有需要的同学试用,如果有什么问题可以在github上反馈。

Go Reflect

| Comments

最近在看一些go语言标准库以及第三方库的源码时,发现go的reflect被大量使用,虽然反射的机制大多数语言都支持,但好像都没有go一样这么依赖反射的特性。个人觉得,reflect使用如此频繁的一个重要原因离不开go的另一个特性,空接口interface{},reflect配合空接口,让原本是静态类型的go具备了很多动态类型语言的特征。 另外,虽然反射大大增加了go语言的灵活性,但要完全掌握它的原理和使用也还是有一点难度的。

go的reflect库有两个重要的类型:

  • reflect.Type
  • reflect.Value

Type,Value分别对应对象的类型和值数据

还有两个重要的函数:

  • reflect.TypeOf(i interface{}) Type
    reflect.TypeOf()返回值的类型就是reflect.Type。

  • reflect.ValueOf(i interface{}) Value
    reflect.ValueIOf()返回值的类型就是reflect.Value


reflect.Type

reflect.TypeOf(i interface{}) Type

因为reflect.Typeof的参数是空接口类型,因此可以接收任意类型的数据。 TypeOf()的返回值是这个接口类型对应的reflect.Type对象。通过Type提供的一些方法,就可以获得这个接口实际的静态类型。

mac下用gdb调试Go程序

| Comments

安装gdb

MAC OS X安装Xcode时,会带一个6.x版本的gdb,只支持DWARF2。 而Go的编译文件默认是包含 DWARFv3 调试信息,因此需要升级gdb版本到7.1或以上。 安装步骤:

1
2
3
4
5
6
$ curl -O http://ftp.gnu.org/gnu/gdb/gdb-7.3.1.tar.gz
$ tar -xzf gdb-3.7.1.tar.gzma
$ cd gdb-7.3.1
$ ./configure
$ make
$ [sudo] make install 

通过上面的步骤安装完后,gdb7.3 会安装到/usr/local/bin/gdb,原来的gdb 6.x在/usr/bin/gdb。 这个时候直接执行gdb,默认使用的还是gdb 6.x(依赖于你的$PATH设置)。如果想显示调用gdb 7.3就得使用绝对路径, /usr/local/bin/gdb 。因为我需要用Xcode调试iOS程序,所以要保证gdb 6.x依然可用,否则可以用/usr/local/bin/下的gdb 替换/usr/bin下面的,这样每次调用就不需要使用绝对路径了。
剩下的事情就和操作系统无关了。

humans.txt

| Comments

都知道robots.txt,可以用来设置爬虫规则。今天发现还有一个humans.txt,还挺有意思的。

这个文件没有什么具体的作用,主要是对网站和作者的介绍,让你的网站显得更有人味。
humans.txt官网有中文版本,有很详细的介绍: 我们是人,不是机器

随手给自己博客也加了一个http://blog.kenshinx.me/humans.txt :D

通过supervisord管理celery守护进程

| Comments

Why Supervisord

supervisord是一个python写的守护进程管理工具,功能非常实用。supervisord的介绍可以看这篇文章。在生成环境,celery worker进程通常会以守护进程的方式运行,而celery命令行工具本身是不支持以daemon方式运行的,虽然可以nohup celery worker &的方式让worker进程在后台运行,但是当有多个celery worker进程时,这种方式管理起来就会变得很麻烦,想要stop,restart还得一个个去kill pid。 supervisord是celery官方推荐的daemon管理工具之一,可以对多个进程统一进行监控,管理。

Configuration

配置其实很简单,主要就是设置supervisord.conf和celerd.conf两个文件。celery官方还提供了这两个文件的示例
下面是我这两个文件的设置,提供给正在弄这个的同学们参考。

supervisord.conf

[unix_http_server]
file=/tmp/supervisor.sock   ; path to your socket file
;chmod=0777
;chown=webscan:webscan

[inet_http_server]
port=1222
username=sinasec
password=xxxxxxx

[supervisord]
logfile=/var/log/supervisord/supervisord.log ; supervisord log file
logfile_maxbytes=50MB       ; maximum size of logfile before rotation
logfile_backups=10          ; number of backed up logfiles
loglevel=info               ; info, debug, warn, trace
pidfile=/var/run/supervisord.pid ; pidfile location
nodaemon=false              ; run supervisord as a daemon
minfds=1024                 ; number of startup file descriptors
minprocs=200                ; number of process descriptors
user=root                  ; default user
childlogdir=/var/log/supervisord/            ; where child log files will live

[rpcinterface:supervisor]
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface

[supervisorctl]
serverurl=unix:///tmp/supervisor.sock ; use unix:// schem for a unix sockets.

; celery的监控工具flower自身也不支持以daemon方式运行,刚好也可以通过supervisord管理起来。
[program:flower]
command=/usr/local/bin/flower --adress=0.0.0.0 --port=1221 
autostart=true
autorestart=true
user=webscan
directory=/var/webscan/scanner/
stdout_logfile_maxbytes = 50MB
stdoiut_logfile_backups = 20
stdout_logfile = /var/log/flower.log

[include]

# Uncomment this line for celeryd for Python
files=celeryd.conf

# Uncomment this line for celeryd for Django.
;files=django/celeryd.conf

基本上就是官方那个配置文件,拿过来加上了flower的设置。

Python Gevent爬虫

| Comments

最近新写了一个爬虫,虽然google可以搜到一大堆爬虫,但要不太过简单,无法设置链接深度,最大并发数等常用爬虫规则,要不像scrapy这样的又太重。因此花了几天时间又从新写了一个适合我们需求的爬虫。代码在这里: https://github.com/kenshinx/second-spider

主要使用的库

支持的爬虫规则

  • 最大并发请求数
  • 最大爬行URL数
  • 最大链接深度
  • http请求的headers,cookies
  • 是否只爬相同域名下的url
  • 是否只爬相同主机名下的url

还需要做的事

  1. 继续添加一些规则,例如解析robots文件,可设置一些不爬的url等
  2. 对相似url进行识别,排重
  3. 对Ajax类url的爬取

Javascript面向对象

| Comments

讨论一门语言的面向对象特性,无非就是封装、继承、和多态的实现机制。 封装可以理解成创建对象,并为对象添加属性和方法的过程,javascript的封装、继承、多态都离不开两个重要概念:

  • constructor 构造函数
  • prototype 原型对象

接下来讨论如何通过这两个东西实现封装、继承和多态。

从wordpress换到octopress

| Comments

原本只是准备把部署在虚拟主机上的博客,换到最近买的linode的vps上来,换过来之后觉得原来的主题太简陋,又开始给wordpress换主题。主题找了一圈也没有太满意的,最后干脆把wordpress换成了一直很喜欢的octopress。经过一番折腾 ,博客的家变了,装修变了,家具也给换了, 原来在wordpress下写的文章大部分也丢了。

linode vps

原来的虚拟主机是国内的一家主机商,价格够便宜,访问速度也是够慢,而且经常出现无法访问的情况,每次电话过去问客服,都说正在被DDOS。这两天没那么忙,就决定找个vps,把博客换过去。网上很多对比各种vps的文章,最后选择了linode,刚好女朋友最近才办了招行的信用卡,用它付款非常方便。根据大家的测评,选择了东京的IDC。到目前为止,感觉还不错,ssh速度和网页访问速度都很稳定。

octopress

octopress与wordpress有很大的区别,系统是用ruby写的,内容以静态HTML的方式发布,mysql也不需要了。不仅访问速度有很大提升,对于vps这种系统资源很紧张的设施,节省系统开销也是很重要的。原来我在vps上把apache,mysql,fastcgi-php都跑起来后,没有访问压力的情况下也需要占用200-300M的内存,现在整个blog只需要跑一个nginx, 占用的内存还不到100M。从wordpress迁移到octopress的介绍也很多,我用了一个exitwp的工具,过程很简单,不过迁移过来后,原来文章的格式需要一些调整。

迁移到octopress之后,最大的变化是写文章的方式。我原来都是在evernote上面写,然后在wordpress上调html的样式。octopress是基于jekyll支持markdown语法,我现在都是在sublime-text 2上面按照markdown的语法写文章,然后通过rake generate生成html文件,省去了原来调html的麻烦。sublime-text 2有两个插件,markdown preview,smart markdown可以帮助提高写markdown文件的便利性,目前还在熟悉markdown的语法,这篇文章文章就是按照markdown语法写的,写起文章来就像写代码,感觉很爽。

备份上相比之前既要备份数据库又要备份代码,现在每次更新文章后直接push到github上保存,非常方便。