网络寻租

Programmer, Gamer, Hacker

是否要用中央空调

| Comments

除了普通的空调以外,现在还有中央空调可以选择。

中央空调学名叫VRV空调, 和普通家用空调一台外机对应一台内机(简称一拖一)不同的是,可以一台外机拖多台内机, 外机同时给多台内机提供致冷剂。

网上各大中央空调的厂商都列了不少的优点,比如节能,舒适,美观等等,因此大家会在装修中考虑使用。 不过我研究过后,除了一些特殊情况,还是不推荐大家在家装环境使用。为什么呢?

首先是节能。从中央空调的原来来说,使用场景是多个房间同时使用空调的情况下,中央空调是节能的, 因为一台外机统一供给内部使用,比起普通空调多台外机来说有节能优势。 但是一方面,家里人员是比房间少,不太会出现多个房间同时使用的状况,节能的优势就没有那么明显了。 中央空调的价格超出普通空调很多,算节约电费,不一定比普通空调划算。

然后是舒适,中央空调从原理上面来说,和一般的一拖一空调没有本质区别,无非是出风方式, 它的工作方式其实和普通一拖一空调是一样的,中央空调的风管机,一拖一也可以选择。 如果需要追求舒适,可以购买好的一拖一空调既可。

还有就是美观。前面说了,中央空调内机和一拖一空调一样,那么一拖一也可以选择内嵌在吊顶里面。 不过内嵌吊顶会影响到维修,同时增加了吊顶空间。空调直接装在墙上,注意好走线,一样可以兼顾美观, 同时减少了吊顶,要知道国内的房子一般层高都不高的,能不做吊顶就不要做。

还有一个重要的因素价格。中央空调需要在装修的时候一次性投入,并且需要增加吊顶。 对于普通三室两厅户型,一般的中央空调加上安装费用还有吊顶,估计要三万五,如果安装普通空调, 要一万五的样子,并且可以装修好之后根据需求慢慢添加。 中国很多地方的大部分月份是不需要使用空调的,那么在空调上面花费大量金钱不是很划算。 装修阶段需要用钱的地方很多,资金可以安排到其他更重要的项目上面。

后期维护。中央空调是一体化系统,如果出现问题,整体系统都不能使用了。 就算是安装中央空调,最好也在一些房间做分离的方案。 因为中央空调是固定在吊顶中,后期如果想更新中央空调,只能重新进行吊顶的装修, 灵活性不像普通空调一样,可以很方便地更换和维修。不过空调系统一般不会出现问题。

从上面分析得出,中央空调不适合普通家装使用。不过以下状况可以考虑用中央空调:

  • 没有足够的空间和权力安装多台外机
  • 需要使用空调的房间很多,或者需要全室内控制温度的

比如美国,大家都是独门独户,很多房间,这个时候最好是安装一体系统化空调, 在这种情况下,也可以考虑风冷空调(集中制冷,用风道通到每个房间)。

引用资料:

装修如何选择窗户

| Comments

装修大家一般不太细细考虑窗户,一些房型自己带有窗户,一些没有,需要另外购买。

窗户有不同的材质类型:塑钢,铝合金,断桥,铝木。 同时也可以选择多种开启方式:推拉,上拉,内开,内开上悬,外开,外开下悬,上下推拉。 还可以添加其他的插件:外加防盗窗,金刚网,纱窗,隐形纱窗。

我们需要考虑的性能和功能有:隔热,隔音,透光,透风,防盗,防蚊,加锁。

有那么多的选择,加上各种功能和装饰上面的区别,同时不同位置的窗户需要关注的重点不一样, 装修的时候最好需要好好思考怎么选择,不能草率定下。因为装修完成之后,换窗付出的成本很高, 用不满意的窗户会很不舒服。

特性

断桥窗因为隔热隔音的特性比较好,现在是装修的主流。推拉窗因为有间隙,隔热隔音性能不好,一般不做断桥的, 多见塑钢以及普通铝合金。铝木的隔音隔热性能更好,但是因为加上了木头,造价比较高,适合土豪以及高价房选择。

大城市高层多用内开窗户,这样比较安全,但是内开占用了室内空间,对于住户不是很方便。 内开上悬(内开内倒)的上悬状态可以保证一定程度的通风同时防盗防水(只开启上面一条缝),但是通风性能有限。 下悬一般不用在家庭中,摩天大楼玻璃幕墙有一些是这样的设置。

