php-Redis锁、管道、位图、哈希

一. 基于redis上的锁类
<?php
class Lock
{
    //获得锁每次尝试间隔,单位:毫秒
    const WAIT_SLEEP_TIME = 50;
    const M_LOCK = 'redis:lock:';
    public static function add($key, $timeout=2, $exception=true){
        while (true) {
            $flag = Cache::redis('cache')->set(self::M_LOCK . $key, 1, 'ex', $timeout, 'nx');
            if ((string)$flag === 'OK') {
                return true;
            }
            if ($exception) {
                throw new Exception('您的操作太快了,请休息一下');
            }
            usleep(self::WAIT_SLEEP_TIME * 1000);
        }
    }

    public static function get($key, $timeout=2){
        return self::add($key, $timeout);
    }

    public static function del($key){
        Cache::redis('cache')->expire(self::M_LOCK . $key, 0);
    }
}
?>
二. 调用锁
$event_key = $this->uid . ':-withdraw';
Lock::add($event_key);

三. 位图(Bitmap)
1.实现记录用户哪天进行了登录,每天只记录是否登录过,重复登录状态算已登录。
  不需要记录用户的操作行为,不需要记录用户上次登录时间和IP地址(这部分以后需要可以单独拿出来存储)
2.区分用户类型
3.查询数据需要精确到天
参考blog地址: https://www.cnblogs.com/bndong/p/7677781.html
首先优点:
数据量小:一个bit位来表示某个元素对应的值或者状态,其中的key就是对应元素本身。我们知道8个bit可以组成一个Byte,
所以bitmap本身会极大的节省储存空间。1亿人每天的登陆情况,用1亿bit,约1200WByte,约10M 的字符就能表示。
计算方便:实用Redis bit 相关命令可以极大的简化一些统计操作。常用命令 SETBIT、GETBIT、BITCOUNT、BITOP

再说弊端:
存储单一:这也算不上什么缺点,位图上存储只是0/1,所以需要存储其他信息就要别的地方单独记录,
对于需要存储信息多的记录就需要使用别的方法了。
Key结构:前缀_年Y-月m_用户类型_用户ID
标准Key:KEYS loginLog_2017-10_client_1001
检索全部:KEYS loginLog_*
检索某年某月全部:KEYS loginLog_2017-10_*
检索单个用户全部:KEYS loginLog_*_client_1001
检索单个类型全部:KEYS loginLog_*_office_*
...

每条BitMap记录单个用户一个月的登录情况,一个bit位表示一天登录情况。
设置用户1001,217-10-25登录:SETBIT loginLog_2017-10_client_1001 25 1
获取用户1001,217-10-25是否登录:GETBIT loginLog_2017-10_client_1001 25
获取用户1001,217-10月是否登录:BITCOUNT loginLog_2017-10_client_1001
获取用户1001,217-10/9/7月是否登录:BITOP OR stat loginLog_2017-10_client_1001 loginLog_2017-09_client_1001 loginLog_2017-07_client_1001
...
关于获取登录信息,就得获取BitMap然后拆开,循环进行判断。特别涉及时间范围,需要注意时间边界的问题,不要查询出多余的数据
获取数据Redis优先级高于数据库,Redis有的记录不要去数据库获取
Redis数据过期:在数据同步中进行判断,过期时间自己定义(我定义的过期时间单位为“天”,必须大于31)。
在不能保证同步与过期一致性的问题,不要给Key设置过期时间,会造成数据丢失。
上一次更新时间:         2107-10-02
下一次更新时间:         2017-10-09
Redis BitMap 过期时间: 2017-10-05
这样会造成:2017-10-09同步的时候,3/4/5/6/7/8/9 数据丢失
所以我把Redis过期数据放到同步时进行判断  

我自己想的同步策略(定时每周一凌晨同步):
一、验证是否需要进行同步:
1. 当前日期 >= 8号,对本月所有记录进行同步,不对本月之前的记录进行同步
2. 当前日期 <  8号,对本月所有记录进行同步,对本月前一个月的记录进行同步,对本月前一个月之前的所有记录不进行同步
二、验证过期,如果过期,记录日志后删除

【支持到的接口】
(1)设置用户登录
(2)查询单个用户某天是否登录过
(3)查询单个用户某月是否登录过
(4)查询单个用户某个时间段是否登录过
(5)查询单个用户某个时间段登录信息
(6)指定用户类型:获取某个时间段内有效登录的用户
(7)全部用户:获取某个时间段内有效登录的用户



四. 管道
<?php
//读取数据通过管道方式写入到redis
$lines = file_get_contents($filePath);//获取文件内容
ini_set('memory_limit', '-1');//不要限制Mem大小,否则会报错
$arr = explode(PHP_EOL, $lines);//转换成数组
try {
    $redis = new \Redis();
    $redis->connect('192.168.1.9', 6379);
    $redis->auth('*****');//密码验证
    $redis->select(0);//选择库
    $redis->pipeline();//开启管道

    foreach ($arr as $key => $value) {
        $redis->hsetNx('helloworld', (string)$key, $value);
    }
        $redis->exec();

        echo $redis->hGet('helloworld', '1000000') . PHP_EOL;
        echo $redis->hGet('helloworld', '1000001') . PHP_EOL;
    } catch (\Exception $e) {
        echo $e->getMessage();

}


//例二:批量设置,通过管道批量设置与读取

try {
    $redis = new \Redis();
    $redis->connect('192.168.1.9', 6379);
    $redis->auth('******');
    $redis->select(0);
    $redis->pipeline();//开启管道
    $redis->set('str1', 'h');
    $redis->set('str2', 'e');
    $redis->set('str3', 'l');
    $redis->set('str4', 'l');
    $redis->set('str5', 'o');
    $redis->set('str6', 'w');
    ......
    $result = $redis->exec();
    print_r($result);
} catch (\Exception $e) {
    echo $e->getMessage();
}
结果:
Array
(
    [0] => 1
    [1] => 1
    [2] => 1
    [3] => 1
    [4] => 1
    [5] => 1
    [6] => 1
    [7] => 1
    [8] => 1
    [9] => 1
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值