redis+mc review

10 篇文章 0 订阅

缓存

 


Redis--分库快速写 与 Memcached--搜索纯读取

--use
网络(单线程|多线程)

--curd
内存(预分配--内存占用 | 实时申请--慢一点)
有效性(LRU--惰性失效 | expire--惰性+随机+暴力)
数据一致性(memcache cas  | redis 事务-Multi/Watch/Exec)
集群-分布式(consistent_hash | Twemproxy)

--save
数据备份(master-slave)
持久化(snapshot快照1/2和AOF-I/O) 
性能(被动访问和内存不够用 |pipeline script )

小结:内存+主从+读写
1. 要进行Master-slave配置,出现服务故障时可以支持切换,只在slave上配置数据持久化。
2. 当Redis物理内存使用超过内存总容量的3/5时就会开始比较危险了,就开始做swap,内存碎片大,物理内存+虚拟内存不足,这个时候dump一直死着,时间久了机器挂掉.当达到最大内存时,会清空带有过期时间的key,即使key未到过期时间.
3. redis与DB同步写的问题,先写DB,后写redis,因为写内存基本上没有问题

 

 

 

 


cache(kv ex):


 * key - user:userid:9:email(表名:主键名:主键值:列名)   lisi@163.com  
 * val - 返回:个数|是否修改|存在性|类型|秒数 -1(已过期) -2(不存在);空字符串|旧值|头尾元素或中间元素|返回随机值
 * ex - mem指定 | redis可指定可不指定 ttl






redis:(单线程 申请内存 |  主从  持久化  多数据类型 事务 | 过期策略(惰性 随机 暴力)) 
持久化剖析:全量bgsave 写 磁盘,增量aof 刷 磁盘;aof支持修复;持久化的fork导致负载大==>主从(从备份和从切换)


mem(分布式consistent 缓存故障(雪崩-ex 无底洞-分布式 数据踢除-lru 命中-slab))
cache 命中:
memcached中新的value过来存放的地址是该value的大小决定的,value总是会被选择存放到chunk与其最接近的一个slab中,如果我的value是80b,那么我这所有的value总是会被存放到1号slab中,那么memcached会把这个slab中最近最少被使用的chunk中的数据清掉,然后放上最新的数据 








问题:持久化+分布式
持久化, 复制和备份带来的系统和网络问题,无分布式方案导致软件设计的复杂度增加.
Redis 不适合作为海量数据存储方案. Redis 适合在数据规模较小, 性能要求较高的条件下应用


1.方法:
redis有全量(save/bgsave)和增量(aof)的持久化命令。 全量的原理就是遍历里所有的DB并写入dump.rdb文件。增量备份就是aof,每次执行命令后如出现数据变化把数据写到server.aofbuffer里,然后依照设置刷到磁盘上


2.区别:
快照db文件,优点是二进制,大小比aof日志文件小。但会丢失最后一次成功备份时间到down机时间的数据。
aof相比而言文件大小就大了点,但相对快照来讲,不大容易丢失文件。
目前redis检查数据文件是否有错对于快照及aof都能够支持,但修复则只对aof文件有效。


3.问题:
redis如果每60s更改记录数过万条就会dump(磁盘没闲着),而且是通过fork子进程dump(内存占用翻倍,cpu打满)。解决方法,可考虑把dump时间改为30m 有一次写修改就dump一次,而且主不dump,启动时只是download数据,不然的话加载数据前无法提供服务,dump交给从 
方式:




主从


备份:redis下同时存在aof和db备份文件,这时根据从redis是否支持aof来决定是否同步aof文件
slave->sync->master->bgsave->db
db->slave->ack
slave->(bgsave->ack期间新请求)->send->slave


切换:
slave  slave of no one  ->check or fix aof(下面2条) ->slave of master


./redis-check-aof /home/jbossas/Data/redis/redis-data/appendonly.aof
./redis-check-aof --fix /home/jbossas/Data/redis/redis-data/appendonly.aof




redis优化:当它们的元素数量及value大小小于某个限值时,会用(数组)来减少内存存储
 






















redis zadd_push or multi
<?php


error_reporting(E_ALL);


ini_set('display_errors',1);






//1.zadd 有序集合实现队列


class RedisClient


{


    const POSITION_FIRST = 0;


    const POSITION_LAST = -1;


    


    public $redis;


    


    public function __construct(){


        


        $this->redis = new redis();


        $this->redis->connect('127.0.0.1', 6379); 


    }


    


    public function testData()


    {


        $this->redis->zadd('msg', '0', 'lunch');


        $this->redis->zadd('msg', '1', 'sleep');


        $this->redis->zadd('msg', '2', 'run');


        $this->redis->zadd('msg', '3', 'swim');


        $this->redis->zadd('msg', '4', 'cinema');


    }


    


    public function zPop($zset)