一些窗户为了满足防盗防蚊的需求,加上了金刚网,但是窗户的厚度需要增加,单价就会高很多。 外加便宜的三段中间抽拉式金刚网价格比较便宜(200多),但是美观要差一些。

防蚊可以用金刚网,固定纱窗和隐形纱窗。隐形纱窗视觉效果最好,也可以通过左右或者上下抽拉收起来, 但是寿命有限。固定纱窗往往装在推拉窗上,断桥就没有办法装了。金刚网造价就要高一些,外加以及窗户一体都比较贵。

防盗窗价格便宜(100左右),但是很影响视觉效果。不锈钢防盗窗便宜但是非常丑,铝合金不锈钢美观,但是造价高一些,不锈钢防盗窗如果里面没有穿钢筋,防盗效果就不是很好,穿了钢筋又重,人难抬。

建材市场里面的窗户品牌非常多,大多数都是小品牌。窗户厂商都是购买铝材回来加工,普通厂商也就几十个人。 但是不同厂商还是有区别,窗户加工机械有很大的不同,具体可以看窗户的做工,是否机械加工还是手工加工, 窗户的框是否厂家压好运过来,还是人工本地组装。

我觉得窗户的级别有几种:国外系统门窗,国内系统门窗,非系统机械加工门窗,人工组合门窗。 系统门窗的意思就是,厂商在设计的时候通盘考虑窗户的隔音隔热性能,可以了解到厂商提供的隔热隔音参数, 厂商为了达到这些参数,对窗户的工艺做了一定调整。国外的系统门窗可以达到非常好的性能,但是非常贵。 国内系统门窗性能没有那么好,价格也贵(2000以上一平)。 我建议至少要用机械加工门窗,而不是组合门窗(可以看窗户的角,是用角码螺丝固定,还是机器冲压的一个口), 这样窗户更稳固一些。

实例

以我自己装修作为一个实例。

首先是考虑更换哪些窗户。因为窗户的成本比较高(新房不能用太差的窗户,最起码也要500一平), 以及我们房子原先的窗户还过得去(铝合金推拉钢化中空),就只更换卧室的窗户。 卧室需要比较好的隔音隔热要求,人在里面待的时间也比较久,花钱更换更好的窗户是值得的。 装修之后窗户更换复杂,如果你觉得窗户使用寿命低于房子的使用寿命,最好更换。

我们装修预算有限,不考虑铝木窗,我们的装修风格是可以搭配灰色铝合金窗户的。

对于所有的窗户,我们有以下要求:安全,都要能够防盗,防止小孩出去,防蚊,美观。 我们是顶层,窗户一定要能够保证安全(住户以及楼下人员); 小偷很容易从楼顶上面翻下来,所有的窗户都要加上防盗; 房子内会养育小孩,窗户需要能够防止淘气小孩掉落出去; 我们的楼顶会有一些露天平台,蚊虫估计也不能避免; 加上是新房,在美观上面也有一定的要求,不能太丑。

然后是针对每一扇窗户进行单独分析和考虑。我们有几个:卧室窗户,书房内阳台,厨房。

卧室窗户的要求是隔热隔音,必须做断桥平开,因为窗户边上是梳妆台,内开就不可能做到了。 同时需要做到防盗和美观,要加上金刚网。因为人待得久,花多一些钱是可以接受的,选择好一些的品牌窗户。

书房内阳台。在保证隔热隔音的同时,我希望有比较好的视野,能够有整面的落地玻璃。 但是电梯的大小有限,太大的玻璃不能上来,我选择垫高阳台靠窗的底部,做一个飘窗一样的平台。 窗户放在阳台的两侧,选择内开外金刚网,因为是阳台,内开不会影响到人的行动。

厨房。厨房关注通风,隔热也需要,因为我们的厨房在北部,有西晒。但是和通风和防盗比较起来, 优先级就没有那么高了。我们选择的是一款带防盗栏和防蚊纱网的推拉窗。

对于所有其他的窗户,都外加漂亮一些的防盗窗,内加纱窗(推拉窗都可以加上,很方便)。

我们考虑了很久才选择这样的方案,价格在一万多的样子,属于可以接受的范围,这个方案我们很满意。 希望大家也要用心选择。

什么通用数据交换格式更好

| Comments

