在使用redis的时候,出现了Error: read error on connection.
找了一下相关资料,在官方也有很多人提出这个问题
phpredis的作者的意思是,是因为default_socket_timeout的问题,将它设为0就好了.
但很多人都说设为0,在60秒后还是会挂 ,只有设为-1才OK
于是,在命令行下subscribe的时候,先init_set('default_socket_timeout',-1);
问题解决 .
膘叔的简单人生
在使用redis的时候,出现了Error: read error on connection.
找了一下相关资料,在官方也有很多人提出这个问题
phpredis的作者的意思是,是因为default_socket_timeout的问题,将它设为0就好了.
但很多人都说设为0,在60秒后还是会挂 ,只有设为-1才OK
于是,在命令行下subscribe的时候,先init_set('default_socket_timeout',-1);
问题解决 .
Redis 在运行一段时间后,发现有部分的数据确实没有缓存的必要,这时,切换数据库当然是一个办法。还有办法,flush掉所有的数据。
flush太危险了。所以。。还是删除key吧,比较安全一点。比如我删除keys "abc:*"的key
在cli里不能直接操作,但是可以
./redis-cli -n 0 keys "abc:*"|xargs ./redis-cli -n 0 del
这样就可以了。
不过因为我的正则不好,所以。。本来想长度为32的key都清掉的。。。(32位,你懂的)
还好某个库我不用了。。
本来一直在用redis,也没有觉得不爽,直到我需要对数据进行排序。。。进行条件查询。
一下子问题就来了。redis不支持这种条件查询。
于是。。我先hmGetAll,然后利用usort先排一下序,然后再利用数组的slice进行切分。这么一处理。。只有3000多条数据,0.2秒就这么浪费了。我晕啊。这怎么可以。。。这不科学啊。
于是,0.001949 一下子就刺瞎了我的钛金狗眼。
因为mongo的查询没有redis那样方便。于是在hashset的这一块,和list的这一块,我还是用redis方便,毕竟可以当成一个简单的链表处理,还是很方便的。。
对于有条件的查询,还是用mongoDB会更方便一点。测试了一下。原来只需要mongodb 512M内存就足够了,哥很大方,给了他1G,小样,你还不开心?
项目中在使用Redis,自然对内存这玩意相对比较看重一点,虽然内存不值钱,但能节约一点内存也就意味着可以存储更多的东西。
所以在博客园看到这篇文章的时候,不管现在是用了没,先备份一下资料,我英文烂 ,有点英文资料虽然能看懂,但毕竟不是母语,看起来累。
原文是在这里:
内容详细如下:http://www.cnblogs.com/stephen-liu74/archive/2012/04/11/2370521.html
一、特殊编码:
自从Redis 2.2之后,很多数据类型都可以通过特殊编码的方式来进行存储空间的优化。其中,Hash、List和由Integer组成的Sets都可以通过该方式来优化存储结构,以便占用更少的空间,在有些情况下,可以省去9/10的空间。
这些特殊编码对于Redis的使用而言是完全透明的,事实上,它只是CPU和内存之间的一个交易而言。如果内存使用率方面高一些,那么在操作数据时消耗的CPU自然要多一些,反之亦然。在Redis中提供了一组配置参数用于设置与特殊编码相关的各种阈值,如:
#如果Hash中字段的数量小于参数值,Redis将对该Key的Hash Value采用特殊编码。
hash-max-zipmap-entries 64
#如果Hash中各个字段的最大长度不超过512字节,Redis也将对该Key的Hash Value采用特殊编码方式。
hash-max-zipmap-value 512
#下面两个参数的含义基本等同于上面两个和Hash相关的参数,只是作用的对象类型为List。
list-max-ziplist-entries 512
list-max-ziplist-value 64
#如果set中整型元素的数量不超过512时,Redis将会采用该特殊编码。
set-max-intset-entries 512
倘若某个已经被编码的值再经过修改之后超过了配置信息中的最大限制,那么Redis会自动将其转换为正常编码格式,这一操作是非常快速的,但是如果反过 来操作,将一个正常编码的较大值转换为特殊编码,Redis的建议是,在正式做之前最好先简单测试一下转换效率,因为这样的转换往往是非常低效的。
二、BIT和Byte级别的操作:
从Redis 2.2开始,Redis提供了GETRANGE/SETRANGE/GETBIT/SETBIT四个用于字符串类型Key/Value的命令。通过这些命 令,我们便可以像操作数组那样来访问String类型的值数据了。比如唯一标识用户身份的ID,可能仅仅是String值的其中一段子字符串。这样就可以 通过GETRANGE/SETRANGE命令来方便的提取。再有就是可以使用BITMAP来表示用户的性别信息,如1表示male,0表示female。 用这种方式来表示100,000,000个用户的性别信息时,也仅仅占用12MB的存储空间,与此同时,在通过SETBIT/GETBIT命令进行数据遍 历也是非常高效的。
三、尽可能使用Hash:
由于小的Hash类型数据占用的空间相对较少,因此我们在实际应用时应该尽可能的考虑使用Hash类型,比如用户的注册信息,这其中包括姓名、性别、 email、年龄和口令等字段。我们当然可以将这些信息以Key的形式进行存储,而用户填写的信息则以String Value的形式存储。然而Redis则更为推荐以Hash的形式存储,以上信息则以Field/Value的形式表示。
现在我们就通过学习Redis的存储机制来进一步证明这一说法。在该篇博客的开始处已经提到了特殊编码机制,其中有两个和Hash类型相关的配置参 数:hash-max-zipmap-entries和hash-max-zipmap-value。至于它们的作用范围前面已经给出,这里就不再过多的 赘述了。现在我们先假设存储在Hash Value中的字段数量小于hash-max-zipmap-entries,而每个元素的长度又同时小于hash-max-zipmap-value。 这样每当有新的Hash类型的Key/Value存储时,Redis都会为Hash Value创建定长的空间,最大可预分配的字节数为:
total_bytes = hash-max-zipmap-entries * hash-max-zipmap-value
这样一来,Hash中所有字段的位置已经预留,并且可以像访问数组那样随机的访问Field/Value,他们之间的步长间隔为hash-max- zipmap-value。只有当Hash Value中的字段数量或某一新元素的长度分别超过以上两个参数值时,Redis才会考虑将他们以Hash Table的方式进行重新存储,否则将始终保持这种高效的存储和访问方式。不仅如此,由于每个Key都要存储一些关联的系统信息,如过期时间、LRU等, 因此和String类型的Key/Value相比,Hash类型极大的减少了Key的数量(大部分的Key都以Hash字段的形式表示并存储了),从而进 一步优化了存储空间的使用效率。
------EOF----
这里还有几篇类似的文章:
说白了,yiiredis中的AR功能的model其实就是一个hash,只是稍作封装了而已
官方有例子:
It is possible to store active record like structures in redis using ARedisRecord.
Note: this is experimental functionality and may be subject to change
$record = ARedisRecord::model()->findByPk(1); // loads a record with a unique id of 1 $record->name = "a test name"; // sets the name attribute on the record $record->somethingElse = "some other value"; $record->save(); // saves the record to redis $record->delete(); // deletes the record from redis
不过,上面的例子不能直接拿来用,因为ARedisRecord是一个abstract类,所以你得写一个类继承于他才行。
顺便,如果用setAttributes的时候,记得加第二个参数(除非你写了rules),否则一定要加第二个参数,不然save不成功哦。
昨天被它折腾了好久才发现
----
笔记而已
该死的command+左箭头。。。写了十分钟的东西全没了。
-------重新开始-----
由于目前的一个项目涉及到的数据库需要跨库跨表操作,而且该库会被频繁的插入、更新、删除,所以相对速度会较慢。但查询量又较大,在一台服务器的情况下,怎么办?分端口主从吧,意义不大,因为某些操作会导致CPU瞬间100%。
这时候我想到了key/value的数据库,想用它来做中间处理,比如大量的内容先经过它,再真正入库,毕竟我不需要过分实时,也不涉及到金钱交易。于是乎就在redis和mongo中间犹豫了。
在这期间咨询了三个人:老王(基于博客http://huoding.com/2012/02/29/146,基于Redis消息系统实现);11爷(redis有pub/sub功能);烂桔(mongo不太适用于单机,redis有内存模式)
基于上述原因,于是选择了redis,那么就开始我的Redis之旅吧
1、安装 Redis ,参考:http://library.linode.com/databases/redis/ubuntu-10.10-maverick(如果我没记错,这应该是11爷推荐的地址,他本来推荐的是Centos下的,但我用的是ubuntu,所以就参考这个了)
先来三个常规操作
apt-get update
apt-get upgrade
apt-get install build-essential
完事之后,接着:
cd /opt/
mkdir /opt/redis
wget http://redis.googlecode.com/files/redis-2.4.8.tar.gz
tar -zxvf /opt/redis-2.4.8.tar.gz
cd /opt/redis-2.4.8/
make
make完后做如下操作,将一些配置文件拷贝到/opt/redis目录下:
cp /opt/redis-2.4.8/redis.conf /opt/redis/redis.conf.default
cp /opt/redis-2.4.8/src/redis-benchmark /opt/redis/
cp /opt/redis-2.4.8/src/redis-cli /opt/redis/
cp /opt/redis-2.4.8/src/redis-server /opt/redis/
cp /opt/redis-2.4.8/src/redis-check-aof /opt/redis/
cp /opt/redis-2.4.8/src/redis-check-dump /opt/redis/
cp /opt/redis/redis.conf.default /opt/redis/redis.conf
接着,更新/opt/redis/redis.conf:
daemonize yes
pidfile /var/run/redis.pid
logfile /var/log/redis.log
port 6379
bind 127.0.0.1
timeout 300
loglevel notice
## Default configuration options
databases 16
save 900 1
save 300 10
save 60 10000
rdbcompression yes
dbfilename dump.rdb
dir /opt/redis/
appendonly no
以上是linode里的配置,你可以参考一下做处理。大部分都一样,但timeout/loglevel/dir这三个参数不太一样。可以看着注释改一下。 linode 中有一个:glueoutputbuf yes ,这个在2.4.8下面会出错,所以我就没有启用它。
接着是加入启用脚本,既然linode有配置参考,那么它就有启动脚本,默认redis是没有给你这些启动脚本的,所以偷懒一下吧,下载linode的脚本:
cd /opt/
wget -O init-deb.sh http://library.linode.com/assets/630-redis-init-deb.sh
adduser --system --no-create-home --disabled-login --disabled-password --group redis
mv /opt/init-deb.sh /etc/init.d/redis
chmod +x /etc/init.d/redis
chown -R redis:redis /opt/redis
touch /var/log/redis.log
chown redis:redis /var/log/redis.log
update-rc.d -f redis defaults
在这一步之后,你就可以直接用/etc/init.d/redis 来 start和stop redis服务了。
2、安装phpredis(https://github.com/nicolasff/phpredis)
在安装之前,先看readme:https://github.com/nicolasff/phpredis/blob/master/README.markdown
看完readme之后你会发现,原来一切是这样的简单啊
OK,先wget 回源代码,然后tar解开目录。。
接着3步搞定:
phpize
./configure
make && make install
速度超快,make install后,会告诉你redis.so生成在哪里,你将这extension=redis.so,加入到你的php.ini中即可。
3、下载YiiRedis项目。(由于我是用Yii的,所以直接用这个插件了,否则,还是参考一下phpredis的一些用法)
同样,在这里有readme:https://github.com/phpnode/YiiRedis/blob/master/README.md
项目地址:https://github.com/phpnode/YiiRedis(请自行下载)
使用方法也很简单,和db一样,在components下加一个组件:
"components" => array(
"redis" => array(
"class" => "packages.redis.ARedisConnection",
"hostname" => "localhost",
"port" => 6379
),
//...
),
加完它之后就可以写上一段测试代码了:
Yii::import("ext.yiiredis.*");
$list = new ARedisList("aNameForYourListGoesHere");
$list->add("cats");
$list->add("dogs");
$list->add("goods");
foreach($list as $i => $val) {
print_r($val) ;
echo "<br />";
}
$list->clear(); // delete the list
直接输出在浏览器中。是不是很HIGH?
------
OK,就介绍到这里,请试用吧。
=------
备注:
$redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_NONE); // don't serialize data
$redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_PHP); // use built-in serialize/unserialize
$redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_IGBINARY); // use igBinary serialize/unserialize
$redis->setOption(Redis::OPT_PREFIX, 'myAppName:'); // use custom prefix on all keys
由于redis默认不做序列化,因此如果要存储PHP的数据,如:数组、对象,那就必须用第二个setOption进行设置,以便 让数据自动序列化