用Memcache实现分布式的锁服务

一般情况下我们都用Memcache作为一个分布式的key/value缓存服务器,其实Memcache也可以实一些外门邪道的功能比如作为分布式锁来用。

原理其实非常简单就是memecach_add的时候,如果添加的key已经存在那么后面的添加就会失败。设想在高并发的场景下,如果存在被竞争的资源,我们就可以利用这个小trick来对资源加锁。知道了原理实现起来非常简单,下面是我初步实现的代码。

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
<?php

/**
 * 锁服务(用Memcache模拟锁)
 * Author: tomheng<zhm20070928@gmail.com>
 * gist: https://gist.github.com/tomheng/6149779
 */


class Lock{

    private $mc = null;
    private $key_prefix = "memcache_lock_service_key_";
    private $all_lock_names = array();
    private $expiration = 60; //one min
    private $max_block_time = 15; //最长的阻塞时间
    /**
     * [__construct description]
     */

    public function __construct(){
        if(function_exists('memcache_init')){
            $this->mc = memcache_connect('memcache_host', 11211);
        }
    }

    /**
     * [get_key description]
     * @param  [type] $name [description]
     * @return [type]       [description]
     */

    private function get_key($name){
        $key = $this->key_prefix.$name;
        return $key;
    }

    /**
     * 捕获锁
     * @param  [type] $name [description]
     * @return [type]       [description]
     */

    public  function begin($name, $block = true)
    {
        if(!$this->mc || !$name){
            return false;
        }
        $max_block_time = $this->max_block_time;
        $key = $this->get_key($name);
        do{
            $re = memcache_add($this->mc, $key, 1, false, $this->expiration);
            if($re == true){
                $this->all_lock_names[$name] = 1;
                //$this->debug();
                break;
            }else{
                //dolog('Lock failed '.$name);
            }
            //echo '#'.PHP_EOL;
            //sleep(1);
        }while($block && $max_block_time-- && !sleep(1));
        return $re;
    }

    /**
     * 释放锁
     */

    public function release($name){
        if(!$this->mc || !$name){
            return false;
        }
        $key = $this->get_key($name);
        $re = memcache_delete($this->mc, $key);
        if($re == true){
            unset($this->all_lock_names[$name]);
        }
        return $re;
    }

    /**
     * 释放所有的锁
     */

    public function __destruct(){
        if(!$this->mc){
            return false;
        }
        foreach ($this->all_lock_names as $name => $value) {
            # code...
            $this->release($name);
        }
    }

    /**
     * 调试
     * @return [type] [description]
     */

    public function debug(){
        var_dump($this->all_lock_names);
        foreach ($this->all_lock_names as $name => $value) {
            $key = $this->get_key($name);
            if($this->mc){
                $value = memcache_get($this->mc, $key);
            }else{
                $value = "no such lock ";
            }
            echo "Lock name:$key, value:{$value}".PHP_EOL;
        }
    }
}

SimplePie 将中文编码成 HTML Entities 的解决方法

闲来折腾一个玩具五车书的过程中,需要用到解析RSS的地方,于是找到了强大的SimplePid。在使用的过程中遇到了一些问题,比如前段时间遇到的This XML document is invalid的问题,其实在这问题前还有一个问题,就是今天说的这个中文被编码的问题。

经过一番折腾之后,终于搞明白了怎么回事并找到了BT的解决方案。

SimplePie 在library/Sanitize.php文件的sanitize方法中使用DOMDocument对数据进行了一次加工,正式这次加工把中文编码成了HTML Entities。

那么为什么会这样呢?php.net上在关于DOMDocument::loadHTML说明下面已经有高人讨论到了此问题。

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
If you use loadHTML() to process utf HTML string (eg in Vietnamese), you may experience result in garbage text, while some files were OK. Even your HTML already have meta charset  like

  <meta http-equiv="content-type" content="text/html; charset=utf-8">

I have discovered that, to help loadHTML() process utf file correctly, the meta tag should come first, before any utf string appear. For example, this HTML file