考虑可以同时用来应对程序和人都需要阅读状况的通用数据格式, 几个层面:

首先是数据格式,需要能够支持:string, bool, number, time。 它们都应该是标准化了的。考虑不增加symbol,因为和string有概念上面的重复, 使用上会产生困扰。

然后是数据的组织方式。因为组织本身是不可变的,用map和list能够覆盖所有类型的数据组合方式, 并且是完备的。tuple这种冗余不需要。

最重要的是数据的表示方式。 人工阅读的数据应该容易阅读,所以数据要有换行和缩进,没有xml这种尾部冗余。 数据组织之间的切割应该用分割符,而不是换行。类似yaml这种换行分割会带来更多的问题。 数据应该同时有两种表示方式,一种文本格式,用utf8编码,方便人阅读, 一种二进制格式,机器处理更快,两种方式能够互相转换。

关于xml,如果说json是类型的组合,那么xml就是物件的组合,默认物件拥有属性和子项, 所以xml我觉得是一种非通用的格式,本质模型不适合进行通用数据交换。

根据上述考虑,我觉得合适的方案是:格式化之后(换行缩进)的json,结合bson来用。 比如RESTful的服务,返回的json默认增加缩进,同时也提供bson格式的返回,不考虑其他格式。

局域网时代下科学上网

| Comments

(2015-12-14更新KCPTUN方法)

我们知道,最近各大运营商都提速了,大家随便就可以买到100M以上的网络。 但是国外出口没有配套提升,这样的结果就是,分到每个人的国际出口带宽就少了, 访问国外网站就成为一个非常痛苦的过程。中国的网络就此成为一个名副其实的局域网。

要解决访问国外网站的问题,需要两步:

  • 要有一个保障国际出口带宽的国内服务。
  • 要有一个国外流量中转服务来绕过我们都知道的防火墙干扰。

用户连接国内VPS的方案可以是VPN,可以是代理。我偏好VPN,因为全局翻墙下各种命令行工具也是可以用的。对于普通人来说只需要访问网页,各种代理协议也可以。

国内VPS连接国外VPS的方法最好是常见的VPN,为什么呢,因为常见VPN各大国内外企或者国内互联网公司也在用,防火墙不太会干扰这些主流业务。 如果用ssh,或者其它代理或者不知名的协议,一方面会被防火墙干扰,另外一方面包协议没有足够好的优先级,性能会差一些。

我觉得最好的解决方案是:国内一台有良好国际出口带宽的VPS和一台国外VPS结合,提供pptp/l2tp/anyconnect VPN服务。

这种方案我没有配置成功,因为不知道如何让国内VPS来做VPN中继。只能用其他的方案了: 结合微林的云涟服务以及ssh代理连到我买的国外VPS上网。

云涟是一个提供良好国外出口流量的服务,方法是用openvpn或者anyconnect连接到一个阿里云里面CN2网络的VPS上面。 有了好的出口带宽,之后用本地电脑命令行的ssh连到国外VPS,提供本地的一个sock5代理,再在浏览器上面设置代理访问网站。

具体操作:

  • 注册微林,按照教程,本地电脑连接上VPN。
  • 购买一台便宜的国外VPS,比如DigitalOcean
  • 如果你是linux或者mac,在命令行执行 ssh -ND 1080 user@digital_ocean_vps_ip。
  • 设置浏览器的代理,用sock5,地址是127.0.0.1,端口1080。

我现在用这种方法,访问国外网站非常顺畅,速度可以达到1MB/s。 不过,成本会高一些,云涟的费用是1块钱每G,国内流量的费用是比较高的。 国外VPS就便宜了,DigitalOcean是5美元一个月。

期待有科学上网服务商提供这样的整体方案,省得大家自己弄了。

2015-08-29更新:

因为ssh提供sock5代理的性能问题,以及有协议特征容易被防火墙干扰,我建议大家换用shadowsocks。 它是一个python写的客户端/服务器分离的sock5代理(国外服务器跑server端,client端和server端加密通讯,client端再启动一个sock5服务)。 现在作者被喝茶,官方项目已经废掉了,不过还有其他的镜像

客户端和服务器双方预先保存密码,没有登录等操作,直接用密码加密通讯, 同时可以选择多种加密方式,这样通讯没有协议特征,防火墙没有办法干扰。 不过还是会有流量特征,防火墙如果开启智能学习的话,会把通讯劣化掉。不过现在好像没有进行这样的干扰。 同时因为跑的是非主流协议,运营商会降低通讯的优先级,造成性能差一些。