    {


        return $this->zsetPop($zset, self::POSITION_FIRST);


    }






    public function zRevPop($zset)


    {


        return $this->zsetPop($zset, self::POSITION_LAST);


    }






    private function zsetPop($zset, $position)


    {


        $this->redis->watch($zset);






        $element = $this->redis->zRange($zset, $position, $position);


        if (!isset($element[0])) {


            return false;


        }






        if ($this->redis->multi()->zRem($zset, $element[0])->exec()) {


            return $element[0];


        }






        return $this->zsetPop($zset, $position);


    }


    


    


    


    //exmaple not use


    public function mzadd($key, $scores, $vals){


        $score_v = '';


        foreach ($scores as $k => $v) {


            $score_v .= ', '.$v.' , '.$vals[$k];


        }


        $score_v = substr($score_v, 1);


        $lua = "return redis.call('zadd', '{$key}', {$score_v})";


        if(!empty($score_v)){


            $ret =  $this->redis->eval($lua);


        }


        return $ret;


    }






    


    


}






//list






$redis = new RedisClient;


echo '<pre>';






$redis->testData();


while ($msg = $redis->zRevPop('msg')) {


    print_R($msg);echo PHP_EOL;


}






$redis->testData();


while ($msg = $redis->zPop('msg')) {


    print_R($msg);echo PHP_EOL;


}






//2.multi enhance profile


for ($i = 1; $i <= 10; $i++) {


    $redis->redis->multi(Redis::PIPELINE);


    for ($j = 1; $j <= 10; $j++) {


        $msgid = ($i - 1) * 10000 + $j;


        $userid = rand(0,100);


        $redis->redis->sAdd('usr:msg', $msgid);


    }


    $redis->redis->exec();


}






$re = $redis->redis->smembers('usr:msg');


print_r($re);






//2.1 multi zadd


$vals = array(100=>'lunch2',101=>'sleep3',201=>'run4',301=>'swim5',401=>'cinema6');


 $redis->redis->multi(Redis::PIPELINE);


foreach($vals as $score=>$val){


    $lua = "return redis.call('zadd', 'mynewmsg', {$score},'{$val}')";


    $ret =  $redis->redis->eval($lua);






}


$redis->redis->exec();


$msg = $redis->redis->zrange('mynewmsg',0,100);


echo '<pre>';


var_dump($msg);






 


?>




一、Redis


数据类型:
string 静态数据:存取
hash   属性数据:关系
set:去重数据:集合
list:列表数据:头尾
sort set    排序数据:先后




//存取 时效 加减1 键名操作 事务 持久化 
//get set setex setex delete mset mget getMultiple=>multi flushdb flushall     (ex nx m+)
//ttl persist setTimeout=>expire expireAt|                                              (+4)
//incr incrby decr decrby                                                                        (number)
//keys randomKey type dbsize rename renameNx move exists            (key use)




//curd +eists contain len 
//string:getSet get/setRange append strlen                           (get set)       
//hash h m/set m/get del keys vals getall len exists incrby    (field 0=>1 2=>3 4=>5 )                    
//list:l r push/x pop set get | l range/trim/rem/insert lsize |rpoplpush   (in out  range(save del get insert)  lists)
+
//set s add rem move pop sort inter/store union/store diff-前面的差集/store randMember members contains=>sismember size=>scared     (inter union diff | add rem  pop | member(contain size rand))
//zset z add rem |rev/range rem/rangebyscore score rank |count incrby size |union/inter(add and multiple)
(key score meber | score member | score member … ... )


zrank zrevrank==>排序的位数不同


zrank rank go
:4
zrevrank rank go
:2


zrange zrevrange =>展现多顺序不同


zrange rank 0 10
*7
$5
lunch
$5
sleep
$6
runner
$4
swim
$2
go
$4
jump
$6
paipai


zrevrange rank 0 10
*7
$6
paipai
$4
jump
$2
go
$4
swim
$6
runner
$5
sleep
$5
lunch




zrangebyscore zrevrangebyscore=>排序的大小不同


zrangebyscore rank 0 10
*7
$5
lunch
$5
sleep
$6
runner
$4
swim
$2
go
$4
jump
$6
paipai


zrevrangebyscore rank 10 0
*7
$6
paipai
$4
jump
$2
go
$4
swim
$6
runner
$5
sleep
$5
lunch






//multi(顺序处理) exec(执行) discard(丢弃) watch(乐观锁 不许改动) unwatch  pipeline(批处理)
//save bgsave lastsave bgrewriteaof slaveof info auth
//ttl -2 是过期了,-1是持久有效


//sort
sort key (desc) limit 0 5  
sort by  get  store






$r->setex('keys',3,'vals');
$r->getMultiple(array('key1','key2','key3','key4','key5'));
$r->setTimeout('x',30);
$r->linsert('list',Redis::BEFORE,'key1','def');
$r->sort('int',array('sort'=>'desc'));
$r->zscore('set','123');