<html>
 <head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <title> Vietnamese - Tiếng Việt</title>
  </head>
<body></body>
</html>

will be OK with loadHTML() when <meta> tag appear <title> tag.

But the file below will not regcornize by loadHTML() because <title> tag contains utf string appear before <meta> tag.

<html>
 <head>
    <title> Vietnamese - Tiếng Việt</title>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
  </head>
<body></body>
</html>

SimplePie其实已经通过的Santinize的preprocess方法加上了合理charset,按照上面的说明中文就不应该被编码了。看起来凶手另有其人啊,仔细看代码后发现,问题出现在SimplePie在saveHTML之前为了原样取回数据进行了一个处理,代码如下。

1
2
$real_body = $document->getElementsByTagName('body')->item(0)->childNodes->item(0);
$document->replaceChild($real_body, $document->firstChild);

这样处理的结果就像重新load一次HTML一样,但是因为这次每页charset设置,所以中文在这里被编码成了HTML Entities。

知道了原因就好办了,我是这样搞定她滴~。
如下修改library/Sanitize.php文件即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//修复开始
$unique_tag = '#'.uniqid().'#';
$data = $unique_tag.$data.$unique_tag;
//修复结束
$data = $this->preprocess($data, $type);
...
...
// Move everything from the body to the root
//注释掉下面紧邻的两行
//$real_body = $document->getElementsByTagName('body')->item(0)->childNodes->item(0);
//$document->replaceChild($real_body, $document->firstChild);

// Finally, convert to a HTML string
$data = trim($document->saveHTML());
//添加此行
list($_, $data, $_) = explode($unique_tag, $data);

没了Google Reader还可以这样玩RSS

好吧,这应该算是一篇“辞旧迎新”的文章。

RSS

RSS 是Really Simple Syndication的简写,意思就是 “聚合真的很简单”。RSS(简易信息聚合)是一种消息来源格式规范,用以聚合经常发布更新数据的网站,例如博客文章、新闻、音频或视频的网摘。RSS文件(或称做摘要、网络摘要、或频更新,提供到频道)包含了全文或是节录的文字,再加上发用者所订阅之网摘布数据和授权的元数据。

从上面可以看出RSS就是一种信息聚合的格式规范,从这个意义上来说,我不认为RSS会随着Google Reader的关闭而逐渐消亡。其实随着科技的进步和发展,信息会变得越来越分散,认为获取有价值信息的 成本也会随之提高,这就是不断出现的信息聚合工具的价值所在。一个能为人们提供价值的东西,怎么会无缘无故的衰亡呢?

Google Reader

Google阅读器(Google Reader)是Google公司旗下一个基于网络的聚合器,能在线或者离线阅读Atom和RSS。英文版的Google Reader于2005年10月7日通过Google实验室发布,2007年9月17日成为正式版。中文版的Google阅读器大约在2007年9月18日左右发布。
2013年3月13日Google宣布,作为第二个春季大扫除计划之一,Google阅读器因用户数量逐年下降,将于2013年7月1日终止服务,用户有3个多月的时间导出自己的数据。

就我的体验来讲,Google Reader确实给我带来了实在的价值,尤其是读书那会。那时的闲暇时间也比较多,所以会长时间的泡在GR上,看各种牛人“山呼海啸”,也算是一种享受了。很不幸的是这样一个优秀的工具要离我们而去,就像很多美好的事物一样。

五车书

是我的一个实现项目,源于6月初离职找工作。离职的事情比较突然,一时没有想好自己下一步应该怎么办?所以自己不想盲目的去找工作,就像要不要出去玩一下放松放松,后来一项五一刚出玩过一次,再说也没有好的地方去。一个偶然的瞬间想到是不是可以把RSS的微信两个东西结合起来,弄成个类似阅读器的东西。

接下来就用了两天的时间做了个原型,验证了下自己的想法,发现确实是可以实现的。随后就又投入了几天的时间,前后整个项目零星投入差不多2周时间。现在总算到了勉强可用的程度,于是想分享出来。