使用方法:

  • 购买一台便宜的国外VPS,比如DigitalOcean
  • 在VPS上面安装SS,然后执行ssserver -p 4431 -k password。记得修改-k的密码参数。
  • 注册微林,在vxTrans里面创建一个端口映射,指向你的VPS服务器的4431端口。通过微林的CN2精品网络保证出国带宽。
  • 在你本地机器上面安装SS,执行sslocal -s 微林服务器地址 -p 微林服务器分配给你的端口号 -k password -l 1080,这样连接到微林的端口转接,同时在本地启动了一个1080的sock5服务。
  • 设置浏览器的sock5代理,指向本地服务器的1080端口。
  • 如果你希望在命令行下面翻墙,可以安装proxychains-ng,OSX下面可以用brew安装。

2016-12-14更新:

ss翻墙中间网络传输的速度不行,我发现了kcptun这个神器,针对链路进行加速,看youtube高清视频一点问题都没有。

使用方法:

  • 在你的服务器上面安装kcptun,直接下载官方的二进制包就好。
  • 整体逻辑:服务器ssserver - 服务器kcptun - 本地kcptun - 本地sslocal,kcptun提供一个加速的链路,ss负责加密传输。
  • 服务器上面跑ss:ssserver -p 4431 -k sskey
  • 服务器上面跑kcptun:./server_linux_amd64 -t "127.0.0.1:4431" -l ":42871" -key "sharedkey" -mtu 1400 -sndwnd 2048 -rcvwnd 2048 -mode fast2
  • 本地机器上面跑kcptun: ./client_linux_amd64 -r "server.com:42871" -l ":4432" -key "sharedkey" -mtu 1400 -sndwnd 106 -rcvwnd 2048 -mode fast2
  • 本地机器上面跑ss:sslocal -s 127.0.0.1 -p 4432 -k sskey -b 0.0.0.0 -l 1081
  • 里面42871是kcp的端口,kcptun把服务器sserver的4431端口映射到本地的4432端口让sslocal访问。sharedkey是你kcptun本地和服务器共享的密钥,sskey是ss共享的密钥,server.com是你vps的地址,都要修改一下。其它的参数你感兴趣可以去官方网站上面看解释。
  • 打开浏览器,设置SOCK5代理,端口1081就可以了。

是否要用装修公司

| Comments

最近忙装修,装修公司挑了无数家。在我们这种四线城市, 很多人不会去找装修公司,而是自己找装修队伍,我不是很认同这种方法, 诚然,自己找装修队可以节省好几万的费用,但是钱不是这样省的。

装修过程有几个方面:

开始的格局设计:考虑什么房间做什么事情,里面的家具如何放置,动线,通风,采光什么的。 没有在这个阶段深入思考,装修出来发现问题再改就来不及了。某朋友自己装修, 完了才发现一个房间空调没有地方放,再打洞就会毁坏掉房间的装潢,很麻烦。 我们购买的是复式楼,在找设计公司的时候,群策群力,分别提出了各种的方案,比如考虑楼梯的位置,就有三种选择。 每种选择都有不同的功能区域划分,然后功能区还需要细化。如果不找装修公司,自己是想不到这么多方案的。

硬装:包括水电,木工泥工什么的。工程方面有很多很多的门道,自己可以去研究,弄清每道工艺, 但是再怎么研究,也比不上有经验的施工人员。施工的过程中也会出现一些突发状况, 需要有施工经验的人帮助参考。某朋友自己找施工队,楼顶敲出来三处,结果防水没有做好,返工了好几次, 损失的钱都可以找装修公司了。

软装:我们去过一些朋友家,自己装修和找人装修的效果区别巨大,很明显就认出谁的家是设计过的。 装修很花钱,效果好不好却很大程度体现在软装上面,一般人对空间色彩不够敏感,也没有很多的设计可以选择。自己装修,花大笔钱,最后却没有一个好的样子。 除非自己是设计领域的,软装最好还是找人把关,自己乱买东西最后搭出来一个古怪的风格。

总而言之,专业的事情交给专业的人员。不要什么事情都自己做。 大脑容量是有限的,多充实自己的专业知识赚更多的钱购买服务更划算。

