网站首页php
Redis分步锁解决Mysql并发处理问题
发布时间:2023-01-13 15:14:07编辑:slayer.hover阅读(243)
1. 测试10个进程并发读取同一个数据库表, 需要保证每个进程读到的数据行都是唯一的.
当使用mysql锁来实现:
DB::transaction(function (){ $row = DB::Table('record') ->where('create_at', '<=', time()) //读取当前时间之前的数据进行处理 ->lockForUpdate() ->first(); //更新$row操作 ... });
当数据量开始增加到1W条的时候, 就可以明显感觉到执行异常的慢了.
抛却数据库锁, 可以使用redis同步锁来控制一下流程.
2. Redis分步锁, 代码如下所示:
function sync($key, callable $func, $expire = 10000) { if (!$cache_enable) { $result = call_user_func($func); }else { $random = uniqid($key) . rand(0, 1000000); while (!Cache::set($key, $random, ['nx', 'px' => $expire])) { usleep(100000); } $result = call_user_func($func); if (Cache::get($key) == $random) { Cache::delete($key); } } return $result; }
备注: Redis不可用则返回原流程.
Cache::set($key, $random, ['nx', 'px'=>$expire]);
$key不存在时写入, 并设置$expire毫秒后自动过期. 写入成功则返回TRUE;
未加锁成功, 则100毫秒后重试. 加锁成功后执行业务流程, 完成后释放当前锁.
3. 替换上面的加锁方法:
sync('lock001', function (){ $key = Cache::get('Key') ?: 0; //读取到已缓存的ID $row = DB::Table('record') ->where('id', '>', $key) //以ID控制每次读到的数据都不一样 ->where('create_at', '<=', time()) ->first(); Cache::set('Key', $row->id); //将当前读取到的ID缓存起来 //更新$row操作 ... });
如此, 每个进程读到的数据都不一行, 即可解决同步读取写入的问题.
评论