本文环境 CentOS8.0,PHP8.1,Nginx1.8,Workerman 4.0 不懂的可以评论或联系我邮箱:owen@owenzhang.com 著作权归OwenZhang所有。商业转载请联系OwenZhang获得授权,非商业转载请注明出处。
image.png
workerman介绍
Workerman是一款纯PHP开发的开源高性能的PHP 应用容器。
Workerman不是重复造轮子,它不是一个MVC框架,而是一个更底层更通用的服务框架,你可以用它开发tcp代理、做游戏服务器、邮件服务器、ftp服务器、甚至开发一个php版本的redis、php版本的数据库、php版本的nginx、php版本的php-fpm等等。Workerman可以说是PHP领域的一次创新,让开发者彻底摆脱了PHP只能做WEB的束缚。
实际上Workerman类似一个PHP版本的nginx,核心也是多进程 Epoll 非阻塞IO。Workerman每个进程能维持上万并发连接。由于本身常驻内存,不依赖Apache、nginx、php-fpm这些容器,拥有超高的性能。同时支持TCP、UDP、UNIXSOCKET,支持长连接,支持Websocket、HTTP、WSS、HTTPS等通讯协议以及各种自定义协议。拥有定时器、异步socket客户端、异步Redis、异步Http、异步消息队列等众多高性能组件。
Redis bitmap位图介绍
在平时开发过程中,经常会有一些 bool 类型数据需要存取。比如记录用户一年内签到的次数,签了是 1,没签是 0。如果使用 key-value 来存储,那么每个用户都要记录 365 次,当用户成百上亿时,需要的存储空间将非常巨大。为了解决这个问题,Redis 提供了位图结构。
位图(bitmap)同样属于 string 数据类型。Redis 中一个字符串类型的值最多能存储 512 MB 的内容,每个字符串由多个字节组成,每个字节又由 8 个 Bit 位组成。位图结构正是使用“位”来实现存储的,它通过将比特位设置为 0 或 1来达到数据存取的目的,这大大增加了 value 存储数量,它存储上限为2^32 。
php 实例
代码语言:javascript复制//setBit($key, $offset, $value)
//$offset参数需要大于等于0,并且小于 2^32 = 4294967296 (bitmaps 最大 512MB)
//$value 偏移量上的位 0和1
//不建议用下面方法,这样造成0到20220101值为空 数据量太大
// 可以key上面显示年份或者月份,然后day1-365这样 key大小就比较合理
$data = [
[
'day' => 20220101,//日期 2022年1月1号
'sign_in' => 1,//签到 1有 0无
],
[
'day' => 20220102,
'sign_in' => 0,
],
[
'day' => 20220322,
'sign_in' => 1,
],
];
//1-1231不存在的值都设置为0
$data = [
[
'day' => 101,//日期 1月1号
'sign_in' => 1,//签到 1有 0无
],
[
'day' => 211,
'sign_in' => 0,
],
[
'day' => 1102,
'sign_in' => 1,
],
[
'day' => 1231,
'sign_in' => 1,
],
];
// foreach ($data as $datum) {
// //写入用户10026的签到位图
// Redis::setBit('bitSingIn:userId:10026', $datum['day'], $datum['sign_in']);
// }
$day = $request->post('day');
//获取用户10026的某天签到情况
$sign_in = Redis::getBit('bitSingIn:userId:10026', $day);
//统计用户的签到次数
$bitCount = Redis::bitCount('bitSingIn:userId:10026');
//获取首次签到的日期
$bitCount = Redis::bitPos('bitSingIn:userId:10026', 1);
return $this->apiSuccess(compact('day', 'sign_in', 'bitCount'));
复制
redis bit位图命令
代码语言:javascript复制# 用户2月17号签到
SETBIT u:sign:1000:201902 16 1 # 偏移量是从0开始,所以要把17减1
# 检查2月17号是否签到
GETBIT u:sign:1000:201902 16 # 偏移量是从0开始,所以要把17减1
# 统计2月份的签到次数
BITCOUNT u:sign:1000:201902
# 获取2月份前28天的签到数据
BITFIELD u:sign:1000:201902 get u28 0
# 获取2月份首次签到的日期
BITPOS u:sign:1000:201902 1 # 返回的首次签到的偏移量,加上1即为当月的某一天
复制
场景需求
适用场景如签到送积分、签到领取奖励等,大致需求如下:
签到1天送1积分,连续签到2天送2积分,3天送3积分,3天以上均送3积分等。
如果连续签到中断,则重置计数,每月初重置计数。
当月签到满3天领取奖励1,满5天领取奖励2,满7天领取奖励3……等等。
显示用户某个月的签到次数和首次签到时间。
在日历控件上展示用户每月签到情况,可以切换年月显示……等等。
运行结果和redis key存储情况
redis服务
代码语言:javascript复制<?php
/**
* This file is part of webman.
*
* Licensed under The MIT License
* For full copyright and license information, please see the MIT-LICENSE.txt
* Redistributions of files must retain the above copyright notice.
*
* @author walkor<walkor@workerman.net>
* @copyright walkor<walkor@workerman.net>
* @link http://www.workerman.net/
* @license http://www.opensource.org/licenses/mit-license.php MIT License
*/
namespace support;
use IlluminateRedisRedisManager;
use WorkermanTimer;