至于行业鱼龙混杂,找不到好的装修公司,或者找到装修公司乱开价的问题,就是“战术”层面的问题了。

我的看法是:根据开销,选择对应档次的装修公司。普通人也不需要顶级的设计师和装修公司, 我觉得满足要求的就可以了(当然满足基本要求也需要挑好久)。最好是原先有经验的设计师出来单干开新公司,价格上优惠,人员也是有经验的。

至于装修公司乱开价问题,这种非标准化服务,没有办法横向比较,只能自己多研究,可以找一些连锁的公司,管理规范一些。 收费方面每个项目自己都要弄明白,这样才不容易被蒙骗。装修不能做甩手掌柜。

另外装修公司也是希望把项目做满意的,项目满意名气就更大,名气大了来的人多,收费也可以更高。 走上合作的道路对双方都有好处。

在项目过程中,顺利的沟通非常重要。 设计师能够提供专业领域的把关,但是生活方式和房子的风格还是只有自己清楚, 需要让设计师弄清楚自己的需求,而不是顺着设计师的思路,弄出一套样板房,自己住着不舒服。

更好的命令行

| Comments

命令行大家应该都熟悉了,但是命令行其实是很烂的, 输入和输出都采用字符串的方式,而不是一个规整的数据结构。 这样的后果是,每个程序都需要自己解析输入,以及提供一个特殊结构的输出, 很容易出现解析上面的问题。

从本质上面说,命令行就是一个函数执行的接口,终端就是一个状态机, 每一个命令就是一个函数。那么为什么不像通用的编程语言的函数一样来定义?

比如这样来写:

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
# 普通操作
$> date
=> "Sat May 23 09:18:38 CST 2015"
$> rm('/fdas/fdas/fda', directory: true, force: true)
=> true

# 输出结构化
$> ls
=> [{mode: 'drwxr-xr-x', user: 'halida', group: 'halida', size: 123, name: 'Gemfile.lock'}]
$> ls(columns: [:name, :size])
=> {name: 'Gemfile.lock', size: 123}

# 管道
$> history >> select{|row| row[:cmd] =~ /mina/ }
=> [cmd: {'mina init'}, run_at: '2014-02-01 10:00:21']
$> ls >> filter(:name)
=> ['Gemfile.lock']

# 很多命令应该用面向对象的方式来执行,更容易理解
$> master = git-get-commit('master')
$> master.files.count
=>3
$> master.committer
{name: 'James', email: 'james@gmail.com'}

# 输出日志就算是以文字的方式体现,也最好结构化起来,方便解析
$> log = log("Process file (filename) finished, spend time (spendtime)", filename: "xxx.mov", spendtime: 220.seconds)
$> log.spendtime
=> 220.seconds

网上搜索了一下,看起来没有什么好的解决方案,有时间我可以开发一个看看。

Rails导出数据经验整理

| Comments

最近做了一些rails数据导出的工作,就是把一些特定的ActiveRecord数据挖出来,保存到表格里面。 需要注意几件事:执行速度,内存消耗,以及调试速度。

执行速度

导数据的程序基本上就是一个循环体,外部获取数据集,内部把一条数据转换成表格。 在内部,往往需要通过一条记录作为主体,通过数据库逻辑关系顺藤摸瓜挖出一批数据, 这样会形成一批短查询,因为是在循环体里面,会带来很大时间上的消耗,比如:

1
2
3
4
out = []
Unit.where("active_at" < Time.now).each do |unit|
  out << [unit.company.name]
end

可以先把这些查询汇总起来,一次查询掉,然后在循环体内部筛选出对应的数据:

1
2
3
4
5
6
out = []
units = Unit.where("active_at" < Time.now)
company_names = Company.where(id: units.pluck(:company_id).uniq).pluck(:id, :name).to_h
units.each do |unit|
  out << [company_names[unit.company_id]]
end

内存消耗

查询大量数据的时候,可以首先查所有的ID,然后分批查询,这样防止序列化大量的数据库对象:

1
2
3
4
5
6
7
unit_ids = Unit.where("active_at" < Time.now).pluck(:id)
group_size = 100
unit_ids.in_groups_of(group_size, false) do |ids|
  Unit.where(id: ids).each do |unit|
    ...
  end
end

数据全部缓存在一个array中的话,会占用大量内存,最好是通过数据流的方式一个个输出处理,用后即丢:

1
2
3
4
5
6
7
8
9
def export
  Unit.where("active_at" < Time.now).each do |unit|
    yield([unit.name])
  end
end

CSV.open('out.csv', wb) do |csv|
  export { |row| csv << row }
end

在循环体内部,尽量用局部变量,不用的资源会更早释放。

跑数据导出的时候,最好同时注意一下服务器的剩余内存。不要把其它服务搞挂了。

调试速度

导数据最花费时间的往往还是调试过程。

调试的时候,可以只返回几条数据,检查完毕之后再全部跑。

1
2
3
4
5
6
7
debug = true
index = 0
Unit.where("active_at" < Time.now).each do |unit|
  yield([unit.name])
  index += 1
  break if debug and index >= 10
end

需要考虑数据并不是很规整,做好预防性编程。

1
2
3
Unit.where("active_at" < Time.now).each do |unit|
  yield([unit.company.try(:name)]) # 公司可能不存在
end

很多时候难免特定数据不符合预设状况,最好循环体内部记录log,出现问题可以跟踪。 比如下面的例子,unit没有oldest_driver的时候,会报错,记录了日志,就知道在哪条上面出现了问题。

1
2
3
4
5
6
7
logs = []
Unit.where("active_at" < Time.now).each do |unit|
  logs << "unit: #{unit.id}"
  oldest_driver = unit.drivers.order('age desc').first
  # 
  yield([ordest_driver.name])
end

导出数据可以生成两个版本,一个给客户,另外一个加上一些debug数据方便自己分析。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def export
  Unit.where("active_at" < Time.now).each do |unit|
    yield([unit.name, 'debug', unit.id])
  end
end

CSV.open('out.csv', wb) do |csv|
  CSV.open('out_debug.csv', wb) do |debug_csv|
    export { |row|
      debug_csv << row
      csv << row[1..1]
    }
  end
end

架构设计

代码架构上面最重要的是职责清晰。导出数据的逻辑比较简单,分离出导数据类,以及处理数据类就可以了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
module Exporter
  def iterator_to_csv(filename, iterator)
    CSV.open(filename, wb) do |csv|
    iterator.call { |row| csv << row }
  end
end

class ExportActiveUnits
  attr_accessor :time
  def export
    Unit.where("active_at" < time).each do |unit|
      yield([unit.name])
    end
  end
end

eau = ExportActiveUnits.new
eau.time = Time.now
Exporter.iterator_to_csv "out.csv", eau.method(:export)

学习ASP.NET心得

| Comments

因为现在公司的一个网站项目是用ASP.NET写的,我周末抽时间学习了一下相关的概念,对于ASP.NET有了一定的了解。 学习过程就是看一遍W3School的教程。 我没有下载Visual Studio实际编写,因为只需要能够看懂项目代码就可以了。

总体来说,我觉得微软的技术有这些特点:

复杂:微软为了让普通程序员能够上手,做了大量的工作,集成在Visual Studio里面。 你用微软的集成环境,按照教程一步步做,就可以跑出来一个东西。但是在这个过程中,你会发现接触到一堆微软特有的概念,以及用到大量微软设计出来的工具。 可能有的人认为微软的东西比较简单,刚刚毕业的大学生就可以拖拉出来一个东西。但是仔细看看,就会发现微软的东西非常复杂,每一步都隐含了大量的复杂度。 微软有自己的设计思路和概念,但是感觉挺别扭,要么是离本质有点远,要么是文档讲了一堆,你还是搞不清楚它到底是什么。

既定路线:如果按照微软设计的路线走,可以很快开发出来一个东西,但是如果需要定制,就会面对重重阻力:工具和库假设你会按照这条路走。 如果说这条路线很顺也就罢了,但是我感觉微软的设计总是不够好,感觉有些偏门,不是“大道”。

依赖:学习一个东西,牵连出来需要学习一整块的东西,而不是单独学习一个内容。同时用了微软的一个工具,就要用微软的一套工具。 这是微软的赚钱战略,如果只生存在这个环境里面就没有什么问题,但是眼界宽一些,感到被限制住就有点难受了。

学习曲线:使用微软提供的解决方案,能够很快进入状态,写一个东西出来,比单独组合工具学习曲线低。 但是再更深一步就很困难,学习曲线就陡峭起来。这里面就有一个平衡:选择更强大的工具,还是更容易理解的工具。 更强大的工具能够更快,但是带来了更多的复杂度,复杂度过高,人就无法控制了。