//事务失败后不能回滚,造成部分执行完毕,事务只能保证操作的原子性,但不能保证数据原子性,因此采用乐观锁,watch/unwatch
$r->watch('num');
$r->multi();
$r->incrby('num',100);
$r->exec(); //or discard();
$num = $r->get('num');
// echo $num;






$r = new Redis;
$r->connect('127.0.0.1',6379);
$r->auth('password');
$r->ping();
$r->set('key','val');
$r->get('key');
$r->setnx('key','val');
$r->ttl('keys');
$r->delete('key');
$r->persist('keys');
$r->mset(array('key1'=>'val1','key2'=>'val2','key3'=>'val3','key4'=>'val4','key5'=>'val5'));
$r->exists('key2');
$r->incr('num');
$r->incrby('num',10);
$r->flushDB();
$r->flushAll();
$r->randomKey();
$r->select(0);
$r->move('x',1);
$r->rename('name','myname');
$r->renameNx('myname','myname2');
$r->expireAt('x',time());
$r->keys('*');
$r->dbSize();


$r->bgrewriteaof();
$r->slaveof('127.0.0.1',6380);
$r->save();
$r->bgsave();
$r->lastSave();
$r->info();
$r->type('myname'));














//string
$r->set('string','str');
$r->strlen('string');
$r->append('string','insert');
$r->get('string');
$r->getSet('string','abc');


//hash
$r->hmset('student',array('wangming'=>80,'xiaohong'=>85,'ligang'=>90));
$r->hdel('student','ligang');
$r->hmget('student',array('xiaohong','wangming'));
$r->hget('student','xiaohong');
$r->hexists('student','wangming');
$r->hlen('student');
$r->hincrBy('student','xiaohong',10);
$r->hget('student','xiaohong');
$r->hkeys('student');
$r->hvals('student');
$r->hgetall('student');


//list
$r->lpush('list','key1');


$r->linsert('list',Redis::BEFORE,'key1','def');


$r->lrange('list',0,-1);
$r->ltrim('list',2,10);
$r->lsize('list');
$r->lget('list',0);
$r->rpoplpush('list','list2');


//set
$r->sadd('set',123);
$r->srem('set',789);
$r->smove('set2','set','789');
$r->smembers('set');
$r->spop('set2');
$r->ssize('set');
$r->scontains('set','456');
$r->srandMember('set');


$r->sort('int',array('sort'=>'desc'));


$r->sinter('int','int2');
$r->sunion('int','int2');
$r->sdiff('int2','int');
$r->sdiffstore('diffstore','int2','int');
$r->smembers('diffstore');




//zset
$r->zadd('set',0,'123');
$r->zcount('set',0,42);
$r->zsize('set');
$r->zincrby('set',2000,'123');
$r->zremrangeByScore('set',0,1);


$r->zscore('set','123');


$r->zrank('set','789');
$r->zRevrange('set',0,-1);








二、Memcached +pipe+bykey+cas | Memcache connect(8个) 


// append prepend getDelayed fetch fetchall setMulti getMulti addServers getServerByKey setByKey cas--写锁的set setOptions
//set = add replace
$m = new Memcached();
$m->addServer('127.0.0.1',11211);
$m->set('foo','bar');
$m->setOption(Memcached::OPT_COMPRESSION,false);
$m->append('foo','def');
$m->prepend('foo','000');
$m->get('foo');
$m->getServerList();
$m->setByKey('127.0.0.1','orderKey',1);
$server = $m->getServerByKey($key);
$m->fetchAll();


$m->getDelayed(array('int','string'),true);
 while ($re = $m->fetch()) {


 }


$m->setMulti(array('key1'=>'val1','key2'=>'val2','key3'=>'val3'),true);
$m->getMulti(array('key1','key2','key3'),$cas);


$m->addServers(array(
array('127.0.0.1',11211),
array('127.0.0.1',11212)


));










do {
$ips = $m->get('ip_block',null,$cas);//加上$cas后面才能用
if ($m->getResultCode()==Memcached::RES_NOTFOUND) {
$ips = $_SERVER['REMOTE_ADDR'];
$m->add('ip_block',$ips);
}else{
$m->cas($cas,'ip_block',$ips);//加了写锁的set
}
} while ($m->getResultCode()!=Memcached::RES_SUCCESS);


var_dump($ips);






三、Memcache
set(key,val,compress,timeout) get delete flush flush_all close add replace
new connect
increment decrement
addServer(host,port,persist,weight,timeout,retry_intval,status,failecallback)


./memcached -m 256 -c 1000 -P -l 127.0.0.1 -p 11211 -u root -d /tmp/memcached.pid


getVersion getStats hit/cmd.. getExtendedStats getStatus

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值