五车书主要分两个部分,一个就是微信公号的接口部分,也就是在微信内实现和用户的交互。第二部是做了一个简单的可以管理和添加订阅的网站。

本来的设想是挺好的,可以实现完全的微信内管理,不过现在有些条件还不成熟,项目目前只是可用离易用还有比较大的差距。有很多可以实现的好的Idea目前无法实现,期待微信5.0出来后可以带来更好好玩的功能。

如果感兴趣可以扫描下面的二维码或者在微信内搜索fbooks添加好友。

 

DigitalOcean SSD Cloud VPS Server 你值得拥有

时至今日,博客断断续续坚持四年有余了。这中间博客换了很多空间,涵盖“古今中外”。最近两年一直是用的HostMoster的空间,有方便的CPanel 操作面板可以省却不少麻烦事,这对于普通用户确实是个好事,但是对我像我这样混互联网的来说,如今还在用这种空间未免有些“不误正业”,怎么着也得搞个靠谱的VPS玩玩啊 :)

正好前段时间有朋友问我Linode如何,于是铁下心来这次要搞一个了。到官网看了下价格,再看看自己的口袋,不胜唏嘘啊!后来又找了一下,发下了一个性价比更高的VPS,就是今天的主角了DigitalOcean。DigitalOcean 的VPS最便宜的每个月最多5美金,并且是按小时扣费的,配置20G的SSD 硬盘、512M的内存,1TB的流量,简直就是VPS中的性价比之王。

具体到速度什么的,大家可以看一下我的博客就好了,经过综合考察如果决定购买的话,有几点是需要注意的。

一、DigitalOcean现在有推广活动。

在注册完成以后,先到https://www.digitalocean.com/user_payment_profiles添加信用卡(不要先用paypal充值),添加行用卡的时候,可以看到有个地方可以填写promo code。在那里填上VPSERS10 他们会送10美金到账户,相当于可以免费使用两个月。

digitalocean-promo-code

二、可以使用财付通的虚拟运通账号

鉴于Linode之前曾经泄露过一次信用卡信息,这个地方如果想保险的话,可以使用财付通的虚拟运通账号来填写信用卡信息(没有信用卡的也可以这样搞)。

三、数据备份

之前他们曾经弄丢过一次数据,后来补偿了每个用户50$。但是对于我们来说,数据事第一位的,自己要做好备份。

前两天DigitalOcean还发了一封感谢邮件,据Netcraft报告说,过去6个月DigitalOcean规模增长了50多倍,看起来发展的不错激动的DigitalOcean在邮件结尾说了5个thank you ~, 有感兴趣的朋友可以搞一个玩玩,我觉着挺靠谱滴……

This XML document is invalid 错误处理

在做XML解析的时候很可能遇到This XML document is invalid这种错误。

在PHP中根据使用的解析函数(字符串编码为UTF-8)不同可能的提示有以下两种:

1)xml_parser*函数错误提示

This XML document is invalid, likely due to invalid characters. XML error: Invalid character at line 30, column 25

2)XMLReader类 或 simplexml_load*函数

error on line 30 at column 25: Input is not proper UTF-8, indicate encoding !
Bytes: 0x1D 0xE7 0xBB 0x

搜索了好久没有找到完美的解决方案,最后分析发现出现这种问题一般是因为出现了不可见字符。于是就试了试能不能通过去除不可见字符的方式来绕过这个错误提示,从而使解析继续下去。经过实验在我的测试中是可以的,所以分享出来,希望对遇到同样问题的朋友能节约一些时间。

可以通过如下方式去除字符串中的不可见字符。

preg_replace(‘/[^\P{C}\n]+/u’, ”, $utf8_data)

【转】你为什么会浮躁

