• 用syslog-safer 保证syslog永不阻塞

    日期:2013-07-18 | 分类:编程

    syslog 是 linux 标准的日志接口,用户可以调用 syslog 函数族(man 3 syslog)来打印日志。本质上syslog 是客户端,它通过 unix 域套接字(man 7 unix)/dev/log 和服务端通信,服务端有多种实现,syslog(同名的服务端程序),syslog-ng,rsyslog 等。习惯的做法是,服务端收下日志后,再把日志推送到日志中心去。

    这里syslog和服务端通信是同步过程。如果服务端响应慢(由于自身设计或者日志中心接收不稳定),syslog 也会受到影响,从而影响业务,尤其是服务端把日志汇总到中心服务器时,问题尤其严重。为了避免服务端慢影响客户端,开发了一个“快速通道”程序,它保证以最快的速度接受syslog输入的日志,用额外的线程输出到syslog服务端,保证syslog函数永不阻塞,它相当于一个缓冲地带,必要时甚至丢弃日志。这里syslog服务端必须能接受配置一个不同于/dev/log的地址。原流程是 syslog -> /dev/log -> syslog-ng,增加syslog-safer后的流程是 syslog -> /dev/log -> syslog-safer -> /dev/xlog -> syslog-ng 

    另外,使用apache服务器,习惯用pipe log的方式通过logger把日志写入syslog,logger程序在centos5下有问题,当日志长度大于1024 时,会截成两条,不利于日志分析,syslog-safer 附带了一个 logger 程序,克服了标准logger的问题。

    syslog-safer 已开源,地址是:https://github.com/zzyongx/syslog-safer

  • 桃花雪

    日期:2013-03-20 | 分类:往昔

    早上5点半起来搞事儿,到7点时也没搞出名堂,满脸沮丧,双眼迷蒙,准备洗脸去上班,发现窗外的树枝变白了。还以为是“东风夜放花千树”,莫不是玉兰开了?仔细看,才发现是昨天的雨,在夜间变成了雪。3月末的雪,赶在春分前落下,竟成了这个冬天最大的雪,和着明媚的阳光,让人无法直视。

  • 双11

    日期:2012-11-11 | 分类:往昔

    昨天北京下了雨,晚上的时候开始刮风,无眠的我躺在床上,听风一遍遍的吹过树梢。本来想,早起推窗,外面必是黄叶铺地,草木萧萧。其实不然,枝头依然绿色葱葱,想必是时节不到,纵然又是雨又是风的,也奈何不得。

    双11,据说淘宝的流量又破了纪录,成交额也是天量,只是单身的人依旧单身,眷侣们在忙着购物。表白被拒的后,你会觉得以前的日子都白过了,会不知道明天该做什么?

    本想早早睡去,在梦中和追求过的妹子相遇,遇到那个算那个。结果是很晚才睡着,中意的人一个也没梦到。

    今天是个晴天。

  • WEB服务器IO高两则

    日期:2012-10-16 | 分类:编程

    1. WEB服务器上有大量的文件,在机器重启后,有短暂的IO高,因为OS的文件缓存是冷的,运行一段时间后IO会慢慢降低。

    2. WEB服务器负载100以上,负载均衡连接WEB服务器大量超时。依旧是IO高,直接原因是OS内存不足,程序所用内存不断抢占OS的文件缓存,原来的热文件缓存被丢弃,文件变成了冷的。并且swap也消耗了相当的IO。因为WEB服务器访问外部资源阻塞,导致httpd进程数量增大,最终耗尽了系统内存(500个进程,每个20M,就要10G以上的内存)。

     

    第2个问题排查了很久,没想到OS内存不足和IO的关系。报警没做好,也占很大的原因,如果在内存消耗70%以上的时候报警,问题排查可能就快很多。

  • 看着题目挺高端的,其实讲了个什么事儿呢?就是重庆人民唱红歌唱烦了,决定花点银子,请一些国外的艺术家,来重庆搞创作(要以重庆为题材),和重庆当地的艺术家做交流。关于艺术,主讲人石甜开场说,在拉萨一个月没洗澡洗头,有人见面打招呼说,你是艺术家吗?俺心想,这不修边幅和蓬头垢面还是有点差距的吧。通过石甜的讲解和课后的讨论,我大概理清了点东西,以下内容绝对有胡诌的成分(主要是绘画方面的艺术)。

     

    艺术家这个称呼其实是敬称,准确的说法,应该是艺术工作者,这跟搞科学的不能都叫科学家一样,尤其是不能自封艺术家。遥想某些同学小时候学习不好,又想考个大学怎么办,可以剑走偏锋,考艺术类院校。大学毕业了,总得找个工作混口饭吃,又不会别的,只好搞艺术创作。这么讲有点大不敬,因为很多艺术家是发自内心热爱艺术的,尤其是那些后来转行搞艺术的人。他们心里有话要说,有思想要表达,不然憋的难受。可能文章写的不好,搞音乐又不行,也不会说相声,也可能觉得这些都没有绘画有力量,于是开始搞绘画。

     

    外地人来北京称为“北漂”(7.21大水真能把人飘起来),在重庆有个“黄漂”,指在四川美术学院所在地“黄”桷坪出现的一个艺术创作群体。不管做什么,“吃饭”都是个大问题。艺术这个事又不靠谱,很多艺术家都是死后成名的(更多的死后也没成名)。说白了,搞艺术跟搞研发是一个道理,无论成败,都需要前期投入(某些艺术,尤其是行为艺术,很烧钱,2万3万的很快就没了。材料,场地,租器械等),前期谁投入?一是政府或者非政府的艺术基金会资助一些艺术从业者,二是很多半路出家搞艺术的,之前有积蓄(国外有些人先做投行,会计,赚很多钱,然后才搞艺术),三是做大众绘画,比如给幼儿园画点卡通啦(据说这个来钱很快,一次好几万),在街边摆个摊画肖像啦。

     

    艺术家受金融危机影响很大。经济形势好的时候,有人有钱,整墙整墙的买画。据说有画家一年卖画卖100万的。经济形势不好的时候,三年也卖不了30万。要这么说,艺术就不那么阳春了。无非是大众卖汽车,艺术家卖画而已,混口饭吃嘛。汽车带来生活的便利,画作带来某种精神的满足。但不乏天赋异禀者,只考虑表达自己的思想(在他们眼里,画只是手段),吃饭等闲事,不放在心上。至于艺术家的社会使命,我觉得考虑它,就跟说相声的考虑相声的社会使命一样,没有必要。艺术家的作品只要忠于艺术家的思想就行了。

     

    在记录片“苏维埃的兴衰”中讲到列宾的一幅油画“意外归来”,如果不是嘉宾讲解,光让我看,我啥也看不出来。但嘉宾一讲,竟也觉得画的实在太好了。

  • “读”程序读什么(2)

    日期:2012-08-09 | 分类:编程

    1. 检查运算符的优先级,p为指针,*p++ 和 (*p)++ 是截然不同的。不确定优先级,就加括号。

    2. 递归调用,注意是传值还是传指针(引用)

    3. 递归调用,注意递归的深度。尾递归没有深度限制。

    4. 注意临界区的代码。写操作优先保证数据的正确。读操作优先保证系统的可用。

    5. 检查竞争条件。如果某个线程需要根据其它线程的状态做操作,竞争条件就出现了。逻辑上的原子操作,如果无锁,也存在竞争条件。

    6. 检查变量的类型,你可能把int型定义成了bool,这通常来自大意。

    7. 检查new[] 出来的对象,是否使用delete[] 释放

    8. 在启动线程前分配的资源,应该在线程退出(pthread_join)后再释放。

    9. 如果升级为多线程,要留心之前不需要担心的线程安全问题(例如,为了简单,某些实现为线程不安全的函数)。为了升级考虑,所有线程不安全的函数,在初次开发时就要标识为非线程安全。

  • recv函数的MSG_PEEK标志介绍

    日期:2012-08-06 | 分类:编程

    考虑下面的场景,server向client发送数据"_META_DATA_\r\n_USER_DATA_",要求"\r\n"之前的数据_META_DATA_在第一次recv中接收,剩下的recv调用读取_USER_DATA_部分的数据。因为tcp是stream协议,并且_META_DATA_数据不是定长的,所以没有办法保证一次recv调用不读到_USER_DATA_部分的数据,除非一次读取一个字符。这种场景下,recv的MSG_PEEK参数就发挥作用。

     

    recv的原型是ssize_t recv(int s, void *buf, size_t len, int flags); 通常flags都设置为0,此时recv函数读取tcp buffer中的数据到buf中,并从tcp buffer中移除已读取的数据。把flags设置为MSG_PEEK,仅把tcp buffer中的数据读取到buf中,并不把已读取的数据从tcp buffer中移除,再次调用recv仍然可以读到刚才读到的数据。

     

    针对上面的场景,recv(fd, buf, nbuf, MSG_PEEK) 查看数据,查看"\r\n"的位置pos,再recv(fd, buf, pos+2, 0) 读取(并移除)数据。

     

    上述场景描述的比较极端,毕竟很多时候,就算在一次recv中读到了_USER_DATA_部分的数据,仍可以先把这部分数据保存起来,添加到后续的recv数据之前,但是如果不同的recv跨越很多函数,保存数据带来了额外的复杂度。还可以考虑另外的场景,同一个端口支持文本协议和二进制协议,利用MSG_PEEK看一下头几个字符,先判断是文本协议还是二进制协议,再做请求分发,也是不错的选择。当然,真正的recv之前调用使用MSG_PEEK导致额外的一次函数调用。

  • 公司周边记事两则

    日期:2012-08-04 | 分类:往昔

    昨天晚上跟两个同事去“走西口”吃饭,有3年没去那吃过了,原来10块钱一碗臊子面,现在14,但是碗大了很多,手工面换成了机器轧的,没以前好吃了。座椅板凳还是原来那样。

    今天晚上跟一个同事去“东来顺”打台球,原本想在“桥香园”吃米线,不想竟然关门了,大概也有2年没来这吃过饭了。台球室比以前装修的好多了,以前15一小时,现在20。

    这几个地方都在公司附近500米内,我刚工作那年,跟着小组的前辈,经常在这附近吃饭。那时平均一顿饭要20,觉得好贵。后来的小组,没了一起出去吃饭的习惯,自己就在附近的一个“大食堂”,一吃就是3年。这两天,一起出来吃饭,玩的同事,竟都是小我3到4年的人,周边这些地方,也都不是我记忆里的模样。

    时光真快,还好,往事都是愉快的回忆。

     

  • 一句话说云安全

    日期:2012-07-27 | 分类:编程

    安全的核心是对资源的争夺。资源分两类,一类是授权资源,一类是非授权资源。对授权资源,要做统计。对非授权资源,要做隔离。对非授权资源的访问,和对授权资源的滥用,都视为对安全的威胁。资源分类:filesystem,cpu,memory,net。

  • 那场一个人看的海

    日期:2012-07-21 | 分类:往昔

    2012年7月21日,星期六,农历六月初三日。那场一个人看的海。

    同事说要介绍一个姑娘给我认识,姑娘是她室友,也是单身,更兼仰慕同事厨艺许久,今日前去叨扰。令人印象深刻的,既不是那位姑娘,也不是同事的厨艺,而是这场雨,大雨如注,浩浩荡荡,到现在已经持续了10个小时,北京城一片汪洋,是的,可以看海。

    我把鞋留在同事家,穿着他的拖鞋,就进入了这场雨,此时已天黑。一起在外吃饭毕,我乘城铁回家。在同事的小区门口,水淹没了整片路面,包括马路,人行道,在路灯的辉映下,这浑浊的水,一望无际。挽裤腿及膝,方能行。汽车在水上行驶,冲开水面,就像破浪的船,车挤压的水涌向路边,像一层浪,拍打小区的围墙。很多车停在路边,估计车里已经进水。

    出五道口城铁,水复如是,除了稍浅。五道口繁华,霓虹依旧闪烁,有车停在路中央,再也无法动弹,与其说是抛锚,不如说是搁浅。本来准备转乘公交回家,可是我望望这水,觉得等车不若步行,既然已半湿,就不在乎再多淋一点。毕竟这雨,不是每天都有的。

  • 使用DIRECT IO的注意事项

    日期:2012-07-11 | 分类:编程

    1. 打开文件使用 O_DIRECT 选项。

    2. IO函数(read/pread/write/pwrite)的buffer地址,必须对齐到文件系统逻辑块。

    3. 操作文件的offset必须对齐到文件系统逻辑块。

  • 用 nc 做桩接口

    日期:2012-05-24 | 分类:编程

    本来准备起名“巧用 nc 做桩接口”,仔细想想,这个大概是程序员们喜闻乐见的一种用法,就不自诩“巧”了。“桩接口”的概念类似“桩函数”,这里的“桩接口”是几个TCP交互。

     

    Le7 需要跟第三方系统X-Port交互,交互细节是:client请求Le7,Le7检查到配置为X-Port,转发请求到X-Port,X-Port接到请求,做若干操作后(这个是X-Port的逻辑)后,通过Le7的接口,将Le7的配置改为R-Port,然后断开Le7来的连接(或让连接超时)。Le7视此为错误,重新加载配置,将请求转发到R-Port。

     

    Le7开发完成后,需要“桩接口”测试。“桩接口”要能够1. 接受请求,2. 调用Le7的接口,3. 断开Le7的连接(或让连接超时)。可以写一个简单的TCP Server做“桩接口”,但是用nc更简单。

     

    1. echo -e "set zzyong_pool 0 0 6\r\n127.0.0.1:9090\r\n" | nc 127.0.0.1 11211 设置 Le7 的配置为X-Port,X-Port这里是127.0.0.1:9090

    2. nc -l 9090 -k  模拟 X-Port,接受Le7的请求,等待超时。

    3. curl "http://127.0.0.1/ut.php" -H "Host: x.le7.io" 模拟client请求Le7,Le7将此请求转发给X-Port

    4. echo -e "set zzyong_pool 0 0 6\r\n127.0.0.1:8060\r\n" | nc 127.0.0.1 11211,在Le7超时前,模拟X-Port,设置Le7的配置为R-Port,R-Port这里是127.0.0.1:8060

    Le7 请求 X-Port 超时,重新加载配置,这里为R-Port,将请求转发给R-Port。

  • 关于竞争条件,记一次故障处理

    日期:2012-04-18 | 分类:编程

    为了省点内存,最近升级了pvuip统计系统,采用BloomFilter代替std::set。这次升级准备非常充分,旁路3天,运行正常。升级后,就没管它。

    今天早上查看报表,发现自昨天升级之后,就没有统计数据。真是晴天霹雳。日志显示统计没问题,统计数据写入文件也没有报错,但是为什么文件中没有昨天的数据呢?线上gdb,发现写文件的相关函数根本就没有调用(怪不得没有报错呢)。情急之下,只好先重启程序,重启后有统计数据写入了。程序bug是不可能通过重启解决的,问题出在哪呢?

    因为升级前,系统空闲内存很少,所以怀疑重启时写统计数据的线程没有启动成功(多可笑,升级前先停老程序,内存就释放了,跟空闲内存很少有什么关系呢)。查看线程数,不是预期中的101,而是53。线程没有启动?不可能,如果没启动直接就抛异常了。gdb发现,线程启动之后,很快就自动退出了。检查线程执行逻辑,发现了一个竞争条件。

    线程池启动函数,在创建所有的线程后,会将线程池的状态置为Run,在这之前线程池的状态未初始化。而线程池中的线程根据线程池的状态是否为Run,判断线程是否退出。因为线程池要启动很多线程,因为有很多cpu,所以在线程池设置状态为Run之前,很多线程运行,并退出。但是大多数时候,线程池里面的线程不会全部退出,所以程序可以正常运行(并在系统负载重时,因为线程数不足而出问题)。只是昨天比较极端,线程池里面的线程全部退出了。

    教训:1. 注意竞争条件。2. 查看进程状态时,查看线程个数是否和预期一致。3. 查看程序接口/输出/日志,以结果为导向。
  • 4月3日 车耳营-大风口-电线塔穿越

    日期:2012-04-12 | 分类:往昔

    这是一次非常难忘的穿越,经历了生死考验。很久没见嗨哩和玲子了,他们都装备了手台,鉴于玲子同学的背包没办法挂手台,手台就挂在我包上,没有手台壮胆,我是断然不敢胡来的。

    从车耳营村走上去凉水背的公路,我们碰上了久违的看山大爷。大爷表示,封山时期,严禁上山。我表示,同意同意。继续套近乎,我表示我们身上都没有带火,不会引起火灾啥的。大爷铁面无私,就是不让进。我们只好往回走了几步,从边上的小道绕到大爷背后,上山了。

    要不是这次出来,我都不知道桃花开了。通往凉水背的山谷里,仍有厚厚的冰,可以站人跑马。路上碰到从凉水背下来的背水的大妈大爷,就问他们怎么通过看山大爷“防区”的,他们说,你就跟他磨,总可以过去。他们每周都来这里背水,一次背30升左右,这里是纯天然的泉水,煮粥,泡茶都别有滋味。想必是跟看山大爷混熟了。过了凉水背的水源头,切到右边的沟里,往大风口走。

    受厚厚的冰吸引,我们走到了只有冰没有路的地方。我踏过冰,去前面看路。路并不清楚,但是有人系的红绳,根据经验,这通常是有路的。走了100多米,也没看到更清楚的路。此时嗨哩和玲子往回走,找到了去大风口的路。我没打算往回走,我觉着沿着红绳,可以和嗨哩他们会合。我犯的第一个错误是,我知道路应该在右手边,但是我并没有刻意往右边靠。第二个错误是,没有红绳,也没有路时,没有果断回撤。

    走远了,就会有一种错觉,认为继续走“野路”上正路,和往回撤上正路的代价是一样的。越走就越发现这不是人走的路,也许这是路,是动物们走的路,据说这里有野猪。有时候还有似是而非的路,有时则完全是拨开藤枝开路。登上一块突出的大石头,我看见一条清晰的小路,只是我跟这条路隔着一条沟,要走过去是不可能的了。只能继续向上,只要到山顶,就有路了。我此时很忐忑,怕碰到野猪,虽然知道野猪不吃人。看见六道木的时候,我心中充满了希望,六道木只在海拔超过1000米的地方才有,说明我的位置已经很高了。当我奋力“到顶”的时候才发现,这只是一个局部的顶,真正的顶还有300米,登真正的顶之前,我还要先下一段。我绝望了,置身于无边的藤枝中,没有路,只有手台跟嗨哩联系。任何一个闪失,都可能让我长眠于此。不能继续往前走了,可是回撤的路在哪里呢?山都是有沟的,这个沟是下雨流水的地方。我快速找到了这个沟,并沿着沟往下走,沟比较好走,没有藤枝什么的挡道。这条沟肯定没人走过,我一脚踩到树叶上,树叶直没膝盖。我这时主要担心脚崴。沿着沟终于撤到山谷里,心算稍微平静了一下。

    继续沿着山谷,回到了和他们分手的地方。本来打算就此下山的,“野路”已经把我折腾的精疲力尽了。但是嗨哩他们也不打算走了,为了不影响他们,我决定去大风口追他们。终于在2点半左右追上了他们,他们正躺在路边晒太阳呢。继续的路就没什么特别了,只是今天的风特别大,大到跟本无法站立,大到玲子要拽着嗨哩才能走路。

    过了电线塔,才感觉不到风了,耳边没有了那种呼呼的风声,感觉好安静。到346车站,排队等车的人已经有100多米,可是有好几个人并排的100多米呀。我估计此时有人敢插队,都没人可以保证他的人身安全,非被唾沫淹死不可。我们排无座的队,还好,抢到两个车轱辘。还管形象,先坐下歇会再说吧。
  • 我怀念苹果园的煎饼。6点45我出苹果园地铁,花了10分钟排队买,此时离948开车还有5分钟,我跑着去车站的。单说公交,这一定是我坐过的最挤的公交,没有之一。快要清明了,有很多人提前去京郊扫墓,人比以往更多一些,何况,如果不坐头班车,就得等9点的那趟了。

    我没有座位,这并不算什么,因为在接下来的几站,将会有很多人连车都上不了。大山没赶上车,我们建议他打出租追公交,幸运的是出租车司机不知道948的线路,如果出租车追上了我们,大山还是上不了车,车上一点空间都没有了。大山对山有着很深的感情,他碰上了绿野的队伍,跟着他们从灰地上铁陀山,我们最终在山顶汇合,感谢手台。

    我对铁陀山比较畏惧。这是任老师失踪的地方,前年我从灰地上铁陀山,脚第一次负伤,至今未彻底痊愈。今天风很大,可以在1分钟内将一个大汗淋漓的人吹的手脚冰凉。这次,我登上了铁陀山顶,海拔超过1000米的山上很多都有个铁架子。

    这次穿越累计爬升1100米,行走27公里,使用了刚买的山杖,没感觉特别累。
  • memcached 使用的若干问题(1)

    日期:2012-03-30 | 分类:编程

    1. memcached 将内存分成若干大小按比例增加的slab,LRU 是在slab内进行的。

    2. 系统启动时,给各个slab预分配一定的内存。剩下的内存(A)不属于任何slab。当某个slab内存不足时,从(A)中分配,分配之后就永远属于该slab了,如果(A)中没有内存,则该slab上发生LRU。这也是给各个slab预分配内存的原因,防止slab需要内存从(A)中分配时,(A)中无内存可用,预留的内存保证了该slab上有至少有预留内存可用。

    3. memcached 运行一段时间,(A)中内存必然耗尽,如果在此之前,某个slab从来没有存储过数据,那么该slab上可用的内存就是预留内存,这导致如果该slab突然需要存储数据,该slab发生LRU的概率就很大,因为预留内存很小。举例说明:memcached中存储的都是很小的数据,小数据slab很快耗尽了(A)中的内存,如果要存储大数据,大数据所在的slab只有预留内存可用,而预留内存通常很小,导致大数据频繁的LRU,这通常严重影响性能。

    4. 客户端通过hash使用memcached池,存在某个key导致某个memcached实例负载/IO高的可能。例如,某个key存放的是大数据,该key的访问量很大,那么这个key所在memcached网络IO会比其它机器高。

    5. 一个用户反映它的mecached的内存使用率不足50%,但是某个key经常刚set进去就get不出来。这个memcached池有4台memcached组成,我随机挑了两台stats,的确没有LRU发生。我换了另一个key,重现该问题。这是怎么回事?我想了很久,最后老老实实的在每台机器上stats,发现有一台机器的内存使用率很高,这台机器有LRU,我和用户的key都落在了这台机器上。因为其它3台机器最近重启过,这导致整体的内存使用率看起来很低。

    6. 我觉得redis也免不了这些问题。
  • 德胜门集合,大队人马坐872,我和博乂坐345快。345快的发车间隔很短。上车前看地图有些大意,345终点站可以倒昌32,但是345快不可以。必须在昌平南大街倒车到昌32起点。我们也没有坐过,下了345快后,一直找新华书店,据地图说那里可以坐昌32。走了10几分钟,没找到新华书店,倒是看见个早餐店,还是吃饭要紧。饭后,看了看边上的站牌,有昌32路,非常高兴。车站等车的一个阿姨说,昌32路,7点,8点各一趟,8点后是半个小时一趟。当时正好是8点,等了片刻,车就到了。在车上看到很多伙伴。

    这次活动有40多人参加,车上有9个,也就是说坐872到常陵的还有30多个,公交车已经很满了,这30多人指定上不全了。果然如此,为了不耽误行程,没上车的人就租了个小面。据说,司机是从被窝里叫出来的。

    望宝川是长寿村,估摸着跟风水有关。今天雾很大,百米之外就看不清了。从银山塔林下来将近11点,雾似乎更大了。这个地方栗子树很多,离子成熟的时候,很多人来这捡栗子。我第一次知道原来栗子的最外面还有个壳,并且是带刺的。我们还偶尔能拣着几个别人漏下的栗子。往东水峪走的时候,有点不妙,具体说是迷路了,走上一条不是路的路。迷途知返,耽误了不少时间。大雾天,稍微不留神,就错过了正确的路口。

    这是我见过最大的雾,空气里可以攥出水来。本来计划是A队在东水峪上莽山走十三陵水库,由于天气糟糕,A队取消,一起B队。走到常陵的时候,很多人就坐872回去了。最后走完全程的有10个人。夕阳中的十三陵水库,特别漂亮。很多人背着沉重的相机,准备拍照呢,天气不作美,啥也没看到。十三陵水库边上有一对老外在露营,这天实在不适合。

    坐朋友的车,在昌平吃了饭,朋友送我们回的家。到家时,雨已经下的不小了。第二天望窗外,银装素裹。此行,爬升700米,行走27公里。
  • 这就是传说中的拖延症吧,2月26日的穿越,3月9日才写记录。

    7点在六里桥北里坐到燕化东岭的901快,到大董村换乘房32到泗马沟。在大董村等了40分钟车,还是赶在9点前到达泗马沟。公交距离还算可以,不算太远。

    泗马沟也是穿越者的老朋友了,通常都是从左手上到红螺三险,这次是从右手上去猫耳山。一开始就是一个1000多米的直拔,赶在11点之前到达山顶,从山顶到三盆水,路非常难走,有的路段贴着悬崖,有的要手脚并用上。也难怪去年清明,一队人被困在猫耳山,靠直升机救援。从山上下来都7点半了。累计爬升1450米,行程23公里。

    我一直很奇怪,北京周边的这些小山村,村里也没什么经济基础,却很有钱,他们是怎么发家致富的。这次算是有点眉目了。靠山吃山。山上有很多的采石场,随便找个山头,几炮炸下来,一车车的石头就是一沓沓的钱。房山的采石场很多,门头沟的煤矿很多。都是来钱的项目。
  • 2月19日 八达岭-居庸关徒步

    日期:2012-02-25 | 分类:往昔

    7点半从西直门坐S2到八达岭车站,依次游览岔道城,八达岭博物馆,青龙桥火车站,水关长城,关沟,居庸关。步行16公里,途中无上升。

    岔道城是一个古老的村子,09年被评为北京最美乡村,是明代军事设施遗址。现存的城墙,已经部分毁坏,从毁坏的剖面可以看出城墙的构造过程。村子边上有万人坑,是日本人做的恶事。万人坑左侧路边沟里是出京古道,慈禧逃离京城就是走的这里。

    八达岭博物馆是了解长城历史,文化最好的地方。有历代出土文物,全国各地的长城照片。参观八达岭长城前,先参观八达岭博物馆是一个不错的选择,博物馆是免费的。

    青龙桥车站是詹天佑设计的“人字形”铁路,列车变轨的地方,有詹天佑塑像和詹天佑夫妇的墓。詹天佑塑像底座写着“詹公天佑”,能被人称为“詹公”,莫大的荣耀。

    水关长城是由戚继光督建,迄今400年历史,长城边上有詹天佑故居,其实一个很小的三合院。我们在这里吃的泡面。

    关沟72景,现在好多景点都找不到了。我们一路大概看了有20来处吧。

    徒步终点居庸关,一座天桥横跨八达岭高速,关口几个大字,天下第一关名副其实。

    这次徒步,感觉脚上的伤还没好。自然调养已经不行了,需要搓红花油,加快康复进程。
  • 使用libcurl POST数据和上传文件

    日期:2012-02-10 | 分类:编程

    为了具有通用性,将文件的内容读到了fc变量中,fclen是fc的长度。fc也可以是任何其它内容。curl 是 libcurl句柄。演示省略了很多显而易见的步骤。

    1. 普通的post请求,这里用curl_easy_escape对fc做了编码
    std::string data("req=plain");
    data.append("&file=");
    char *efc = curl_easy_escape(curl, fc, fclen);
    data.append(efc)
    curl_free(encoded);

    curl_easy_setopt(curl, CURLOPT_URL, PURGE_URL);
    curl_easy_setopt(curl, CURLOPT_POST, 1L);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
    curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, data.size());

    2. multipart/formdata请求
    struct curl_httppost *formpost = 0;
    struct curl_httppost *lastptr  = 0;
    curl_formadd(&formpost, &lastptr, CURLFORM_PTRNAME, "reqformat", CURLFORM_PTRCONTENTS, "plain", CURLFORM_END);
    curl_formadd(&formpost, &lastptr, CURLFORM_PTRNAME, "file", CURLFORM_PTRCONTENTS, fc, CURLFORM_CONTENTSLENGTH, fclen, CURLFORM_END);

    curl_easy_setopt(curl, CURLOPT_URL, URL);
    curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
    curl_easy_perform(curl);
    curl_formfree(formpost);

    3. multipart/formdata请求,不把文件读入fc,其它步骤相同
    curl_formadd(&formpost, &lastptr, CURLFORM_PTRNAME, "file", CURLFORM_FILE, "/path/filename", CURLFORM_END);

    4. 通过put上传文件
    curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
    curl_easy_setopt(curl, CURLOPT_PUT, 1L);
    curl_easy_setopt(curl, CURLOPT_READDATA, fp);   // FILE *fp = fopen("/path/filename");
    curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, fsize);  // fsize = sizeof /path/filename

    5. 发送自己的Header
    struct curl_slist *slist = 0;
    slist = curl_slist_append(slist, "Blog-X-User: username");
    slist = curl_slist_append(slist, "Blog-X-Signature: signature");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);
    curl_slist_free_all(slist);
  • 2个线程执行这段代码,sum的最终结果是多少?for (int i = 0; i < 1000000; ++i) sum++;

    答案是取决于编译器的参数,如果-O0编译答案是小于2000000的某个数,如果-O2编译答案是2000000。O2编译能得到正确结果,O0却不能。我们能得出i++在O2编译下具有原子性,从而不需要锁保护的结论吗?

    用objdump -d查看汇编代码发现,在O0下cpu老老实实的执行了1000000次加法,而在O2下cpu只加了一次1000000,这就是编译器优化,因为只加了两次1000000,所以结论总是2000000。但编译器不会总是这么好运,碰到这么容易优化的情况,所以还是老老实实的用锁吧。
  • 记一次磁盘IO高故障排查经历

    日期:2012-02-03 | 分类:编程

    最初是用户反馈codefs部署代码速度很慢。用dstat 1观察磁盘IO在10~20M左右。iostat -x 1 10观察util接近100%,说明已经达到磁盘性能极限,同时显示数据写入集中在sda5。

    最初怀疑是codefs的问题,但是dstat观察显示磁盘IO很高,网络IO很低。因为codefs写入磁盘的数据来自网络,网络IO远小于磁盘IO,说明不是codefs的问题。同时strace -f -p pid -e trace=write也显示没有写入,更确定不是codefs的问题。剩下只有httpd进程了。我们的httpd禁用了磁盘IO,更不可能是它导致的,并且strace -f -p pid -e trace=write显示只有少量的磁盘IO。但是,停掉httpd进程后,磁盘IO马上就降下来。两者相互矛盾。用mount命令查看/tmp分区挂在sda5,于是lsof | grep tmp发现只有APC的临时文件处于打开状态,但是不知道APC用临时文件干什么。禁用APC之后,磁盘IO降了下来,基本确认是APC的问题。

    APC是php加速器,完全使用内存,怎么会涉及到磁盘呢?原来APC有个选项apc.mmap_file_mask指定的是tmp分区下的文件。看到这个选项的名字,马上就明白是怎么回事了。APC通过mmap的方式使用共享内存,mmap映射到磁盘,而在mmap修改文件时,操作系统会将修改的内容刷到磁盘。APC开了1G的共享内存,大量的小应用导致APC经常的修改mmap的内容,从而导致频繁的将mmap的内容刷到磁盘。解决办法是将apc.mmap_file_mask设置为/dev/shm下的文件,/dev/shm是tmpfs,tmpfs是内存磁盘,没有刚才mmap刷磁盘的问题。

    磁盘IO高是前天就发现的现象,直到今天才引起足够重视并解决。首先被很多的现象所迷惑,1. 最近修改了codefs,而codefs是写磁盘的,怀疑它有道理,但是从它身上没找出问题。2. 前天就发现httpd停掉后,磁盘IO降下来,应该怀疑是它的问题,但这个又和strace的结果矛盾,就没有进一步查找。3. strace只盯着write系统调用,误导了我们,其实很多系统调用都会写磁盘writev,mmap等。其次是排查方法有问题,其实最直接的方法是查看挂载在sda5上的tmp分区,用lsof观察有哪些文件打开,通过文件名获取更详细的信息。最后是,用户不再反馈codefs部署慢,就自我麻痹,不再深究这个问题,逃避现实。
  • 自从11月19日,在延庆遭遇了一场雪,得了2011年最重的感冒,直到昨天我都没再爬过山。其间,感冒一次,遇雪一次,加班两次,偷懒若干,一晃就进入了2012,人真的会变懒的。当你在晨光中醒来,望着暖暖的室内阳光,真的不想出门,只想就这么一直待在这温暖的阳光中。外面也有阳光,但是那里的阳光稀薄,一丝的风就足以吹散阳光带来的暖意。我承认,这些是自我欺瞒的借口,虽然真实,但仍然是借口。

    周四的时候,上班路上碰到博乂,博乂说,咱们走一个大强度的穿越吧,从圈门到百望山。我们曾经从圈门走到香山(还是缩水版的,因为没走风口庵,少走至少一个小时),当时我是较紧牙关才走下来的。当时是夏天,我可以怪天气。这次是冬天,适合大强度穿越,我以为只要有体力,应该是没问题的。你知道吗?这段距离至少40公里。

    早上,中关园982,南坞倒992,终点站西辛房下车,走一站地到圈门。早上6点出门,7点40就到了,距离集合时间8点10分早了半个小时。天下着小雪,门头沟的雪比海淀的要大。我们在附近的小店吃早饭,等待集合。不知是天气缘故,还是人的缘故,直到8点50人才到齐,出发。强度大,天气糟,出发晚,真不像是能完成全程的样子。

    也许,很多人根本就没打算走全程,除了我和博乂,只有6个人一直不懈的往前赶。我承认,我走的慢,任凭我以最快的速度,我仍然赶不上他们6个。10点半到风口庵,11点半到小狗之家,13点40到水闸。不到2点到三家店,我们8个人在饭店每人吃碗杂酱面,2点半,继续往香山走。上午我喝了半罐红牛,吃了4块牛肉,1个面包,中午又一碗杂酱面,这些东西没白费,虽然步伐慢,但是体力还可以,没有觉得很累。走到新望京的时候都4点半了,这时一个男的单独下撤,两个女生往香山下撤,两男一女继续往百望山方向,我和博乂计划继续往百望山方向走,走不动就下撤,不一定非走到百望山不可。我不得不佩服那两男一女,名副其实的强驴,马不停蹄的狂奔了7个小时以后,他们还能以小跑的速度奔向百望山。我和博乂走的也不慢,直到好汉波,我们的速度也很快。

    5点半过了好汉坡后,我觉得脚腱的地方有点疼,就停下来沾了一块创可贴,我以为是鞋磨脚,因为之前爬山就疼过。但是我错了,我一迈大步,脚腱就疼。我开始悟到,是身体抵抗不住了。但已无退路,只能走到四棵树,从植物园下山。如果按照之前的速度,也就1个半小时的事情,但这次用了将近2个半小时。慢慢的,膝盖也开始怠工。我们平时很自然的走路,不会注意走路时各个关节是如何配合的,当某个部位出问题,才发现它们配合的太好了,少一个都不行。先是脚腕和大腿发力,膝关节肌肉收缩,这样迈出一步。现在脚腱伤了,膝关节疼痛,主要靠髋部的大腿,腿像钟摆一样向前摆,费力走不快。

    这是煎熬的两个半小时,好在有博乂陪伴。这次穿越由豪迈演变成了自虐,我后悔没有从香山下撤,后悔之前没有坚持爬山,并发誓今年都不再走超过20公里的线路。8点到车站,我一屁股就坐到地上,去他妈的形象,我只想休息。
    晚上回到家,只洗了脚,倒在床上,不知不觉就睡着了,一直到12点,才开始脱了衣服,再睡。我没有力气洗澡,真的没有力气。今天又休息一天,才感觉自己又活过来了。今天中午,博乂特意打电话,问身体情况,非常感谢,如果不是我拖后腿,他可以走到百望山的。这次穿越,虽然没有走完,大概也走了有33公里的样子。

    回顾一下,我感情上并不觉得累,但是身体上却体现出无可置疑的过度疲劳,身体的症状只能用疲劳解释,大概身体的疲劳时一种自我保护,免的感情作出出格的事情。跟那3位强驴比,我差的很多,先天的身体素质和后天的锻炼都有关系,总之是不能强求的,不想再有第二次这样的经历,惨痛的自虐。
  • 驷马沟-三险-坡峰岭穿越

    日期:2011-11-02 | 分类:往昔

    上周六,跟逍遥队从驷马沟-三险-坡峰岭。累计行走15多公里,上升1000多米。
    穿过兵营,上坡峰岭时,路过李莲英的行宫。行宫规模很小,10多间房子的样子,现在已经完全破落。行宫内有两个石碑,上写“万古流芳”,不管好人坏人,这点追求还是有的。
    这是第三次走这条线,虽然每次路线不是完全一致,这条线基本记路了。最近爬山听说的事故多了,自己也变得谨慎了。
  • 程序两三事(8)

    日期:2011-11-02 | 分类:编程

    1. mysql的编码问题。创建表时指定了数据的编码(没有指定用默认),假定为utf8,这个是存储在磁盘上的数据的编码。客户端和mysql服务器通信也指定了编码(set names),假定为latin1,客户端从服务端得到的数据编码就是latin1。最好的方法是指定通讯编码和数据编码相同。
    2. c语言中 char 可能是 signed char,c = (c % ('~' - ' ' + 1)) + ' '; 这行的意思是返回一个可打印字符,但是 c 是char,导致模运算可能返回负值,正确方法是:c = ((unsigned char)c % ('~' - ' ' + 1)) + ' ';
    3. 考虑压缩和网络协议优化,减少带宽消耗。
    4. 通过 strace -ttt -p pid 查看正在运行程序的系统调用的时间点,可以为辅助查找系统慢的原因。
    5. 不是只有cpu占用率70-100%,才叫高,对于一个读取mysql,然后将数据写入mc的应用,cpu 30%就叫高了。同理内存。
    6. 观看程序运行状态的关键是“cpu/内存/io”是不是在一个合适的区间。例如,占10M内存的程序,也可能是有问题,它可能只应该占1M,这个是可以预估的。
    7. php的某些操作是很慢的,当数据量上万后,array_merge是个很耗时的操作。
    8. 单线程php写入memcached小数据,在1000/秒左右,估计其它语言测试也差不多。
  • 柏峪-北灵山穿越

    日期:2011-10-27 | 分类:往昔

    上周六,跟逍遥队从柏峪经黄草梁,实心楼穿越到北灵山。累计行走21公里,上升1300多米。最后攀登无名1,无名2,的确感到吃力。
    北灵山风光最美的莫过于山顶的黄草和白桦林。就是远了点,来回7个小时车程。
  • 法城-大寒岭城关-千军台穿越

    日期:2011-10-20 | 分类:往昔

    5点起床,5点40中关园等982公交10分钟,30分钟后到五棵松北,6点45到苹果园,赶上6点55分的892,1个小时50分钟后到达法城,此时近9点。等到10点最后一队人才到,开始爬山。下午4点到千军台,正好赶上公交车。

    2点半到髽鬏山底,一队人直接去千军台。我们8个人绕道大寒岭关城去千军台。同行的8人中有4个50岁左右的人,我用尽全身的力气,勉强跟的上他们。大寒岭关城现在只剩一个破落的城头,以前是京西古道的关口。千军台有一个煤矿,山坡上有一片棚户区。

    爬山6个小时,来回公交6个小时。周六爬的山,今天补记。
  • noreply的含义是,client发送请求给TcpServer,但是TcpServer不返回响应给client,籍此,可以大幅提高TcpServer的吞吐量。

    最早看到这个是在memcached协议中,memcached协议里,所有的写操作(含delete)都可以设置server不返回响应给client。首先tcp保证了client的请求肯定发送给了server,而这些操作几乎不可能失败,所以server返回响应给client没有什么意义。

    提高吞吐量的原因有:1. 减少了server往client的写操作。2. server一次可以从tcp缓冲去中读取多个请求。我的一个计数器程序,noreply相比reply,吞吐量提高了5倍。对于网络IO是瓶颈,client不十分关心server返回值的应用,都可以考虑这个方法。

    因为tcp自身有流量控制,所以通常这个不是问题。但当client采用non-block IO时,client可以产生很大的压力,此时收到EAGAIN,可能在client堆积大量的请求。要预先估计系统容量,防止client堆积请求。
  • 程序两三事(5)

    日期:2011-10-10 | 分类:编程

    1. c++ 中enum可以赋值给int,int不可用赋值给enum。
    2. syslog-ng 有丢日志的现象,多的时候丢50%以上。
    3. 先入为主是可怕的。如果拿memcached做计数,统计5分钟和一天的数据,简单的逻辑是同一个key分别加后缀,相当于两个key,分别计数。
       如果是自己拿HASH表做计数,还用memcached的逻辑就错了,只用一个key,value记录和5分钟和一天的数据才是正确的方法。
    4. 我觉得在c++中,分配内存还是用malloc/calloc好,创建对象用new,毕竟内存不同于对象,你得记着内存的初始化。
    5. 不要完全相信数据链路的crc校验,如果你的数据很有价值,也不要相信tcp/udp的校验和。
    6. 最大udp数据报的长度和发送/接收缓冲区的长度直接相关,通过调整这两个长度可以发送最大不超过65535的包。
  • 大觉寺-鹫峰穿越

    日期:2011-09-27 | 分类:往昔

    这是连续第3次从大觉寺上山。前4周,snnn说要去鹫峰,问我能不能带队,我答应了,结果天气预报有雨,于是放弃,事实证明没雨。前3周,snnn说继续去鹫峰吧,我答应了,结果天气预报还是有雨,于是放弃,事实果然有雨。前2周,snnn没说啥。上周,snnn说还是想去鹫峰,终于成行。是为此次穿越。其实云飞是认路的,他们自己完全搞的定。虽说一起爬山的有很多姑娘,但是我在陌生人前相当矜持,连句搭讪都没有,枉费了这么多姑娘。