<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
<channel>
<title><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></title> 
<link>http://www.jackxiang.com/index.php</link> 
<description><![CDATA[赢在IT，Playin' with IT,Focus on Killer Application,Marketing Meets Technology.]]></description> 
<language>zh-cn</language> 
<copyright><![CDATA[向东博客 专注WEB应用 构架之美 --- 构架之美，在于尽态极妍 | 应用之美，在于药到病除]]></copyright>
<item>
<link>http://www.jackxiang.com/post/10461/</link>
<title><![CDATA[[值得了解]redis的串行和iothread模型对多CPU使用更高效，但是对单个Client的先后顺序仍然是串行的。skiplist链表说明。]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[Cache与Store]]></category>
<pubDate>Sun, 15 Mar 2020 12:42:20 +0000</pubDate> 
<guid>http://www.jackxiang.com/post/10461/</guid> 
<description>
<![CDATA[ 
	<br/><a href="http://www.jackxiang.com/attachment.php?fid=558" target="_blank"><img src="http://www.jackxiang.com/attachment.php?fid=558" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0" width="870"/></a><br/><br/><br/>skiplist跳跃表链表说明，有论文：<br/><a href="https://cloud.tencent.com/developer/article/1452187" target="_blank">https://cloud.tencent.com/developer/article/1452187</a><br/><br/><a href="http://www.jackxiang.com/attachment.php?fid=559" target="_blank"><img src="http://www.jackxiang.com/attachment.php?fid=559" class="insertimage" alt="点击在新窗口中浏览此图片" title="点击在新窗口中浏览此图片" border="0"/></a><br/><br/>
]]>
</description>
</item><item>
<link>http://www.jackxiang.com/post/10011/</link>
<title><![CDATA[[实践OK]统计redis中某类key的数量，代替keys指令]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[Cache与Store]]></category>
<pubDate>Sat, 29 Dec 2018 07:44:37 +0000</pubDate> 
<guid>http://www.jackxiang.com/post/10011/</guid> 
<description>
<![CDATA[ 
	<textarea name="code" class="php" rows="15" cols="100">
SCAN 0 MATCH SESS_* COUNT 10
redis-cli -p 6401 -a X**--scan --pattern &quot;SESS*&quot;&nbsp;&nbsp;&gt; /tmp/10.71.1*.3*_SESS_KEYS_ALL.txt
</textarea><br/><br/><textarea name="code" class="php" rows="15" cols="100">
#!/bin/bash

A=$0
B=$&#123;A##*/&#125;
C=$&#123;B%.*&#125;
running_file_name=$C
running_flag=&quot;run.$running_file_name&quot;

REDIS_CLIENT=&#039;redis-cli -h 0.0.0.0 -p 6400 -x&#039;
function process &#123;
&nbsp;&nbsp;&nbsp;&nbsp;echo $0
&nbsp;&nbsp;&nbsp;&nbsp;index=-1
&nbsp;&nbsp;&nbsp;&nbsp;count=0
&nbsp;&nbsp;&nbsp;&nbsp;step=100000
&nbsp;&nbsp;&nbsp;&nbsp;while ((index!=0))
&nbsp;&nbsp;&nbsp;&nbsp;do
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if [ $index -le 0 ];then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;index=0
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fi
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;echo &quot;scan $index match $1 count $step&quot; &#124; $REDIS_CLIENT &gt; $running_file_name.cache
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;read index &lt;&lt;&lt; `head -1 $running_file_name.cache`
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;read inc &lt;&lt;&lt; `cat $running_file_name.cache &#124; wc -l`
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;inc=$((inc - 1))
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if [ $? -ne 0 ];then
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;break
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fi
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;count=$((count + inc))
&nbsp;&nbsp;&nbsp;&nbsp;done
&nbsp;&nbsp;&nbsp;&nbsp;echo &quot;$1 count:&quot;$count
&#125;
#
if [ $# -ne 1 ];then
&nbsp;&nbsp;&nbsp;&nbsp;echo &quot;$0 &lt;pars&gt;&quot;
&nbsp;&nbsp;&nbsp;&nbsp;exit 0
fi
#
if [ -f &quot;$running_flag&quot; ] ; then
&nbsp;&nbsp;&nbsp;&nbsp;echo &quot;is running...&quot;
&nbsp;&nbsp;&nbsp;&nbsp;exit 0
fi
#
touch $running_flag
#
echo &quot;processing....&quot;
echo $*
process $*
#
rm -rf $running_flag
#
echo &quot;ok!&quot;

</textarea><br/><br/>./redis_keycount.sh &#039;SESS*&#039;&nbsp;&nbsp; <br/>processing....<br/>SESS*<br/>./redis_keycount.sh<br/><br/><br/><br/>SESS* count:21798578<br/>ok!<br/><br/>来自：https://studygolang.com/articles/14275?fr=sidebar
]]>
</description>
</item><item>
<link>http://www.jackxiang.com/post/9576/</link>
<title><![CDATA[高并发下PHP请求Redis异常处理]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[Cache与Store]]></category>
<pubDate>Sat, 23 Dec 2017 15:36:58 +0000</pubDate> 
<guid>http://www.jackxiang.com/post/9576/</guid> 
<description>
<![CDATA[ 
	https://weibo.com/2717930601/EkAZGDVAz?type=comment#_rnd1514043204039<br/>http://blog.csdn.net/u013474436/article/details/53117463#0-tsina-1-14535-397232819ff9a47a7b7e80a40613cfe1<br/>这个哥们描述了类似Mysql的长连接问题，在redis的长连接也有类似的问题，于是作了一个总结性的博文，值得在实践中注意。
]]>
</description>
</item><item>
<link>http://www.jackxiang.com/post/9572/</link>
<title><![CDATA[Mysql锁表模拟主从延迟，测试Zabbix主从同步延迟报警，以及Mysql的innodb也能先停复制的IO追平后，再停Mysql拷贝数据目录到别的Mysql能启动来的方法。]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[Cache与Store]]></category>
<pubDate>Thu, 21 Dec 2017 03:50:44 +0000</pubDate> 
<guid>http://www.jackxiang.com/post/9572/</guid> 
<description>
<![CDATA[ 
	追平后，再停Mysql拷贝数据目录到别的Mysql能启动来的方法参考，Mysql的innodb也能先停复制的IO追平后停Mysql拷贝数据目录到别的Mysql能启动来的方法：http://jackxiang.com/post/9702/<br/>背景：有时候为了测试Zabbix主从延迟，还得锁从库的表（或是停从库），诱发主从同步延迟。<br/>SHOW PROCESSLIST查看数据库中表的状态，是否被锁；<br/>kill id&nbsp;&nbsp; //杀掉被锁的表<br/><br/>1. FLUSH TABLES WITH READ LOCK<br/>&nbsp;&nbsp; 这个命令是全局读锁定，执行了命令之后所有库所有表都被锁定只读。一般都是用在数据库联机备份，这个时候数据库的写操作将被阻塞，读操作顺利进行。2<br/><br/>&nbsp;&nbsp; 解锁语句是：UNLOCK TABLES;<br/><br/>2.LOCK TABLES tbl_name [AS2alias] &#123;READ [LOCAL] &#124; [LOW_PRIORITY] WRITE&#125;<br/>&nbsp;&nbsp;这个命令是表级别的锁定，可以定制锁定某一个表。例如： lock 2tables test read; 不影响其他表的写操作。<br/><br/>&nbsp;&nbsp; 解锁语句是：UNLOCK TABLES;<br/><br/>&nbsp;&nbsp;这两个语句在执行的时候都需要注意个特点，就是 隐式提交的语句。在退出 mysql2终端的时候都会隐式的执行 UNLOCK TABLES2。也就是说如果要让表锁定生效就必须一直保持对话。<br/>原文：http://blog.csdn.net/shootyou/article/details/626735<br/><br/>Mysql的innodb也能先停复制的IO追平后停Mysql拷贝数据目录到别的Mysql能启动来的方法:<br/>mysql&gt; help stop slave<br/>Name: &#039;STOP SLAVE&#039;<br/>Description:<br/>Syntax:<br/>STOP SLAVE [thread_types]<br/><br/>thread_types:<br/>&nbsp;&nbsp;&nbsp;&nbsp;[thread_type [, thread_type] ... ]<br/><br/>thread_type: IO_THREAD &#124; SQL_THREAD<br/>
]]>
</description>
</item><item>
<link>http://www.jackxiang.com/post/9251/</link>
<title><![CDATA[[实践Ok]Redis学习手册(Hashes数据类型)，以及PHP代码如何操作Redis的Hash实现。]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[Cache与Store]]></category>
<pubDate>Sat, 24 Jun 2017 04:38:52 +0000</pubDate> 
<guid>http://www.jackxiang.com/post/9251/</guid> 
<description>
<![CDATA[ 
	背景：对于一些Redis里所提供的数据结构，用Hash可能是用得最多的，为何呢？因为日常中很多东西都可以用它来表示。<br/>把一个复杂的需要序列化的东西变为一个HashTable进行存储，利用Hash存储节约内存,这样还可能更快更少的消耗实现高并发:<br/><br/>&lt;?php<br/>/** 每天下达指令的也就是x权限（每种鸡蛋的上下限），<br/>而r就是只有看温度的权限，而w就是有设置温度权限 **/<br/><br/>$arr = array(<br/>&nbsp;&nbsp;&nbsp;&nbsp;&quot;tcp&quot; =&gt;array(<br/>&nbsp;&nbsp;&quot;ip&quot;=&gt;&quot;192.168.1.1&quot;,<br/>&nbsp;&nbsp;&quot;fd&quot;=&gt;&quot;2&quot;,<br/>&nbsp;&nbsp;&quot;mac&quot;=&gt;&quot;00-50-56-C0-00-08&quot;,<br/>&nbsp;&nbsp;&quot;chineseName&quot;=&gt;&quot;蛋壳108109&quot;,<br/>&nbsp;&nbsp;&quot;EnglishName&quot;=&gt;&quot;LevooAllCanBeHatch&quot;<br/>&nbsp;&nbsp;&nbsp;&nbsp;),<br/>&nbsp;&nbsp;&nbsp;&nbsp;&quot;frame&quot; =&gt;array(<br/>&nbsp;&nbsp;array(<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;ip&quot;=&gt;&quot;192.168.1.1&quot;,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;fd&quot;=&gt;&quot;2&quot;,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;token&quot;=&gt;&quot;jfdjfldjflkdjdjfkldf&quot;,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;isconnected&quot;=&gt;0,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;chmod&quot;=&gt;&quot;rwx&quot;<br/><br/>&nbsp;&nbsp;),<br/>&nbsp;&nbsp;array(<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;ip&quot;=&gt;&quot;192.168.1.1&quot;,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;fd&quot;=&gt;&quot;2&quot;,&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;token&quot;=&gt;&quot;jfdjfldjflkdjdj1fkl2df&quot;,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;isconnected&quot;=&gt;1,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;chmod&quot;=&gt;&quot;rw&quot;<br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;),<br/>&nbsp;&nbsp;array(<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;ip&quot;=&gt;&quot;192.168.1.1&quot;,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;fd&quot;=&gt;&quot;2&quot;,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;token&quot;=&gt;&quot;jfdjfldjflkdjdjfk33ld22f&quot;,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;isconnected&quot;=&gt;1,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;chmod&quot;=&gt;&quot;x&quot;<br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;),<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;array(<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;ip&quot;=&gt;&quot;192.168.1.1&quot;,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;fd&quot;=&gt;&quot;2&quot;,&nbsp;&nbsp;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;token&quot;=&gt;&quot;jfdjfl323djdjfkld22f&quot;,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;isconnected&quot;=&gt;1,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;chmod&quot;=&gt;&quot;rwx&quot;<br/>&nbsp;&nbsp;<br/>&nbsp;&nbsp;),<br/>&nbsp;&nbsp;array(<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;ip&quot;=&gt;&quot;192.168.1.1&quot;,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;fd&quot;=&gt;&quot;2&quot;,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;token&quot;=&gt;&quot;jf1121fldjflkdjdjfkld22f&quot;,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;isconnected&quot;=&gt;1,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;chmod&quot;=&gt;&quot;rwx&quot;<br/>&nbsp;&nbsp;)<br/>&nbsp;&nbsp;&nbsp;&nbsp;)<br/>);<br/>print_r($arr);<br/>echo json_encode($arr);<br/>?&gt;<br/><br/><br/><br/><br/>命令示例：<br/>&nbsp;&nbsp;&nbsp;&nbsp;1. HSET/HGET/HDEL/HEXISTS/HLEN/HSETNX:<br/>&nbsp;&nbsp;&nbsp;&nbsp;#在Shell命令行启动Redis客户端程序<br/>&nbsp;&nbsp;&nbsp;&nbsp;/&gt; redis-cli<br/>&nbsp;&nbsp;&nbsp;&nbsp;#给键值为myhash的键设置字段为field1，值为stephen。<br/>&nbsp;&nbsp;&nbsp;&nbsp;redis 127.0.0.1:6379&gt; hset myhash field1 &quot;stephen&quot;<br/>&nbsp;&nbsp;&nbsp;&nbsp;(integer) 1<br/>&nbsp;&nbsp;&nbsp;&nbsp;#获取键值为myhash，字段为field1的值。<br/>&nbsp;&nbsp;&nbsp;&nbsp;redis 127.0.0.1:6379&gt; hget myhash field1<br/>&nbsp;&nbsp;&nbsp;&nbsp;&quot;stephen&quot;<br/>&nbsp;&nbsp;&nbsp;&nbsp;#myhash键中不存在field2字段，因此返回nil。<br/>&nbsp;&nbsp;&nbsp;&nbsp;redis 127.0.0.1:6379&gt; hget myhash field2<br/>&nbsp;&nbsp;&nbsp;&nbsp;(nil)<br/>&nbsp;&nbsp;&nbsp;&nbsp;#给myhash关联的Hashes值添加一个新的字段field2，其值为liu。<br/>&nbsp;&nbsp;&nbsp;&nbsp;redis 127.0.0.1:6379&gt; hset myhash field2 &quot;liu&quot;<br/>&nbsp;&nbsp;&nbsp;&nbsp;(integer) 1<br/>&nbsp;&nbsp;&nbsp;&nbsp;#获取myhash键的字段数量。<br/>&nbsp;&nbsp;&nbsp;&nbsp;redis 127.0.0.1:6379&gt; hlen myhash<br/>&nbsp;&nbsp;&nbsp;&nbsp;(integer) 2<br/>&nbsp;&nbsp;&nbsp;&nbsp;#判断myhash键中是否存在字段名为field1的字段，由于存在，返回值为1。<br/>&nbsp;&nbsp;&nbsp;&nbsp;redis 127.0.0.1:6379&gt; hexists myhash field1<br/>&nbsp;&nbsp;&nbsp;&nbsp;(integer) 1<br/>&nbsp;&nbsp;&nbsp;&nbsp;#删除myhash键中字段名为field1的字段，删除成功返回1。<br/>&nbsp;&nbsp;&nbsp;&nbsp;redis 127.0.0.1:6379&gt; hdel myhash field1<br/>&nbsp;&nbsp;&nbsp;&nbsp;(integer) 1<br/>&nbsp;&nbsp;&nbsp;&nbsp;#再次删除myhash键中字段名为field1的字段，由于上一条命令已经将其删除，因为没有删除，返回0。<br/>&nbsp;&nbsp;&nbsp;&nbsp;redis 127.0.0.1:6379&gt; hdel myhash field1<br/>&nbsp;&nbsp;&nbsp;&nbsp;(integer) 0<br/>&nbsp;&nbsp;&nbsp;&nbsp;#判断myhash键中是否存在field1字段，由于上一条命令已经将其删除，因为返回0。<br/>&nbsp;&nbsp;&nbsp;&nbsp;redis 127.0.0.1:6379&gt; hexists myhash field1<br/>&nbsp;&nbsp;&nbsp;&nbsp;(integer) 0<br/>&nbsp;&nbsp;&nbsp;&nbsp;#通过hsetnx命令给myhash添加新字段field1，其值为stephen，因为该字段已经被删除，所以该命令添加成功并返回1。<br/>&nbsp;&nbsp;&nbsp;&nbsp;redis 127.0.0.1:6379&gt; hsetnx myhash field1 stephen<br/>&nbsp;&nbsp;&nbsp;&nbsp;(integer) 1<br/>&nbsp;&nbsp;&nbsp;&nbsp;#由于myhash的field1字段已经通过上一条命令添加成功，因为本条命令不做任何操作后返回0。<br/>&nbsp;&nbsp;&nbsp;&nbsp;redis 127.0.0.1:6379&gt; hsetnx myhash field1 stephen<br/>&nbsp;&nbsp;&nbsp;&nbsp;(integer) 0<br/><br/>&nbsp;&nbsp; 2. HINCRBY：<br/>&nbsp;&nbsp;&nbsp;&nbsp;#删除该键，便于后面示例的测试。<br/>&nbsp;&nbsp;&nbsp;&nbsp;redis 127.0.0.1:6379&gt; del myhash<br/>&nbsp;&nbsp;&nbsp;&nbsp;(integer) 1<br/>&nbsp;&nbsp;&nbsp;&nbsp;#准备测试数据，该myhash的field字段设定值1。<br/>&nbsp;&nbsp;&nbsp;&nbsp;redis 127.0.0.1:6379&gt; hset myhash field 5<br/>&nbsp;&nbsp;&nbsp;&nbsp;(integer) 1<br/>&nbsp;&nbsp;&nbsp;&nbsp;#给myhash的field字段的值加1，返回加后的结果。<br/>&nbsp;&nbsp;&nbsp;&nbsp;redis 127.0.0.1:6379&gt; hincrby myhash field 1<br/>&nbsp;&nbsp;&nbsp;&nbsp;(integer) 6<br/>&nbsp;&nbsp;&nbsp;&nbsp;#给myhash的field字段的值加-1，返回加后的结果。<br/>&nbsp;&nbsp;&nbsp;&nbsp;redis 127.0.0.1:6379&gt; hincrby myhash field -1<br/>&nbsp;&nbsp;&nbsp;&nbsp;(integer) 5<br/>&nbsp;&nbsp;&nbsp;&nbsp;#给myhash的field字段的值加-10，返回加后的结果。<br/>&nbsp;&nbsp;&nbsp;&nbsp;redis 127.0.0.1:6379&gt; hincrby myhash field -10<br/>&nbsp;&nbsp;&nbsp;&nbsp;(integer) -5&nbsp;&nbsp; <br/><br/>&nbsp;&nbsp;&nbsp;&nbsp;3. HGETALL/HKEYS/HVALS/HMGET/HMSET:<br/>&nbsp;&nbsp;&nbsp;&nbsp;#删除该键，便于后面示例测试。<br/>&nbsp;&nbsp;&nbsp;&nbsp;redis 127.0.0.1:6379&gt; del myhash<br/>&nbsp;&nbsp;&nbsp;&nbsp;(integer) 1<br/>&nbsp;&nbsp;&nbsp;&nbsp;#为该键myhash，一次性设置多个字段，分别是field1 = &quot;hello&quot;, field2 = &quot;world&quot;。<br/>&nbsp;&nbsp;&nbsp;&nbsp;redis 127.0.0.1:6379&gt; hmset myhash field1 &quot;hello&quot; field2 &quot;world&quot;<br/>&nbsp;&nbsp;&nbsp;&nbsp;OK<br/>&nbsp;&nbsp;&nbsp;&nbsp;#获取myhash键的多个字段，其中field3并不存在，因为在返回结果中与该字段对应的值为nil。<br/>&nbsp;&nbsp;&nbsp;&nbsp;redis 127.0.0.1:6379&gt; hmget myhash field1 field2 field3<br/>&nbsp;&nbsp;&nbsp;&nbsp;1) &quot;hello&quot;<br/>&nbsp;&nbsp;&nbsp;&nbsp;2) &quot;world&quot;<br/>&nbsp;&nbsp;&nbsp;&nbsp;3) (nil)<br/>&nbsp;&nbsp;&nbsp;&nbsp;#返回myhash键的所有字段及其值，从结果中可以看出，他们是逐对列出的。<br/>&nbsp;&nbsp;&nbsp;&nbsp;redis 127.0.0.1:6379&gt; hgetall myhash<br/>&nbsp;&nbsp;&nbsp;&nbsp;1) &quot;field1&quot;<br/>&nbsp;&nbsp;&nbsp;&nbsp;2) &quot;hello&quot;<br/>&nbsp;&nbsp;&nbsp;&nbsp;3) &quot;field2&quot;<br/>&nbsp;&nbsp;&nbsp;&nbsp;4) &quot;world&quot;<br/>&nbsp;&nbsp;&nbsp;&nbsp;#仅获取myhash键中所有字段的名字。<br/>&nbsp;&nbsp;&nbsp;&nbsp;redis 127.0.0.1:6379&gt; hkeys myhash<br/>&nbsp;&nbsp;&nbsp;&nbsp;1) &quot;field1&quot;<br/>&nbsp;&nbsp;&nbsp;&nbsp;2) &quot;field2&quot;<br/>&nbsp;&nbsp;&nbsp;&nbsp;#仅获取myhash键中所有字段的值。<br/>&nbsp;&nbsp;&nbsp;&nbsp;redis 127.0.0.1:6379&gt; hvals myhash<br/>&nbsp;&nbsp;&nbsp;&nbsp;1) &quot;hello&quot;<br/>&nbsp;&nbsp;&nbsp;&nbsp;2) &quot;world&quot; <br/><br/>来自：http://www.cnblogs.com/stephen-liu74/archive/2012/03/19/2352932.html<br/>实践如下：<br/>Redis学习手册(Hashes数据类型):<br/><br/>/usr/local/redis/bin/redis-cli -h 10.44.202.177 -p 6379<br/>10.44.202.177:6379&gt; hset myhash field1 &quot;stephen&quot;<br/>(integer) 1<br/>10.44.202.177:6379&gt;&nbsp;&nbsp;hget myhash field1<br/>&quot;stephen&quot;<br/>10.44.202.177:6379&gt; hget myhash field2<br/>(nil)<br/>10.44.202.177:6379&gt;&nbsp;&nbsp;hset myhash field2 &quot;liu&quot;<br/>(integer) 1<br/>10.44.202.177:6379&gt;&nbsp;&nbsp;hlen myhash<br/>(integer) 2<br/>10.44.202.177:6379&gt; hexists myhash field1<br/>(integer) 1<br/>10.44.202.177:6379&gt; <br/>10.44.202.177:6379&gt;&nbsp;&nbsp;hdel myhash field1<br/>(integer) 1<br/>10.44.202.177:6379&gt;&nbsp;&nbsp;hdel myhash field1<br/>(integer) 0<br/>10.44.202.177:6379&gt; hexists myhash field1<br/>(integer) 0<br/>10.44.202.177:6379&gt;&nbsp;&nbsp;hsetnx myhash field1 stephen<br/>(integer) 1<br/>10.44.202.177:6379&gt;&nbsp;&nbsp;hsetnx myhash field1 stephen<br/>(integer) 0<br/>10.44.202.177:6379&gt;&nbsp;&nbsp;del myhash<br/>(integer) 1<br/>10.44.202.177:6379&gt; hset myhash field 5<br/>(integer) 1<br/>10.44.202.177:6379&gt;&nbsp;&nbsp;hincrby myhash field 1<br/>(integer) 6<br/>10.44.202.177:6379&gt;&nbsp;&nbsp;hincrby myhash field -1<br/>(integer) 5<br/>10.44.202.177:6379&gt;&nbsp;&nbsp;hincrby myhash field -10<br/>(integer) -5<br/>10.44.202.177:6379&gt;&nbsp;&nbsp;del myhash<br/>(integer) 1<br/>10.44.202.177:6379&gt;&nbsp;&nbsp;hmset myhash field1 &quot;hello&quot; field2 &quot;world&quot;<br/>OK<br/>10.44.202.177:6379&gt;&nbsp;&nbsp;hmget myhash field1 field2 field3<br/>1) &quot;hello&quot;<br/>2) &quot;world&quot;<br/>3) (nil)<br/>10.44.202.177:6379&gt; hgetall myhash<br/>1) &quot;field1&quot;<br/>2) &quot;hello&quot;<br/>3) &quot;field2&quot;<br/>4) &quot;world&quot;<br/>10.44.202.177:6379&gt;&nbsp;&nbsp;hkeys myhash<br/>1) &quot;field1&quot;<br/>2) &quot;field2&quot;<br/>10.44.202.177:6379&gt; hvals myhash<br/>1) &quot;hello&quot;<br/>2) &quot;world&quot;<br/><br/><br/><br/>PHP如何设置Hash：<br/><br/>&lt;?php<br/>$redis = new redis();<br/>$redis-&gt;connect(&#039;10.51.77.34&#039;, 6379);<br/>$redis-&gt;delete(&#039;test&#039;);<br/>$redis-&gt;hset(&#039;test&#039;, &#039;key1&#039;, &#039;hello&#039;);<br/>echo $redis-&gt;hget(&#039;test&#039;, &#039;key1&#039;);&nbsp;&nbsp;&nbsp;&nbsp; //结果：hello<br/><br/>echo &quot;&lt;br&gt;&quot;;<br/>$redis-&gt;hSetNx(&#039;test&#039;, &#039;key1&#039;, &#039;world&#039;);<br/>echo $redis-&gt;hget(&#039;test&#039;, &#039;key1&#039;);&nbsp;&nbsp; //结果：hello<br/><br/>$redis-&gt;delete(&#039;test&#039;);<br/>$redis-&gt;hSetNx(&#039;test&#039;, &#039;key1&#039;, &#039;world&#039;);<br/>echo &quot;&lt;br&gt;&quot;;<br/>echo $redis-&gt;hget(&#039;test&#039;, &#039;key1&#039;);&nbsp;&nbsp; //结果：world<br/><br/>echo $redis-&gt;hlen(&#039;test&#039;);&nbsp;&nbsp; //结果：1<br/>var_dump($redis-&gt;hdel(&#039;test&#039;,&#039;key1&#039;));&nbsp;&nbsp;//结果：bool(true)<br/><br/>$redis-&gt;delete(&#039;test&#039;);<br/>$redis-&gt;hSet(&#039;test&#039;, &#039;a&#039;, &#039;x&#039;);<br/>$redis-&gt;hSet(&#039;test&#039;, &#039;b&#039;, &#039;y&#039;);<br/>$redis-&gt;hSet(&#039;test&#039;, &#039;c&#039;, &#039;z&#039;);<br/>print_r($redis-&gt;hkeys(&#039;test&#039;));&nbsp;&nbsp;//结果：Array ( [0] =&gt; a [1] =&gt; b [2] =&gt; c )<br/><br/>print_r($redis-&gt;hvals(&#039;test&#039;));&nbsp;&nbsp;//结果：Array ( [0] =&gt; x [1] =&gt; y [2] =&gt; z )<br/><br/>print_r($redis-&gt;hgetall(&#039;test&#039;));&nbsp;&nbsp;//结果：Array ( [a] =&gt; x [b] =&gt; y [c] =&gt; z )<br/><br/>var_dump($redis-&gt;hExists(&#039;test&#039;, &#039;a&#039;));&nbsp;&nbsp;//结果：bool(true)<br/><br/>$redis-&gt;delete(&#039;test&#039;);<br/>echo $redis-&gt;hIncrBy(&#039;test&#039;, &#039;a&#039;, 3);&nbsp;&nbsp;&nbsp;&nbsp;//结果：3<br/>echo $redis-&gt;hIncrBy(&#039;test&#039;, &#039;a&#039;, 1);&nbsp;&nbsp;&nbsp;&nbsp;//结果：4<br/><br/>$redis-&gt;delete(&#039;test&#039;);<br/>var_dump($redis-&gt;hmset(&#039;test&#039;, array(&#039;name&#039; =&gt;&#039;tank&#039;, &#039;sex&#039;=&gt;&quot;man&quot;))); //结果：bool(true)<br/>print_r($redis-&gt;hmget(&#039;test&#039;, array(&#039;name&#039;, &#039;sex&#039;)));&nbsp;&nbsp;//结果：Array ( [name] =&gt; tank [sex] =&gt; man )<br/><br/>$redis-&gt;hSet(&quot;hashA&quot;, &quot;name&quot;, &quot;iname&quot;);<br/>$redis-&gt;hSet(&quot;hashA&quot;, &quot;age&quot;, &quot;age&quot;);<br/><br/>// 同时设置多个值<br/>$redis-&gt;hMset(&quot;hashA&quot;, [<br/>&nbsp;&nbsp;&nbsp;&nbsp;&quot;gender&quot; =&gt; &quot;male&quot;,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&quot;salary&quot; =&gt; 12000<br/>]);<br/>$redis-&gt;hGet(&quot;hashA&quot;, &quot;salary&quot;);<br/><br/>// 获得多个值<br/>var_dump($redis-&gt;hMGet(&quot;hashA&quot;, [&quot;name&quot;, &quot;gender&quot;]));<br/>?&gt;<br/><br/><br/><br/><br/>php redishash.php <br/>hello&lt;br&gt;hello&lt;br&gt;world1int(1)<br/>Array<br/>(<br/>&nbsp;&nbsp;&nbsp;&nbsp;[0] =&gt; a<br/>&nbsp;&nbsp;&nbsp;&nbsp;[1] =&gt; b<br/>&nbsp;&nbsp;&nbsp;&nbsp;[2] =&gt; c<br/>)<br/>Array<br/>(<br/>&nbsp;&nbsp;&nbsp;&nbsp;[0] =&gt; x<br/>&nbsp;&nbsp;&nbsp;&nbsp;[1] =&gt; y<br/>&nbsp;&nbsp;&nbsp;&nbsp;[2] =&gt; z<br/>)<br/>Array<br/>(<br/>&nbsp;&nbsp;&nbsp;&nbsp;[a] =&gt; x<br/>&nbsp;&nbsp;&nbsp;&nbsp;[b] =&gt; y<br/>&nbsp;&nbsp;&nbsp;&nbsp;[c] =&gt; z<br/>)<br/>bool(true)<br/>34bool(true)<br/>Array<br/>(<br/>&nbsp;&nbsp;&nbsp;&nbsp;[name] =&gt; tank<br/>&nbsp;&nbsp;&nbsp;&nbsp;[sex] =&gt; man<br/>)<br/>array(2) &#123;<br/>&nbsp;&nbsp;[&quot;name&quot;]=&gt;<br/>&nbsp;&nbsp;string(5) &quot;iname&quot;<br/>&nbsp;&nbsp;[&quot;gender&quot;]=&gt;<br/>&nbsp;&nbsp;string(4) &quot;male&quot;<br/>&#125;<br/>来自：http://blog.csdn.net/qjwcn/article/details/45293035
]]>
</description>
</item><item>
<link>http://www.jackxiang.com/post/9201/</link>
<title><![CDATA[[实践OK]利用Redis的notifications功能实现延时任务,任务失败重试N次的机制实现,Node之Error: Cannot find module redis。]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[Cache与Store]]></category>
<pubDate>Thu, 22 Jun 2017 15:45:37 +0000</pubDate> 
<guid>http://www.jackxiang.com/post/9201/</guid> 
<description>
<![CDATA[ 
	PHP版本的实践：<a href="https://www.imooc.com/article/10431" target="_blank">https://www.imooc.com/article/10431</a><br/><br/>背景：在工作中经常会遇到一些关于定时任务的实际场景，比如每天凌晨1点自动备份数据库，或者，每隔1小时执行一次爬虫脚本，这种固定时间执行固定动作的需求我们称之为定时任务，利用crontab即可轻松实现。如果我们对自动备份数据库这个定时任务改变一下需求（这种情况就像你邀请一个人，一天内如果没有人来或有人来你通知下你，你邀请的人来了，这种任务。二、再就是公司没啥好的设备，钱少，网太烂了搞一个任务比如Mysql备份数据库的脚本，比如备份Redis的数据Bgsave的Scp拷贝经常出现网络不好，第一次备份会失败，于是得第二次这种垃圾需求。有垃圾需求就有解决办法，于于优雅或不优雅是一回事，但得技术人员觉得有一个流程总比没有流程好，本来没有方案的，于是就有技术方案。），如图：<br/>点击在新窗口中浏览此图片&nbsp;&nbsp; <br/>如果仍然利用crontab来实现，就有点勉强了。类似这种需求最常见的是服务器之间的消息通知，假如服务器B由于网络不稳定或者服务器压力较大导致不能即时对服务器A的消息作出正确响应，那么服务器A就会延迟一段时间再次发送消息，直到收到服务器B的正确响应或者超出最大通知次数为止。过去的做法是定时扫表，把通知失败的消息再次发送一遍，虽然可以多次发送通知，但是发送间隔太短会增加服务器B的压力，发送间隔太长消息的时效性就不能保证，显然处理这种延时任务用crontab根本不能解决问题。<br/>Node之Error: Cannot find module &#039;redis：<br/>#npm install -g redis<br/>/usr/lib<br/>└─┬ redis@2.7.1 <br/>&nbsp;&nbsp;├── double-ended-queue@2.1.0-0 <br/>&nbsp;&nbsp;├── redis-commands@1.3.1 <br/>&nbsp;&nbsp;└── redis-parser@2.6.0 <br/>环境变量：<br/>#rpm -ql nodejs-6.10.3-1.el7.x86_64 <br/>/usr/bin/node<br/>/usr/lib/node_modules<br/>export NODE_PATH=/usr/lib/node_modules<br/>#echo $NODE_PATH&nbsp;&nbsp;<br/>/usr/lib/node_modules<br/>#node notice.js <br/>订阅成功<br/><br/>select 3<br/>OK<br/>setex msg_2 2 chokingwin<br/>OK<br/>client.on(&quot;pmessage&quot;, function(pattern, channel, expiredKey) &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;console.log(pattern + &quot;&#124;&quot; + channel + &quot;&#124;&quot; + expiredKey);<br/>_&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _keyevent@3__:expired&#124;__keyevent@3__:expired&#124;msg_2<br/><br/><br/><br/><br/>从Redis 2.8.0版本起，加入了&quot;Keyspace notifications&quot;（即&quot;键空间通知&quot;）的功能。按照官方的说法：键空间通知，允许Redis客户端从“发布/订阅”通道中建立订阅关系，以便客户端能够在Redis中的数据因某种方式受到影响时收到相应事件。比如：所有改变给定key的命令；所有经过lpush操作的key；所有在0号数据库中过期的key等等。我们在处理延时任务的时候，先把通知失败的消息ID作为key的一部分存到redis缓存中，并设定过期时间（相当于延时），当这条缓存数据失效的时候，通过订阅关系（用NodeJS实现）就可以收到消息，通过分析消息就可以知道过期KEY，这样就可以再次发送消息通知，从而实现延时任务。<br/>不过，需要注意一点：Redis的发布/订阅目前是即发即弃(fire and forget)模式的，因此无法实现事件的可靠通知。也就是说，如果发布/订阅的客户端断链之后又重连，则在客户端断链期间的所有事件都丢失了。<br/>核心部分是两个Redis的终端，分别连接上Redis，并打开这个特性，另一个终端是监控的，这块里面用代码进行编写订阅，如下：<br/>订阅，作者用的是Node，我在这儿不得不打下广告了，Swoole是不是应该也能支持这个功能？https://wiki.swoole.com/wiki/page/523.html ,http://blog.csdn.net/koastal/article/details/52869140,subscribe。<br/>psubscribe来自：https://wiki.swoole.com/wiki/page/590.html<br/><br/>&lt;?php<br/>$serv = new Swoole&#92;Server(&quot;127.0.0.1&quot;, 9501);<br/>$serv-&gt;set(array(<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#039;worker_num&#039; =&gt; 8,&nbsp;&nbsp; //工作进程数量<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#039;daemonize&#039; =&gt; false, //是否作为守护进程<br/>));<br/>$serv-&gt;on(&#039;connect&#039;, function ($serv, $fd)&#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;echo &quot;Client:Connect.&#92;n&quot;;<br/>&#125;);<br/>$serv-&gt;on(&#039;receive&#039;, function ($serv, $fd, $from_id, $data) &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;$val = &quot;&quot;;<br/>&nbsp;&nbsp;&nbsp;&nbsp;$redis = new Swoole&#92;Coroutine&#92;Redis();<br/>&nbsp;&nbsp;&nbsp;&nbsp;$redis-&gt;connect(&#039;10.51.77.34&#039;, 6379);<br/>&nbsp;&nbsp;&nbsp;&nbsp;while (true) &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$val = $redis-&gt;psubscribe([&#039;psubscribe __keyevent@3__:expired&#039;]);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//订阅的channel，以第一次调用subscribe时的channel为准，后续的subscribe调用是为了收取Redis Server&gt;的回包<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//如果需要改变订阅的channel，请close掉连接，再调用subscribe<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;var_dump($val);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&#125;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>&#125;);<br/>$serv-&gt;on(&#039;close&#039;, function ($serv, $fd) &#123;<br/>&nbsp;&nbsp;&nbsp;&nbsp;echo &quot;Client: Close.&#92;n&quot;;<br/>&#125;);<br/>$serv-&gt;start();<br/><br/><br/>Swoole的这个Redis的Coroutine必须要有一个端口暴露，这是和Node最大的不同吧？上面这个图我试着使用了一下，感觉有点问题。<br/>=============================================================================<br/><br/>#redis-cli -h 10.51.77.34 <br/>10.51.77.34:6379&gt;&nbsp;&nbsp;psubscribe __keyevent@0__:expired<br/>Reading messages... (press Ctrl-C to quit)<br/>1) &quot;psubscribe&quot;<br/>2) &quot;__keyevent@0__:expired&quot;<br/>3) (integer) 1<br/><br/><br/><br/>1) &quot;pmessage&quot;<br/>2) &quot;__keyevent@0__:expired&quot;<br/>3) &quot;__keyevent@0__:expired&quot;<br/>4) &quot;name&quot;<br/><br/><br/><br/>塞一个数据进去：<br/><br/>#redis-cli -h 10.51.77.34 <br/>10.51.77.34:6379&gt; config set notify-keyspace-events Ex<br/>OK<br/>10.51.77.34:6379&gt; setex name 10 chokingwin<br/>OK<br/><br/><br/>===================================================================================<br/>关于expired事件通知的发送时间<br/>Redis使用以下两种方式删除过期的键：a：当一个键被访问时，程序会对这个键进行检查，如果键已过期，则删除该键；b：系统会在后台定期扫描并删除那些过期的键。<br/>当过期键被以上两种方式中的任意一种发现并且删除时，才会产生expired事件通知。<br/>Redis不保证生存时间（TTL）变为 0 的键会立即被删除：如果没有命令访问这个键，或者设置生存时间的键非常多的话，那么在键的生存时间变为0，到该键真正被删除，这中间可能会有一段比较显著的时间间隔。<br/>因此，Redis产生expired事件通知的时间，是过期键被删除的时候，而不是键的生存时间变为 0 的时候。<br/>接下来我们开始代码实现（假定阅读本文的同学已正确安装Nginx/PHP/Redis/NodeJS的环境）。<br/><br/>一、与本文相关的环境信息<br/>Redis配置文件路径：/etc/redis/6379.conf<br/>测试用的Redis库编号为：3<br/>监听消息的NodeJS文件：/NodeApp/notice.js<br/>发送消息的PHP代码为：/send.php<br/>接收redis数据的PHP代码：/test.php<br/>业务流程：首先运行notice.js开启监听，然后运行send.php发送消息，如果没有收到成功响应，将消息ID存入redis缓存，之后按照10秒、30秒、60秒、120秒、300秒的时间间隔，再次发送消息通知，直到收到对消息的成功响应，或者超出最大通知次数为止。<br/><br/>二、修改Redis配置文件<br/>因为键空间通知功能需要耗费一定的CPU时间，因此默认情况下，该功能是关闭的。可以通过修改配置文件，或者通过CONFIG SET命令，设置notify-keyspace-events选项，来启用或关闭该功能。<br/>该选项的值为空字符串时，该功能禁用，选项值为非空字符串时，启用该功能，非空字符串由特定的多个字符组成，每个字符表示不同的意义：<br/>K keyspace事件，事件以__keyspace@&lt;db&gt;__为前缀进行发布<br/>E keyevent事件，事件以__keyevent@&lt;db&gt;__为前缀进行发布<br/>g 一般性的，非特定类型的命令，比如del，expire，rename等<br/>$ 字符串特定命令<br/>l 列表特定命令<br/>s 集合特定命令<br/>h 哈希特定命令<br/>z 有序集合特定命令<br/>x 过期事件，当某个键过期并删除时会产生该事件<br/>e 驱逐事件，当某个键因maxmemore策略而被删除时，产生该事件<br/>A g$lshzxe的别名，因此”AKE”意味着所有事件<br/>注意：该选项的值中至少需要包含K或者E，否则不会发布任何事件。比如，如果需要开启针对列表的keyspace事件通知，则该选项需要配置为&quot;Kl&quot;。<br/><br/>我们在服务器上运行vim /etc/redis/6379.conf，找到notify-keyspace-events开头的一行，将其配置为：notify-keyspace-events Ex，含义为：发布keyevent事件，使用过期事件（当每一个key失效时，都会生成该事件）。保存退出，并重启redis服务。如图：<br/>点击在新窗口中浏览此图片<br/><br/>三、安装Node扩展<br/>在网站根目录下，依次运行：<br/>npm init #初始化创建package.json<br/>npm install redis #安装redis扩展<br/>npm install mysql #安装mysql扩展<br/><br/>四、实现send.php<br/><br/>为了便于实现延时的计算，我们将存入redis的key格式设计为：固定前缀+消息ID+时间戳+次数，如：noticeId_12345678_1482991887_2点击在新窗口中浏览此图片<br/>关键代码：<br/>$delayArr=[0,10,30,60,120,300];//延时间隔，相对于首次通知时间，单位为 s<br/>$res=doSomething();//发送消息<br/>$content=date(&#039;Y-m-d H:i:s&#039;).&#039; 第 &#039;.$nums.&#039; 次发送通知，消息ID为：&#039;.$noticeId.&quot;&#92;n&quot;;<br/>if($res==true)&#123;<br/>$content.=&#039;消息发送成功&#039;.&quot;&#92;n&quot;;<br/>&#125;else&#123;//未收到对方回应<br/>$content.=&#039;消息发送失败，等待下次重发&#039;.&quot;&#92;n&quot;;<br/>$expTime=$delayArr[$nums];<br/>$nums++;<br/>saveNoticeToRedis($noticeId,$stamp,$nums,$expTime);//存入缓存<br/>&#125;<br/>//记录日志<br/>file_put_contents($root.&#039;/tmp.log&#039;,$content,FILE_APPEND);<br/><br/>五、实现 notice.js<br/>服务器端运行notice.js后，会一直监听redis的Expired事件，取到ExpiredKey后，把消息ID、时间、通知次数，POST给test.php，从而实现再次发送消息。<br/><br/>关键代码：<br/>var client = redis.createClient(&#039;6379&#039;, &#039;127.0.0.1&#039;);<br/>client.psubscribe(&quot;__keyevent@&quot;+redisDB+&quot;__:expired&quot;,function()&#123;<br/>//console.log(&#039;订阅成功&#039;);<br/>&#125;);<br/>client.on(&quot;pmessage&quot;, function(pattern, channel, expiredKey) &#123;<br/>var tmpArr=expiredKey.split(&#039;_&#039;);<br/>if(tmpArr[0]==keyPrefix)&#123;<br/>console.log(&#039;-----expired Key-----&#039;,expiredKey);<br/>var noticeId=tmpArr[1];<br/>var stamp=parseInt(tmpArr[2]);<br/>var nums=parseInt(tmpArr[3]);<br/>sendPost(noticeId,stamp,nums,logFile);//向test.php发送数据<br/>&#125;else&#123;<br/>console.log(&#039;-----error Key-----&#039;,expiredKey);<br/>writeLog(logFile,&#039;The key &quot;&#039;+expiredKey+&#039;&quot; is a error key.&#039;);<br/>&#125;<br/>&#125;);<br/><br/>六、实现 test.php<br/>点击在新窗口中浏览此图片<br/><br/>关键代码：<br/><br/>$delayArr=[0,10,30,60,120,300];//延时间隔，相对于首次通知时间，单位为 s<br/>$res=doSomething();//发送消息<br/>$content=date(&#039;Y-m-d H:i:s&#039;).&#039; 第 &#039;.$nums.&#039; 次发送通知，消息ID为：&#039;.$noticeId.&quot;&#92;n&quot;;<br/>if($res==true)&#123;<br/>$content.=&#039;消息发送成功&#039;.&quot;&#92;n&quot;;<br/>&#125;else&#123;//未收到对方回应<br/>if($nums &amp;&amp; $nums&gt;=6)&#123;<br/>$content.=&#039;消息ID：&#039;.$noticeId.&quot;已达到最大通知次数，任务停止&#92;n&quot;;<br/>&#125;else&#123;<br/>$content.=&#039;消息发送失败，等待下次重发&#039;.&quot;&#92;n&quot;;<br/>$expTime=$stamp+$delayArr[$nums]-time();<br/>$nums++;<br/>saveNoticeToRedis($noticeId,$stamp,$nums,$expTime);//存入缓存<br/>&#125;<br/>&#125;<br/>//记录日志<br/>file_put_contents($root.&#039;/tmp.log&#039;,$content,FILE_APPEND);<br/><br/>七、测试结果<br/>点击在新窗口中浏览此图片<br/><br/>八、其他说明<br/>本文内容为个人原创，首发今日头条，同时提供代码下载地址，供大家学习交流。本人以后还会发布更多原创干货，如果觉得有用，希望及时关注本头条号。<br/><br/>代码下载地址：http://www.i1981.com/zb_users/upload/2016/12/20161223.zip<br/>DownLoad：<br/>下载文件<br/>点击这里下载文件<br/><br/><br/>From: http://www.toutiao.com/a6369425996433408257/?tt_from=weixin&amp;utm_campaign=client_share&amp;app=news_article&amp;utm_source=weixin&amp;iid=11032449540&amp;utm_medium=toutiao_ios&amp;wxshare_count=1
]]>
</description>
</item><item>
<link>http://www.jackxiang.com/post/9154/</link>
<title><![CDATA[Redis-benchmark测试Redis性能]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[Cache与Store]]></category>
<pubDate>Wed, 04 Jan 2017 09:30:52 +0000</pubDate> 
<guid>http://www.jackxiang.com/post/9154/</guid> 
<description>
<![CDATA[ 
	背景： 有时间对Redis的一个测试来看，特别是经过了网络，此时，会傻傻分不清楚是Redis本来性能就差，还是网络不好（PHP调用Redis的机器和Redis分离或不在同一网段），这个工具可以直接在Redis上测试Redis，或是在PHP上测试Redis，这样有一个粗粒度的判断和把握。<br/><br/><textarea name="code" class="php" rows="15" cols="100">
测试命令事例：

1、redis-benchmark -h 192.168.1.201 -p 6379 -c 100 -n 100000 
100个并发连接，100000个请求，检测host为localhost 端口为6379的redis服务器性能 
</textarea><br/><br/><br/>Redis-benchmark是官方自带的Redis性能测试工具，可以有效的测试Redis服务的性能。<br/><br/>使用说明如下：<br/><br/>复制代码<br/>Usage: redis-benchmark [-h &lt;host&gt;] [-p &lt;port&gt;] [-c &lt;clients&gt;] [-n &lt;requests]&gt; [-k &lt;boolean&gt;]<br/><br/> -h &lt;hostname&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Server hostname (default 127.0.0.1)<br/> -p &lt;port&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Server port (default 6379)<br/> -s &lt;socket&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Server socket (overrides host and port)<br/> -c &lt;clients&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Number of parallel connections (default 50)<br/> -n &lt;requests&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Total number of requests (default 10000)<br/> -d &lt;size&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Data size of SET/GET value in bytes (default 2)<br/> -k &lt;boolean&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1=keep alive 0=reconnect (default 1)<br/> -r &lt;keyspacelen&gt;&nbsp;&nbsp; Use random keys for SET/GET/INCR, random values for SADD<br/>&nbsp;&nbsp;Using this option the benchmark will get/set keys<br/>&nbsp;&nbsp;in the form mykey_rand:000000012456 instead of constant<br/>&nbsp;&nbsp;keys, the &lt;keyspacelen&gt; argument determines the max<br/>&nbsp;&nbsp;number of values for the random number. For instance<br/>&nbsp;&nbsp;if set to 10 only rand:000000000000 - rand:000000000009<br/>&nbsp;&nbsp;range will be allowed.<br/> -P &lt;numreq&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Pipeline &lt;numreq&gt; requests. Default 1 (no pipeline).<br/> -q&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Quiet. Just show query/sec values<br/> --csv&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Output in CSV format<br/> -l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Loop. Run the tests forever<br/> -t &lt;tests&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Only run the comma-separated list of tests. The test<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;names are the same as the ones produced as output.<br/> -I&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Idle mode. Just open N idle connections and wait.<br/>复制代码<br/><br/>测试命令事例：<br/><br/>1、redis-benchmark -h 192.168.1.201 -p 6379 -c 100 -n 100000 <br/>100个并发连接，100000个请求，检测host为localhost 端口为6379的redis服务器性能 <br/><br/>2、redis-benchmark -h 192.168.1.201 -p 6379 -q -d 100&nbsp;&nbsp;<br/><br/>测试存取大小为100字节的数据包的性能<br/><br/>3、redis-benchmark -t set,lpush -n 100000 -q<br/><br/>只测试某些操作的性能<br/><br/>4、redis-benchmark -n 100000 -q script load &quot;redis.call(&#039;set&#039;,&#039;foo&#039;,&#039;bar&#039;)&quot;<br/><br/>只测试某些数值存取的性能<br/><br/> <br/><br/>测试结果分析：<br/><br/>复制代码<br/>&nbsp;&nbsp;10000 requests completed in 0.30 seconds<br/>&nbsp;&nbsp;100 parallel clients<br/>&nbsp;&nbsp;3 bytes payload<br/>&nbsp;&nbsp;keep alive: 1<br/><br/>0.11% &lt;= 1 milliseconds<br/>86.00% &lt;= 2 milliseconds<br/>90.12% &lt;= 3 milliseconds<br/>96.68% &lt;= 4 milliseconds<br/>99.27% &lt;= 5 milliseconds<br/>99.54% &lt;= 6 milliseconds<br/>99.69% &lt;= 7 milliseconds<br/>99.78% &lt;= 8 milliseconds<br/>99.89% &lt;= 9 milliseconds<br/>100.00% &lt;= 9 milliseconds<br/>33222.59 requests per second<br/><br/>====== PING_BULK ======<br/>&nbsp;&nbsp;10000 requests completed in 0.27 seconds<br/>&nbsp;&nbsp;100 parallel clients<br/>&nbsp;&nbsp;3 bytes payload<br/>&nbsp;&nbsp;keep alive: 1<br/><br/>0.93% &lt;= 1 milliseconds<br/>97.66% &lt;= 2 milliseconds<br/>100.00% &lt;= 2 milliseconds<br/>37174.72 requests per second<br/><br/>====== SET ======<br/>&nbsp;&nbsp;10000 requests completed in 0.32 seconds<br/>&nbsp;&nbsp;100 parallel clients<br/>&nbsp;&nbsp;3 bytes payload<br/>&nbsp;&nbsp;keep alive: 1<br/><br/>0.22% &lt;= 1 milliseconds<br/>91.68% &lt;= 2 milliseconds<br/>97.78% &lt;= 3 milliseconds<br/>98.80% &lt;= 4 milliseconds<br/>99.38% &lt;= 5 milliseconds<br/>99.61% &lt;= 6 milliseconds<br/>99.72% &lt;= 7 milliseconds<br/>99.83% &lt;= 8 milliseconds<br/>99.94% &lt;= 9 milliseconds<br/>100.00% &lt;= 9 milliseconds<br/>30959.75 requests per second<br/><br/>====== GET ======<br/>&nbsp;&nbsp;10000 requests completed in 0.28 seconds<br/>&nbsp;&nbsp;100 parallel clients<br/>&nbsp;&nbsp;3 bytes payload<br/>&nbsp;&nbsp;keep alive: 1<br/><br/>0.55% &lt;= 1 milliseconds<br/>98.86% &lt;= 2 milliseconds<br/>100.00% &lt;= 2 milliseconds<br/>35971.22 requests per second<br/><br/>====== INCR ======<br/>&nbsp;&nbsp;10000 requests completed in 0.14 seconds<br/>&nbsp;&nbsp;100 parallel clients<br/>&nbsp;&nbsp;3 bytes payload<br/>&nbsp;&nbsp;keep alive: 1<br/><br/>95.61% &lt;= 1 milliseconds<br/>100.00% &lt;= 1 milliseconds<br/>69444.45 requests per second<br/><br/>====== LPUSH ======<br/>&nbsp;&nbsp;10000 requests completed in 0.21 seconds<br/>&nbsp;&nbsp;100 parallel clients<br/>&nbsp;&nbsp;3 bytes payload<br/>&nbsp;&nbsp;keep alive: 1<br/><br/>18.33% &lt;= 1 milliseconds<br/>100.00% &lt;= 1 milliseconds<br/>48309.18 requests per second<br/><br/>====== LPOP ======<br/>&nbsp;&nbsp;10000 requests completed in 0.23 seconds<br/>&nbsp;&nbsp;100 parallel clients<br/>&nbsp;&nbsp;3 bytes payload<br/>&nbsp;&nbsp;keep alive: 1<br/><br/>0.29% &lt;= 1 milliseconds<br/>99.76% &lt;= 2 milliseconds<br/>100.00% &lt;= 2 milliseconds<br/>44052.86 requests per second<br/><br/>====== SADD ======<br/>&nbsp;&nbsp;10000 requests completed in 0.22 seconds<br/>&nbsp;&nbsp;100 parallel clients<br/>&nbsp;&nbsp;3 bytes payload<br/>&nbsp;&nbsp;keep alive: 1<br/><br/>2.37% &lt;= 1 milliseconds<br/>99.81% &lt;= 2 milliseconds<br/>100.00% &lt;= 2 milliseconds<br/>44444.45 requests per second<br/><br/>====== SPOP ======<br/>&nbsp;&nbsp;10000 requests completed in 0.22 seconds<br/>&nbsp;&nbsp;100 parallel clients<br/>&nbsp;&nbsp;3 bytes payload<br/>&nbsp;&nbsp;keep alive: 1<br/><br/>4.27% &lt;= 1 milliseconds<br/>99.84% &lt;= 2 milliseconds<br/>100.00% &lt;= 2 milliseconds<br/>44642.86 requests per second<br/><br/>====== LPUSH (needed to benchmark LRANGE) ======<br/>&nbsp;&nbsp;10000 requests completed in 0.22 seconds<br/>&nbsp;&nbsp;100 parallel clients<br/>&nbsp;&nbsp;3 bytes payload<br/>&nbsp;&nbsp;keep alive: 1<br/><br/>12.35% &lt;= 1 milliseconds<br/>99.62% &lt;= 2 milliseconds<br/>100.00% &lt;= 2 milliseconds<br/>46082.95 requests per second<br/><br/>====== LRANGE_100 (first 100 elements) ======<br/>&nbsp;&nbsp;10000 requests completed in 0.48 seconds<br/>&nbsp;&nbsp;100 parallel clients<br/>&nbsp;&nbsp;3 bytes payload<br/>&nbsp;&nbsp;keep alive: 1<br/><br/>0.01% &lt;= 1 milliseconds<br/>3.27% &lt;= 2 milliseconds<br/>98.71% &lt;= 3 milliseconds<br/>99.93% &lt;= 4 milliseconds<br/>100.00% &lt;= 4 milliseconds<br/>20964.36 requests per second<br/><br/>====== LRANGE_300 (first 300 elements) ======<br/>&nbsp;&nbsp;10000 requests completed in 1.26 seconds<br/>&nbsp;&nbsp;100 parallel clients<br/>&nbsp;&nbsp;3 bytes payload<br/>&nbsp;&nbsp;keep alive: 1<br/><br/>0.01% &lt;= 2 milliseconds<br/>0.14% &lt;= 3 milliseconds<br/>0.90% &lt;= 4 milliseconds<br/>7.03% &lt;= 5 milliseconds<br/>31.68% &lt;= 6 milliseconds<br/>78.93% &lt;= 7 milliseconds<br/>98.88% &lt;= 8 milliseconds<br/>99.56% &lt;= 9 milliseconds<br/>99.72% &lt;= 10 milliseconds<br/>99.95% &lt;= 11 milliseconds<br/>100.00% &lt;= 11 milliseconds<br/>7961.78 requests per second<br/><br/>====== LRANGE_500 (first 450 elements) ======<br/>&nbsp;&nbsp;10000 requests completed in 1.82 seconds<br/>&nbsp;&nbsp;100 parallel clients<br/>&nbsp;&nbsp;3 bytes payload<br/>&nbsp;&nbsp;keep alive: 1<br/><br/>0.01% &lt;= 2 milliseconds<br/>0.06% &lt;= 3 milliseconds<br/>0.14% &lt;= 4 milliseconds<br/>0.30% &lt;= 5 milliseconds<br/>0.99% &lt;= 6 milliseconds<br/>2.91% &lt;= 7 milliseconds<br/>8.11% &lt;= 8 milliseconds<br/>43.15% &lt;= 9 milliseconds<br/>88.38% &lt;= 10 milliseconds<br/>97.25% &lt;= 11 milliseconds<br/>98.61% &lt;= 12 milliseconds<br/>99.26% &lt;= 13 milliseconds<br/>99.30% &lt;= 14 milliseconds<br/>99.44% &lt;= 15 milliseconds<br/>99.48% &lt;= 16 milliseconds<br/>99.64% &lt;= 17 milliseconds<br/>99.85% &lt;= 18 milliseconds<br/>99.92% &lt;= 19 milliseconds<br/>99.95% &lt;= 20 milliseconds<br/>99.96% &lt;= 21 milliseconds<br/>99.97% &lt;= 22 milliseconds<br/>100.00% &lt;= 23 milliseconds<br/>5491.49 requests per second<br/><br/>====== LRANGE_600 (first 600 elements) ======<br/>&nbsp;&nbsp;10000 requests completed in 2.29 seconds<br/>&nbsp;&nbsp;100 parallel clients<br/>&nbsp;&nbsp;3 bytes payload<br/>&nbsp;&nbsp;keep alive: 1<br/><br/>0.01% &lt;= 2 milliseconds<br/>0.05% &lt;= 3 milliseconds<br/>0.10% &lt;= 4 milliseconds<br/>0.19% &lt;= 5 milliseconds<br/>0.34% &lt;= 6 milliseconds<br/>0.46% &lt;= 7 milliseconds<br/>0.58% &lt;= 8 milliseconds<br/>4.46% &lt;= 9 milliseconds<br/>21.80% &lt;= 10 milliseconds<br/>40.48% &lt;= 11 milliseconds<br/>60.14% &lt;= 12 milliseconds<br/>79.81% &lt;= 13 milliseconds<br/>93.77% &lt;= 14 milliseconds<br/>97.14% &lt;= 15 milliseconds<br/>98.67% &lt;= 16 milliseconds<br/>99.08% &lt;= 17 milliseconds<br/>99.30% &lt;= 18 milliseconds<br/>99.41% &lt;= 19 milliseconds<br/>99.52% &lt;= 20 milliseconds<br/>99.61% &lt;= 21 milliseconds<br/>99.79% &lt;= 22 milliseconds<br/>99.88% &lt;= 23 milliseconds<br/>99.89% &lt;= 24 milliseconds<br/>99.95% &lt;= 26 milliseconds<br/>99.96% &lt;= 27 milliseconds<br/>99.97% &lt;= 28 milliseconds<br/>99.98% &lt;= 29 milliseconds<br/>100.00% &lt;= 29 milliseconds<br/>4359.20 requests per second<br/><br/>====== MSET (10 keys) ======<br/>&nbsp;&nbsp;10000 requests completed in 0.37 seconds<br/>&nbsp;&nbsp;100 parallel clients<br/>&nbsp;&nbsp;3 bytes payload<br/>&nbsp;&nbsp;keep alive: 1<br/><br/>0.01% &lt;= 1 milliseconds<br/>2.00% &lt;= 2 milliseconds<br/>18.41% &lt;= 3 milliseconds<br/>88.55% &lt;= 4 milliseconds<br/>96.09% &lt;= 5 milliseconds<br/>99.50% &lt;= 6 milliseconds<br/>99.65% &lt;= 7 milliseconds<br/>99.75% &lt;= 8 milliseconds<br/>99.77% &lt;= 9 milliseconds<br/>99.78% &lt;= 11 milliseconds<br/>99.79% &lt;= 12 milliseconds<br/>99.80% &lt;= 13 milliseconds<br/>99.81% &lt;= 15 milliseconds<br/>99.82% &lt;= 16 milliseconds<br/>99.83% &lt;= 17 milliseconds<br/>99.84% &lt;= 19 milliseconds<br/>99.85% &lt;= 21 milliseconds<br/>99.86% &lt;= 23 milliseconds<br/>99.87% &lt;= 24 milliseconds<br/>99.88% &lt;= 25 milliseconds<br/>99.89% &lt;= 27 milliseconds<br/>99.90% &lt;= 28 milliseconds<br/>99.91% &lt;= 30 milliseconds<br/>99.92% &lt;= 32 milliseconds<br/>99.93% &lt;= 34 milliseconds<br/>99.95% &lt;= 35 milliseconds<br/>99.96% &lt;= 36 milliseconds<br/>99.97% &lt;= 37 milliseconds<br/>99.98% &lt;= 39 milliseconds<br/>99.99% &lt;= 41 milliseconds<br/>100.00% &lt;= 41 milliseconds<br/>27173.91 requests per second<br/><br/><br/>摘自：http://www.cnblogs.com/silent2012/p/4514901.html
]]>
</description>
</item><item>
<link>http://www.jackxiang.com/post/9102/</link>
<title><![CDATA[redis的hGetAll函数的性能问题，redis缓慢多是hgetall导致的当然其他的情况也有...]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[Cache与Store]]></category>
<pubDate>Mon, 12 Dec 2016 06:17:58 +0000</pubDate> 
<guid>http://www.jackxiang.com/post/9102/</guid> 
<description>
<![CDATA[ 
	背景：如果redis缓慢多是hgetall导致的当然其他的情况也有...<br/><br/>在没关注这个函数之前，一直用的Memcache的数据存储方式，但是自从更换了redis之后，对于一个hash的数据存与取 对于Memcache方便甚多，但是问题来了，一个hash的列表如果量不大的情况，用hGetAll函数几乎看不出问题，一旦这个列表超过50或者更多时，此时用hGetAll函数便能很直观的看到性能问题，这里就不作数据分析了。<br/><br/>Redis是单线程的！当它处理一个请求时其他的请求只能等着。通常请求都会很快处理完，但是当我们使用HGETALL的时候，必须遍历每个字段来获取数据，这期间消耗的CPU资源和字段数成正比，如果还用了PIPELINING，无疑更是雪上加霜。<br/>PERFORMANCE = CPUs / OPERATIONs<br/>也就是说，此场景下为了提升性能，要么增加运算过程中的CPU数量；要么降低运算过程中的操作数量。在为了继续使用hash结构的数据，又要解决此问题，比较方便的方法就是将hash以序列化字符串存储，取的时候先取出反序列化的数据，再用hGet(key,array(hash..))。<br/><br/>例如：<br/>....<br/>$arrKey = array(&#039;dbfba184bef630526a75f2cd073a6098&#039;,&#039;dbfba184bef630526a75f2cd0dswet98&#039;)<br/>$strKey = &#039;test&#039;;<br/>$obj-&gt;hmGet($strKey,$arrKey);<br/>把原本的hGetAll操作简化为hGet，也就是说，不再需要遍历hash中的每一个字段，因此即便不能让多个CPU参与运算，但是却大幅降低了操作数量，所以性能的提升仍然是显著的；当然劣势也很明显，和所有的冗余方式一样，此方案浪费了大量的内存。<br/><br/>有人会问，这样虽然没有了遍历字段的过程，但是却增加了反序列化的过程，而反序列化的成本往往也是很高的，难道这样也能提升性能？问题的关键在于开始我们遍历字段的操作是在一个cpu上完成的，后来反序列化的操作，不管是什么语言，都可以通过多进程或多线程来保证是在多个cpu上完成的，所以性能总体上是提升的。<br/><br/>另外，很多人直觉是通过运行redis多实例来解决问题。确实，这样可以增加运算过程中的CPU数量，有助于提升性能，但是需要注意的是，hGetAll和PIPELINING往往会让运算过程中的操作数量呈几何级爆炸式增长，相比之下，我们能增加的redis多实例数量简直就是杯水车薪，所以本例中这种方法不能彻底解决问题。<br/><br/>来自：http://www.mudbest.com/redis%E7%9A%84hgetall%E5%87%BD%E6%95%B0%E7%9A%84%E6%80%A7%E8%83%BD%E9%97%AE%E9%A2%98/?utm_source=tuicool&amp;utm_medium=referral
]]>
</description>
</item><item>
<link>http://www.jackxiang.com/post/8868/</link>
<title><![CDATA[redis默认记录超过10000us的命令，默认保留128条慢查询日志。]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[Cache与Store]]></category>
<pubDate>Tue, 09 Aug 2016 06:35:05 +0000</pubDate> 
<guid>http://www.jackxiang.com/post/8868/</guid> 
<description>
<![CDATA[ 
	Redis的慢日志是一个系统记录了超出规定的执行时间查询。执行时间不包括I/O操作，比如与客户会话，发送回复等等，只是实际执行的命令(这就是线程被阻塞而无法执行命令的唯一阶段所需的时间为在此期间其他请求)。可以用两个参数来配置的慢日志：slowlog-log-slower-than告诉Redis是什么的执行时间，以微秒为单位，以超过为获得记录的命令。需要注意的是负数禁用慢日志，而零值强制每个命令的记录。slowlog-max-len是慢日志的长度。最小值是零。当一个新的命令被记录和慢日志已处于其最大长度时，最早的一个是从记录的命令队列中移出以腾出空间。该配置可以通过编辑redis.conf完成或当服务器使用CONFIG GET和Config中设置的命令运行。<br/><br/>一、Redis默认记录超过10000us的命令：<br/>10.64.*.54:6379&gt; config get slowlog-log-slower-than<br/>1) &quot;slowlog-log-slower-than&quot;<br/>2) &quot;10000&quot;<br/><br/><br/>二、默认保留128条慢查询日志：<br/>10.64.*.54:6379&gt; config get slowlog-max-len<br/>1) &quot;slowlog-max-len&quot;<br/>2) &quot;128&quot;<br/><br/><br/>三、慢查询日志查询，2条：<br/>[root@rh08 ~]# redis-cli -h 10.64.*.54<br/>10.64.6.54:6379&gt;&nbsp;&nbsp;slowlog get 2<br/>1) 1) (integer) 2<br/>&nbsp;&nbsp; 2) (integer) 1470219973<br/>&nbsp;&nbsp; 3) (integer) 36910<br/>&nbsp;&nbsp; 4) 1) &quot;info&quot;<br/>2) 1) (integer) 1<br/>&nbsp;&nbsp; 2) (integer) 1469739564<br/>&nbsp;&nbsp; 3) (integer) 14997<br/>&nbsp;&nbsp; 4) 1) &quot;save&quot;
]]>
</description>
</item><item>
<link>http://www.jackxiang.com/post/7814/</link>
<title><![CDATA[[实践OK]libmemcached使用（c 客户端连接 memcached），封装 libmemcached 构建 memcached 客户端。]]></title> 
<author>jack &lt;xdy108@126.com&gt;</author>
<category><![CDATA[Cache与Store]]></category>
<pubDate>Sun, 15 Feb 2015 09:05:39 +0000</pubDate> 
<guid>http://www.jackxiang.com/post/7814/</guid> 
<description>
<![CDATA[ 
	背景：如果要用c写成一个服务部署4台机器，均得和memcached交互，还得用这个库，如PHP的扩展啥的没怎么和c的lib打交到，这下实践一下挺好的，过程比较曲折但是也发现了这memcached用新的gcc还是对配置上有一些影响的，就单说配置这块的门槛就变高了，更别说c下的调试啥的，实践起来仅仅通过网上的一篇文章未必能搞定。<br/>libmemcached是C客户端到memcached服 务器的接口库。具有低内存占用率、线程安全、并提供对memcached功能的全面支持。它还采用多种命令行工具，包括： memcat、memflush、memrm、memstat、memslap。<br/>在Ubuntu上安装memcached和libmemcached&nbsp;&nbsp;http://www.linuxidc.com/Linux/2010-04/25543.htm<br/>libmemcached C/C++ API使用实例 http://www.linuxidc.com/Linux/2012-01/52516.htm<br/>memcached简单的使用教程(转载):&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;http://blog.csdn.net/huangqiwa/article/details/21174425<br/>使用连接池访问memcached(libmemcached)的完整例子:http://blog.csdn.net/hzhxxx/article/details/41961355<br/><br/>（1）封装 libmemcached 构建 memcached 客户端：http://blog.csdn.net/yanghw0510/article/details/7292236<br/>（2）libmemcached使用（c 客户端连接 memcached） :<br/>（3）libmemcached 下载地址。https://launchpad.net/libmemcached/<br/><br/>1、下载安装libmemcached <br/> $ wget http://launchpad.net/libmemcached/1.0/0.44/+download/libmemcached-0.44.tar.gz<br/> $ tar xvzf libmemcached-0.44tar.gz <br/> $ cd libmemcached-0.44<br/> $ ./configure<br/> $ make<br/> $ sudo make install<br/> libmemcached 默认安装在/usr/local/,头文件安装在/usr/local/include/libmemcachde/,动态库默认安装在/usr/local/lib/下。<br/>我在这儿下的：https://launchpadlibrarian.net/165454254/libmemcached-1.0.18.tar.gz<br/>注:<br/>如果报”./libmemcached-1.0/memcached.h:46:27: error: tr1/cinttypes: No such file or directory”错误,则需要升级gcc版本.<br/>处理如下：<br/>yum install gcc44 gcc44-c++ libstdc++44-devel<br/>export CC=/usr/bin/gcc44<br/>export CXX=/usr/bin/g++44<br/>重新编译安装libmemcached-1.0.9<br/>关键信息：error: tr1/cinttypes: No such file or directory<br/>报错原因：libmemcached需要 gcc 4.2 以上版本才可编译，而centos 5.4 的gcc版本只有4.1 ，详见：https://bugs.launchpad.net/libmemcached/+bug/1076181<br/>解决方法：安装gcc44的扩展包，详见：http://gearman.info/build/centos5-8.html<br/>export就是在于此，把这个gcc和g++的版本号给提上去，以方便这个memcached的编译：<br/>/usr/bin/gcc44 -v<br/>gcc version 4.4.7 20120313 (Red Hat 4.4.7-1) (GCC)<br/><br/>gcc -v<br/>gcc version 4.1.2 20080704 (Red Hat 4.1.2-46)<br/><br/>/usr/bin/g++44 -v<br/>gcc version 4.4.7 20120313 (Red Hat 4.4.7-1) (GCC) <br/> g++ -v<br/>gcc version 4.1.2 20080704 (Red Hat 4.1.2-46)<br/>——————————————————————————————————————————————————————————<br/>这个问题在安gearman时也遇到过，升级gcc，参考连接： http://jackxiang.com/post/7693/ ，软链接如下所示：<br/> export CC=/usr/bin/gcc44 or export CC=/usr/bin/gcc<br/> export CXX=/usr/bin/g++44<br/> ./configure &amp;&amp; make &amp;&amp; make install&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br/><br/>./configure &amp;&amp; make &amp;&amp; make install<br/> /usr/bin/install -c -m 644 support/libmemcached.pc &#039;/usr/local/lib/pkgconfig&#039;<br/>make[2]: Leaving directory `/tmp/testmemcachedcpp/libmemcached-1.0.18&#039;<br/>make[1]: Leaving directory `/tmp/testmemcachedcpp/libmemcached-1.0.18&#039;<br/><br/>g++ -o testmemcached testmemcached.cpp -lmemcached&nbsp;&nbsp;<br/>In file included from /usr/local/include/libmemcached/memcached.h:39,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from testmemcached.cpp:6:<br/>/usr/local/include/libmemcached-1.0/memcached.h:46:23: error: cinttypes: No such file or directory<br/>明天再整下，估计是so没有给ldd进来...<br/>2、libmemcached简单测试使用<br/><textarea name="code" class="php" rows="15" cols="100">
//g++ -o testmemcached testmemcached.cpp -lmemcached
///usr/bin/g++44 -g&nbsp;&nbsp;-o testmemcached testmemcached.cpp -lmemcached -lrt&nbsp;&nbsp;-std=c++0x

#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;libmemcached/memcached.h&gt;

using namespace std;

int main(int argc,char *argv[])
&#123;
&nbsp;&nbsp; //connect server

&nbsp;&nbsp; memcached_st *memc;
&nbsp;&nbsp; memcached_return rc;
&nbsp;&nbsp; memcached_server_st *server;
&nbsp;&nbsp; time_t expiration;
&nbsp;&nbsp; uint32_t flags;

&nbsp;&nbsp; memc = memcached_create(NULL);
&nbsp;&nbsp; server = memcached_server_list_append(NULL,&quot;localhost&quot;,11211,&amp;rc);
&nbsp;&nbsp; rc=memcached_server_push(memc,server);
&nbsp;&nbsp; memcached_server_list_free(server);

&nbsp;&nbsp; string key = &quot;key&quot;;
&nbsp;&nbsp; string value = &quot;value&quot;;
&nbsp;&nbsp; size_t value_length = value.length();
&nbsp;&nbsp; size_t key_length = key.length();


&nbsp;&nbsp; //Save data

&nbsp;&nbsp; rc=memcached_set(memc,key.c_str(),key.length(),value.c_str(),value.length(),expiration,flags);
&nbsp;&nbsp; if(rc==MEMCACHED_SUCCESS)
&nbsp;&nbsp; &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout&lt;&lt;&quot;Save data:&quot;&lt;&lt;value&lt;&lt;&quot; sucessful!&quot;&lt;&lt;endl;
&nbsp;&nbsp; &#125;

&nbsp;&nbsp; //Get data

&nbsp;&nbsp; char* result = memcached_get(memc,key.c_str(),key_length,&amp;value_length,&amp;flags,&amp;rc);
&nbsp;&nbsp; if(rc == MEMCACHED_SUCCESS)
&nbsp;&nbsp; &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout&lt;&lt;&quot;Get value:&quot;&lt;&lt;result&lt;&lt;&quot; sucessful!&quot;&lt;&lt;endl;
&nbsp;&nbsp; &#125;

&nbsp;&nbsp; //Delete data

&nbsp;&nbsp; rc=memcached_delete(memc,key.c_str(),key_length,expiration);
&nbsp;&nbsp; if(rc==MEMCACHED_SUCCESS)
&nbsp;&nbsp; &#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cout&lt;&lt;&quot;Delete key:&quot;&lt;&lt;key&lt;&lt;&quot; sucessful!&quot;&lt;&lt;endl;
&nbsp;&nbsp; &#125;

&nbsp;&nbsp; //free

&nbsp;&nbsp; memcached_free(memc);
&nbsp;&nbsp; return 0;
&#125;
</textarea><br/><br/>编译：g++ -o testmemcached testmemcached.cpp -lmemcached<br/>运行：./testmemcached<br/>结果：Save data:value sucessful!<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Get value:value sucessful!<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Delete key:key sucessful!<br/><br/>实践编译一下：<br/> g++ -o testmemcached testmemcached.cpp -lmemcached<br/>In file included from /usr/local/include/libmemcached/memcached.h:39,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from testmemcached.cpp:6:<br/>/usr/local/include/libmemcached-1.0/memcached.h:46:23: error: cinttypes: No such file or directory<br/>看来还得重新export一次新的编译器，因为昨天的关了终端，今天的又没了：<br/> export CC=/usr/bin/gcc44 or export CC=/usr/bin/gcc&nbsp;&nbsp;//这行有问题~<br/> export CXX=/usr/bin/g++44<br/> g++ -o testmemcached testmemcached.cpp -lmemcached<br/>为何还是不行？<br/> echo $CC<br/>/usr/bin/gcc&nbsp;&nbsp;//没变，这儿有问题，再重新设置一次，查到上面这个or有问题：export CC=/usr/bin/gcc44。<br/># echo $CXX<br/>/usr/bin/g++44 //变了<br/><br/>重新设置，好了：<br/>export CC=/usr/bin/gcc44<br/>/usr/bin/gcc44<br/><br/>继续折腾，/usr/bin/gcc44 -o testmemcached testmemcached.cpp -lmemcached <br/>In file included from /usr/lib/gcc/x86_64-redhat-linux6E/4.4.7/../../../../include/c++/4.4.7/cinttypes:35,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from /usr/local/include/libmemcached-1.0/memcached.h:46,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from /usr/local/include/libmemcached/memcached.h:39,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; from testmemcached.cpp:6:<br/>/usr/lib/gcc/x86_64-redhat-linux6E/4.4.7/../../../../include/c++/4.4.7/c++0x_warning.h:31:2: error: #error This file requires compiler and library support for the upcoming ISO C++ standard, C++0x. This support is currently experimental, and must be enabled with the -std=c++0x or -std=gnu++0x compiler options.<br/> <br/><br/>#error This file requires compiler and library support for the upcoming ISO C++ standard, C++0x. <br/>加上：-lpthread -std=c++0x ，解决如下：<br/> g++ -o testmemcached testmemcached.cpp -lmemcached -lpthread -std=c++0x <br/>/usr/bin/ld: cannot find -lmemcached<br/>collect2: ld returned 1 exit status&nbsp;&nbsp;<br/>也就是说编译器并不能从ldconfig 里得知，其lib在哪儿（及时把Lib路径加入到/etc/ld.so.conf.d/libmemcache.conf），得指定：<br/><textarea name="code" class="php" rows="15" cols="100">
 g++ -o testmemcached testmemcached.cpp -lmemcached -lpthread -std=c++0x&nbsp;&nbsp;-L/usr/local/libmemcached/lib/ 
 ldconfig -p&#124;grep memcache
 libmemcached.so (libc6,x86-64) =&gt; /usr/local/libmemcached/lib/libmemcached.so&nbsp;&nbsp; AddTime:2017-08-01
</textarea><br/><br/> 在网上找了一下，发现是这样的：http://blog.163.com/guixl_001/blog/static/4176410420121021111117987/ 里说得加一个新的参数，是和宏相关，那就加了，<br/> 指定一个新的参数：-std=c++0x :<br/> /usr/bin/gcc44&nbsp;&nbsp;-o testmemcached testmemcached.cpp -lmemcached&nbsp;&nbsp; -std=c++0x&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>/usr/local/lib/libmemcached.so: undefined reference to `pthread_once&#039;<br/>collect2: ld returned 1 exit status<br/><br/><br/>/usr/bin/g++44&nbsp;&nbsp;-o testmemcached testmemcached.cpp -lmemcached&nbsp;&nbsp; -std=c++0x&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>/usr/local/lib/libmemcached.so: undefined reference to `pthread_once&#039;<br/>怎样彻底解决&quot;undefined reference to `pthread_create&#039;&quot;问题 ，说是加个： -lrt ，这一看就是那个memcached的库包含了这个文件：#include&lt;pthread.h&gt;<br/>来源参考：<br/>http://bbs.chinaunix.net/thread-1586752-1-1.html<br/><br/>于是Ok啦，最终O了，如下：<br/>[root@test testmemcachedcpp]# /usr/bin/g++44&nbsp;&nbsp;-o testmemcached testmemcached.cpp -lmemcached -lrt&nbsp;&nbsp;-std=c++0x <br/>[root@test testmemcachedcpp]#&nbsp;&nbsp;<br/>运行一下试试：<br/>[root@test testmemcachedcpp]#&nbsp;&nbsp;./testmemcached<br/>./testmemcached: error while loading shared libraries: libmemcached.so.11: cannot open shared object file: No such file or directory<br/>[root@test /]# find . -name &quot;libmemcached.so.11&quot;<br/>./usr/local/lib/libmemcached.so.11<br/>打开配置文件 vi /etc/ld.so.conf<br/>加上一行：/usr/local/lib <br/>执行/sbin/ldconfig /etc/ld.so.conf<br/>[root@test testmemcachedcpp]# /sbin/ldconfig /etc/ld.so.conf<br/>[root@test testmemcachedcpp]# ./testmemcached&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br/>[root@test testmemcachedcpp]# <br/>没报错了~，用gdb看一下 加个-g参数：<br/>/usr/bin/g++44 -g&nbsp;&nbsp;-o testmemcached testmemcached.cpp -lmemcached -lrt&nbsp;&nbsp;-std=c++0x <br/><br/>发现localhost没有开11211，于是找了一台机器把ip和端口写上，重新编译一次后运行Ok，如下：<br/>[root@test testmemcachedcpp]# ./testmemcached <br/>Save data:value sucessful!<br/>Get value:value sucessful!<br/><br/>少了一个删除成功的，简单调试一下：<br/>(gdb) n<br/>Get value:value sucessful!<br/>50&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rc=memcached_delete(memc,key.c_str(),key_length,expiration);<br/>(gdb) p key.c_str()<br/>$5 = 0x184372e8 &quot;key&quot;<br/>(gdb) p key_length<br/>$6 = 3<br/>(gdb) n<br/>51&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(rc==MEMCACHED_SUCCESS)<br/>(gdb) p rc<br/>$3 = MEMCACHED_INVALID_ARGUMENTS<br/><br/>也就是调这个函数的参数不对，返回不是MEMCACHED_SUCCESS，所以没有打印出：cout&lt;&lt;&quot;Delete key:&quot;&lt;&lt;key&lt;&lt;&quot; sucessful!&quot;&lt;&lt;endl;<br/><br/>####################新的代码里grep了一下该方法###########################<br/>./tests/mem_udp.cc:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; memcached_delete(memc, test_literal_param(&quot;foo&quot;), 0));<br/>./libmemcached-1.0/memcached.hpp:&nbsp;&nbsp;&nbsp;&nbsp;return memcached_success(memcached_delete(memc_, key.c_str(), key.length(), 0));<br/>./libmemcached-1.0/memcached.hpp:&nbsp;&nbsp;&nbsp;&nbsp;return memcached_success(memcached_delete(memc_,<br/>./tests/libmemcached-1.0/replication.cc:&nbsp;&nbsp;&nbsp;&nbsp;memcached_return_t del_rc= memcached_delete(memc_replicated,<br/>./tests/libmemcached-1.0/mem_functions.cc:&nbsp;&nbsp;&nbsp;&nbsp;rc= memcached_delete(memc, &quot;foo&quot;, 3, 1);<br/><br/>./tests/libmemcached-1.0/mem_functions.cc:&nbsp;&nbsp;&nbsp;&nbsp;test_compare(MEMCACHED_BUFFERED, (rc= memcached_delete(memc, &quot;foo&quot;, 3, 0)));<br/>./tests/libmemcached-1.0/mem_functions.cc:&nbsp;&nbsp;&nbsp;&nbsp;test_compare(MEMCACHED_SUCCESS, memcached_delete(memc, &quot;foo&quot;, 3, 0));<br/>./tests/libmemcached-1.0/mem_functions.cc:&nbsp;&nbsp;&nbsp;&nbsp;test_compare(MEMCACHED_NOTFOUND, memcached_delete(memc, &quot;foo&quot;, 3, 0));<br/><br/>####################################################################<br/>于是修改为下面这样：<br/>//rc=memcached_delete(memc,key.c_str(),key_length,expiration);<br/>rc=memcached_delete(memc,key.c_str(),key_length,0);<br/><br/>./testmemcached <br/>Save data:value2 sucessful!<br/>Get value:value2 sucessful!<br/>Delete key:key sucessful!<br/><br/>刚才失败时有值，现在运行后没值了，给成功删除了：<br/>[root@localhost ~]# telnet 192.168.108.7 11211<br/>Escape character is &#039;^]&#039;.<br/>get key<br/>VALUE key 0 5<br/>value<br/>END<br/>get key<br/>END<br/><br/><br/><br/>后面怎么结合c的socket 及epoll进行进程/线程调试就不再细说了，我也在摸索中，应该也有相关的调试办法，但这儿说明这个memcached搞个新的gcc版本库才能编译确实带了相当多编译及配置上的的麻烦~<br/><br/>最后，用C函数里的add函数实现类php的memcache的扩展的原子操作函数，如下：<br/>原子操作方法，假如有add后就不能再add，必须删除后才能add，这个可以用作锁：<br/>./libmemcached-1.0.18/libmemcached-1.0/memcached.hpp:&nbsp;&nbsp;&nbsp;&nbsp;<br/><textarea name="code" class="C" rows="15" cols="100">
return memcached_success(memcached_add(memc_, key.c_str(), key.length(),
&nbsp;&nbsp;/**
&nbsp;&nbsp; * Add an object with the specified key and value to the server. This
&nbsp;&nbsp; * function returns false if the object already exists on the server.
&nbsp;&nbsp; *
&nbsp;&nbsp; * @param[in] key key of object to add
&nbsp;&nbsp; * @param[in] value of object to add
&nbsp;&nbsp; * @return true on success; false otherwise
&nbsp;&nbsp; */
&nbsp;&nbsp;bool add(const std::string&amp; key, const std::vector&lt;char&gt;&amp; value)
&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp;return memcached_success(memcached_add(memc_, key.c_str(), key.length(),&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp;value[0], value.size(), 0, 0));
&nbsp;&nbsp;&#125;
</textarea><br/><br/>和php的add函数一样第一次运行时没有问题此时值设置成功，再运行add时一次就add不进去，add设置进去后，用set是能重新设置进去的，只是用add原子操作是不行的，用它来做锁很好使：<br/>1）代码片段：<br/><textarea name="code" class="C" rows="15" cols="100">
 //add data,then test set data error 

 rc=memcached_add(memc,key.c_str(),key.length(),value.c_str(),value.length(),expiration,flags);
 if(rc==MEMCACHED_SUCCESS)
 &#123;
&nbsp;&nbsp;&nbsp;&nbsp; cout&lt;&lt;&quot;Add data:&quot;&lt;&lt;value&lt;&lt;&quot; sucessful!&quot;&lt;&lt;endl;
 &#125;else&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&lt;&lt;&quot;Add data:&quot;&lt;&lt;value&lt;&lt;&quot; unsucessful,Perhaps add key before set !&quot;&lt;&lt;endl;
 &#125;

</textarea><br/>2）运行情况：<br/>[root@test testmemcachedcpp]# gdb testmemcached<br/>b 41<br/>r<br/>Add data:value unsucessful,Perhaps add key before set !<br/>(gdb) p rc<br/>$2 = MEMCACHED_NOTSTORED<br/>但是能够set进去：<br/>42&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rc=memcached_set(memc,key.c_str(),key.length(),value.c_str(),value.length(),expiration,flags);<br/>(gdb) n<br/>43&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(rc==MEMCACHED_SUCCESS)<br/>(gdb) p rc<br/>$3 = MEMCACHED_SUCCESS<br/>EOF<br/><br/><br/>对add后的键对应的值，再用set方法是可以设置的，如下：<br/>string key = &quot;key2&quot;;<br/>string value = &quot;jackxiang&quot;;<br/>rc=memcached_add(memc,key.c_str(),key.length(),value.c_str(),value.length(),expiration,flags);<br/>后再修改这个值：<br/>value = &quot;xiangdong&quot;; <br/>rc=memcached_set(memc,key.c_str(),key.length(),value.c_str(),value.length(),expiration,flags);<br/><br/>用gdb的断点跟踪一下并用telnet在设置后查看，如下：<br/>[root@localhost ~]# telnet 192.168.108.7 11211<br/>Escape character is &#039;^]&#039;.<br/>get key2<br/>END<br/>get key2<br/>VALUE key2 0 9<br/>jackxiang<br/>END<br/>get key2<br/>VALUE key2 0 9<br/>xiangdong<br/>END<br/><br/>听说，在下载客户端libmemcached-1.0.18/tests 下有测试列子，也可参考。比如cpp_example.cc<br/>ls ~+/cpp_example.cc<br/>/tmp/testmemcachedcpp/libmemcached-1.0.18/tests/cpp_example.cc<br/><br/>摘自：http://www.cppblog.com/kefeng/archive/2010/10/11/129422.html<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; http://blog.chinaunix.net/uid-52437-id-2108905.html<br/>后发现这个哥们写的文章很详细，http://blog.chinaunix.net/uid-20548989-id-1667248.html<br/><br/>加入add后，rc=MEMCACHED_NOTSTORED情况，代码贴下面：<br/><textarea name="code" class="C" rows="15" cols="100">
//g++ -o testmemcached testmemcached.cpp -lmemcached
///usr/bin/g++44 -g&nbsp;&nbsp;-o testmemcached testmemcached.cpp -lmemcached -lrt&nbsp;&nbsp;-std=c++0x


#include &lt;iostream&gt;
#include &lt;string&gt;
#include &lt;libmemcached/memcached.h&gt;

using namespace std;

int main(int argc,char *argv[])
&#123;
&nbsp;&nbsp;&nbsp;&nbsp;//connect server

&nbsp;&nbsp;&nbsp;&nbsp;memcached_st *memc;
&nbsp;&nbsp;&nbsp;&nbsp;memcached_return rc;
&nbsp;&nbsp;&nbsp;&nbsp;memcached_server_st *server;
&nbsp;&nbsp;&nbsp;&nbsp;time_t expiration;
&nbsp;&nbsp;&nbsp;&nbsp;uint32_t flags;

&nbsp;&nbsp;&nbsp;&nbsp;memc = memcached_create(NULL);
&nbsp;&nbsp;&nbsp;&nbsp;//server = memcached_server_list_append(NULL,&quot;192.168.109.7&quot;,11211,&amp;rc);
&nbsp;&nbsp;&nbsp;&nbsp;server = memcached_server_list_append(NULL,&quot;192.168.109.7&quot;,21211,&amp;rc);//TTServer
&nbsp;&nbsp;&nbsp;&nbsp;rc=memcached_server_push(memc,server);
&nbsp;&nbsp;&nbsp;&nbsp;memcached_server_list_free(server);

&nbsp;&nbsp;&nbsp;&nbsp;string key = &quot;key&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;string value = &quot;value&quot;;
&nbsp;&nbsp;&nbsp;&nbsp;size_t value_length = value.length();
&nbsp;&nbsp;&nbsp;&nbsp;size_t key_length = key.length();

&nbsp;&nbsp;&nbsp;&nbsp;//add data,then test set data error 
&nbsp;&nbsp;&nbsp;&nbsp;rc=memcached_add(memc,key.c_str(),key.length(),value.c_str(),value.length(),expiration,flags);
&nbsp;&nbsp;&nbsp;&nbsp;if(rc==MEMCACHED_SUCCESS)
&nbsp;&nbsp;&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&lt;&lt;&quot;Add data:&quot;&lt;&lt;value&lt;&lt;&quot; sucessful!&quot;&lt;&lt;endl;
&nbsp;&nbsp;&nbsp;&nbsp;&#125;else&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&lt;&lt;&quot;Add data:&quot;&lt;&lt;value&lt;&lt;&quot; unsucessful,Perhaps add key before set !&quot;&lt;&lt;endl;
&nbsp;&nbsp;&nbsp;&nbsp;&#125;

&nbsp;&nbsp;&nbsp;&nbsp;//Save data

&nbsp;&nbsp;&nbsp;&nbsp;rc=memcached_set(memc,key.c_str(),key.length(),value.c_str(),value.length(),expiration,flags);
&nbsp;&nbsp;&nbsp;&nbsp;if(rc==MEMCACHED_SUCCESS)
&nbsp;&nbsp;&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&lt;&lt;&quot;Save data:&quot;&lt;&lt;value&lt;&lt;&quot; sucessful!&quot;&lt;&lt;endl;
&nbsp;&nbsp;&nbsp;&nbsp;&#125;

&nbsp;&nbsp;&nbsp;&nbsp;//Get data

&nbsp;&nbsp;&nbsp;&nbsp;char* result = memcached_get(memc,key.c_str(),key_length,&amp;value_length,&amp;flags,&amp;rc);
&nbsp;&nbsp;&nbsp;&nbsp;if(rc == MEMCACHED_SUCCESS)
&nbsp;&nbsp;&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&lt;&lt;&quot;Get value:&quot;&lt;&lt;result&lt;&lt;&quot; sucessful!&quot;&lt;&lt;endl;
&nbsp;&nbsp;&nbsp;&nbsp;&#125;

&nbsp;&nbsp;&nbsp;&nbsp;//Delete data

&nbsp;&nbsp;&nbsp;&nbsp;//rc=memcached_delete(memc,key.c_str(),key_length,expiration);
&nbsp;&nbsp;&nbsp;&nbsp;rc=memcached_delete(memc,key.c_str(),key_length,0); 
&nbsp;&nbsp;&nbsp;&nbsp;if(rc==MEMCACHED_SUCCESS)
&nbsp;&nbsp;&nbsp;&nbsp;&#123;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cout&lt;&lt;&quot;Delete key:&quot;&lt;&lt;key&lt;&lt;&quot; sucessful!&quot;&lt;&lt;endl;
&nbsp;&nbsp;&nbsp;&nbsp;&#125;

&nbsp;&nbsp;&nbsp;&nbsp;//free

&nbsp;&nbsp;&nbsp;&nbsp;memcached_free(memc);
&nbsp;&nbsp;&nbsp;&nbsp;return 0;
&#125;


</textarea>
]]>
</description>
</item>
</channel>
</rss>