现在用微软解决方案的人越来越少,这是好事。作为程序员其实自主选择容易被大环境控制,其他人如果都用一个烂工具,很难独善其身。 你不可能采用一个很少有其他人会用的技术,一个是技术成熟度需要程序员的时间去堆,另外一个是项目不是一个人的事情,要有其他人一起做,或者至少能够找到维护人员。

微软的操作系统也是,国内基于微软的生态系统乱七八糟,作为程序员自己可以用linux或者apple的生态圈,但是总是免不了被其他人拉回来, 重装系统,解决问题。看到操作系统差劲的用户体验,漫天飞的木马病毒,大大小小的流氓软件,死活找不到东西的搜索引擎,不由觉得普通人真辛苦。

用chef对少量服务器进行配置管理

| Comments

原先介绍了chef,现在需要面对一个实际的问题:如何用chef管理少量的服务器。

我希望:

  • 能够对几台或者十几台服务器进行配置管理。
  • 针对每台服务器,写yml格式的配置文件,执行一个命令之后,就可以配置好这台服务器,同时源码管控这个yml文件的变更。
  • 支持复杂的服务器配置,包括启动项目管理,自动告警,日志归总等。
  • 不需要管理服务器,比如chef-server这样的东西,只需要留有本地的配置文件。

我采用的解决方案:

  • littlechef,这个项目可以把chef-solo,一个本地跑chef的方法,部署到远端服务器上面去,同时拷贝本地的recipe和配置文件到远端,执行需要的操作。
  • 写recipe,让部署能够通过写node配置文件进行配置,比如启动服务,日志归总,服务器管理员用户,自动重启更新等。
  • 用yml格式撰写node配置文件,以及datatag配置文件,然后用自动化脚本转换成json格式。手动写json太反人类了。
  • 远端的脚本用ruby写,脚本里面的参数不是用erb渲染出来的,而是把配置序列化成yml,ruby脚本再读取它们。这样远端服务器上面的执行代码是规整的,人可以阅读。

都弄好之后,可以写这样的服务器配置文件:

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
39
40
41
42
43
44
---
  # 服务器名字
  name: "test"
  # 基础配置的recipe
  base-system:
    # 是否跑软件包更新
    update: false
    # 是否设置自动更新
    auto-upgrade: true

    # base-system会自动创建一个deployer管理员用户,谁可以通过公钥的方式访问这个用户
    authorized_keys:
      - "linjunhalida"

    # 写在databags里面的配置参数,可以连接到slack发提醒
    notify: 'test'
    # 是否每天判断服务器是否需要重启或者更新
    check:
      need_reboot: true
      need_upgrade: true
    # 设置服务器定期重启
    schedule-reboot:
      minute: '26'
      hour: '8'
      weekday: '2'
    # 设置服务器自动升级安全更新
    schedule-upgrade:
      reboot: true
      minute: '1'
      hour: '0'
      weekday: '1'
    # 服务器启动的时候跑的应用
    start:
      - name: "railsapp"
        user: 'deployer'
        pwd: '/home/deployer/apps/railsapp/current'
        cmds:
          - 'bundle exec thin restart -C config/thin.yml'
          - 'RAILS_ENV=staging bundle exec rake resque:restart_workers'
          - 'RAILS_ENV=staging bundle exec rake ts:restart'

  run_list:
    - "recipe[chef-solo-search]" # so chef-solo search can work
    - "recipe[base-system]"

chef部署之后,会创建目录/etc/base-system,里面存放各种配置和执行脚本,同时安装到crontab,/etc/rc.local等各种地方。 服务器的关键操作,比如重启,安全更新结果,都会通过notify功能汇报到slack上面。 我可以通过node配置文件,清晰看到每台服务器是如何配置的。并且这个系统可以演化,更换一种配置方式,只需要重新跑一下部署。

不过还是有一些难办的问题:

  • littlechef项目成熟度不高,使用起来不是很舒服。
  • 架构复杂:chef已经很复杂了,远端还要部署一个ruby环境,架构复杂带来调试和理解上面的难度。
  • 学习成本高:维护者需要弄懂chef,远端编织起来的ruby框架,之后才能配置服务器,最后可能只是需要加上一个小东西。
  • 维护成本:又多了一个项目了。