从十七八岁到二十七八岁的差不多十年时间里,大多数人都处于浮躁状态。如果你恰好这样,只能表明一件事情:你很正常——你并不孤独,周围的人和你一样,甚至比你更没底儿,你要做的就是稳住,给自己多一些快乐,多阅读、多思考、多积累、多享受生命中这段“浮躁岁月”。
浮躁的首要原因,是因为自己的满意度正处于递减的阶段。满意度低(也就是不快乐)根源在于“不确定性”,看不清前途,不知自己要什么,不满足现状但不知如何努力。从15岁左右开始,人的满意程度开始持续下降。大抵上应该是不再无知无畏造成的。慢慢意识到自己在这个世界上无足轻重微不足道;终日在所谓的理想和扭曲的现实中痛苦、挣扎,却又找不到明确的方向。直到45岁左右的时候,曲线才开始上扬。漫长的三十年。以一个普通人的心智,观察、感受、理解、思索、实践、反思、直至恍然大悟或者误入歧途平均需要30年。
满意度低,自我感觉不良好,很难不浮躁;越浮躁越负向作用,感觉越不爽——形成恶性循环。 浮躁的另一个原因,来自于一个不正确——至少并不完全正确的心态:人们总是希望马上有确定的结果——就是俗话讲的,“急于求成”。
人们总是在决定是否学习之前试图弄清楚“这东西究竟是否真的有用?”这个貌似合理的想法,实际上是很愚蠢的。首先要知道的是,每个人的心智都必然在不同程度上受一定的限制。所以,在没有学会某一项技能之前,很难知道学会那样东西究竟有用到什么程度。反过来,当看到人们某个人拥有一项技能,而判定此技能非常有用的时候,又往往已经来不及了——因为学习并精通一项技能,往往需要5到10年时间。
所以,想进入“踏踏实实”的状态的第一步,就是明确一件事情:学习的真正乐趣不是因为它有用,而是因为学习的过程本身有趣。“学这个有用吗?”的正确答案不是“有用!”,也不是“没用!”。正确答案应该是“不知道有什么用处……”
总结一下尴尬形成的原因,就是太多人的世界观有问题:竟然不停地尝试在一个不确定的世界里,去寻找一个永恒确定的方案——痴迷于一个根本不存在的状态。最要命的是,不仅想知道确定的结果,还需要马上知道——这就更荒唐了。 浮躁的第三个原因——怪只怪环境的压力越来越大。信息的高速流动意味着说每个人都有更多的机会看到更多比自己更优秀的人,而谁都止不住几乎是本能的比较。这比较就是压力,来自环境的压力。一个圆,越大,接触的未知领域也就越多。
人们往往低估环境的巨大能量,但是,人们往往把来自环境的影响当作自己由衷的想法。与外界的无谓比较,使得每个人“凭空”多出了一个根本不属于自己的目标。于是,动不动就出现被自己理想绑架的情况。越是不满现状,摆脱现状的欲望就越强烈,而这种欲望会让一个人最终迷失方向。 生活的本质是什么呢?无非是“你要什么就不给你什么”,而生活的智慧是什么呢?是“给你什么就用好什么”。某种意义上,“逆境造就成功、磨难令人成熟”之类的话纯属胡说八道——更可是失败者对一生都未曾有机会体会的成功以及成功者的“意淫”式的猜想而已。失败者永远不会有机会了解成功的真相,因为人最容易受到自身经验的局限,而不曾有哪怕一点点成功经验的人更无从摆脱自身局限。
对现状不满,急于摆脱现状,往往是常人最常不知不觉就掉进去的陷阱——尽管偶尔这也是少数人的真正动力。接受现状才是最优策略,有什么做什么,有什么用什么;做什么都做好,用什么都用好。不要常常觉得苦(那样的话就会忍不住顾镜自怜,浪费精力与时间),而是要想办法在任何情况下找到情趣——快乐是一种本事。这些年我遇到的几乎所有优秀的年轻人都有个特征,他们最少对现状不满(可能是他们的优秀使得他们更加难以不满吧?),他们热爱自己的生活,他们相对更不在意外界的影响,他们更专注做事而心无旁骛,他们当然每时每刻都更加优秀。