redis实用小实例
1:发送手机短信,1分钟限制3次
分析:给用户发送短信,首先验证手机号码格式,然后判断在1分钟以内是否发送过3次,有很多种做法,比如基于mysql实现,每发送一次,记录一条数据:手机号,时间戳。很麻烦,如果用redis处理非常简单:
思路:基于redis的TTL,设置生命周期,key 设置一分钟,每次访问加1,然后判断数量,1分钟后redis会自动回收注销key。
(1)伪代码:golang,稍微封装下:
package main import( "fmt" "os" "github.com/gomodule/redigo/redis" ) func main(){ conn := connect() defer conn.Close()//记得销毁本次链连接 phoneNum := "13512345678" //手机号 key := "shortMsg:limit:" + phoneNum // NX:表示key不存在则设置,设置值为0 过期时间:60s _ ,setErr := conn.Do("SET",key,0,"EX",60,"NX") checkError(setErr) //错误提示 count , _ := conn.Do("INCR",key) //加 1 返回KEY的值 //conn.DO返回的是interface,需要转换 if( count.(int64) <= 3){ fmt.Println("OK") }else{ fmt.Println("超过次数") } } //连接 func connect()redis.Conn{ const ip string = "192.168.17.160" //redis地址 const port string = "6379" //端口 conn := ip+":"+port passrord := "123" //密码 // 连接redis c,err := redis.Dial("tcp",conn,redis.DialPassword(passrord)) checkError(err) return c } //错误提示 func checkError(err error){ if err != nil { fmt.Println("Error is ",err) os.Exit(-1) } }
(2)伪代码:php,假装封装下连接
<?php
date_default_timezone_set("PRC");
$phoneNum = "13512345678"; //手机号
$key = "shortMsg:limit:".$phoneNum;
$conn = connect(); //连接
$isExists = $conn->set($key,1,array("EX"=>60,"NX"));
if($isExists != "" || $conn->incr($key) <=3){
echo "ok";
}else{
echo "超过次数";
}
//连接
function connect(){
$redis = new Redis();
$redis->connect('192.168.17.160',6379); //连接服务器 返回【true | false】
$redis->auth('123'); //登录验证密码,返回【true | false】
return $redis;
}这种可以扩展出其他一些使用场景,比如限制一些爬虫,或者是恶意频繁访问,如:1秒钟限制5次……,API每天限制多少次、同一个IP每天投票多少次等等!
2:发送短信,一天之内发送10次,且1分钟限制一次
分析:这里要用两个key,一个是记录1天的次数,一个是记录1分钟的次数
思路:基本思路同上,不过用到了另外一个命令,设置当天过期用到了redis的Expireat命令:用于以 UNIX 时间戳(unix timestamp)格式设置 key 的过期时间。key 过期后将不再可用。也就是我们设置某个时间点过期,只要设置这个时间点的时间戳就行了。
分两步:首先判断一天是否超过10次,如果没有超过再判断一分钟限制,一分钟限制很简单,我们保存1个key设置一分钟过期,如果存在key,说明1分钟内已经发送过,不能再发送。
(1)伪代码:golang
package main
import(
"fmt"
"os"
"time"
"github.com/gomodule/redigo/redis"
)
func main(){
conn := connect()
defer conn.Close()//记得销毁本次链连接
phoneNum := "13512345678" //手机号
if !dayData(phoneNum,conn) {
fmt.Println("超过一天次数")
return
}
isExists := minData(phoneNum,conn)
if isExists {
fmt.Println("OK")
} else{
fmt.Println("超过每分钟次数")
}
}
//一天10次
func dayData(phone string , c redis.Conn) bool {
key := "shortMsg:day:" + phone
exists, _ := redis.Bool(c.Do("EXISTS", key))
if !exists {
_ , setErr := c.Do("SET",key,0)
checkError(setErr) //错误提示
_ , err := c.Do("Expireat",key,endTime()) //UNIX 时间戳(unix timestamp)格式设置 key 的过期时间
checkError(err) //错误提示
}
count , _ := c.Do("INCR",key) //加 1 返回KEY的值
if( count.(int64) <= 10){
return true
}else{
return false
}
}
//一分钟1次
func minData(phone string , c redis.Conn) bool {
key := "shortMsg:min:" + phone
exists, _ := redis.Bool(c.Do("EXISTS", key)) //如果不存在返回 设置key 返回ture
if !exists {
_ ,setErr := c.Do("SET",key,1,"EX",60,"NX")
checkError(setErr) //错误提示
return true
}else{
return false
}
}
//获取当天 23:59:59秒的时间戳
func endTime() int64 {
t := time.Now()
return time.Date(t.Year(), t.Month(), t.Day(), 23, 59, 59, 0, t.Location()).Unix()
}
//连接
func connect()redis.Conn{
const ip string = "192.168.17.160" //redis地址
const port string = "6379" //端口
conn := ip+":"+port
passrord := "123" //密码
// 连接redis
c,err := redis.Dial("tcp",conn,redis.DialPassword(passrord))
checkError(err)
return c
}
//错误提示
func checkError(err error){
if err != nil {
fmt.Println("Error is ",err)
os.Exit(-1)
}
}(2)伪代码:php
<?php
date_default_timezone_set("PRC");
$phoneNum = "13512345678"; //手机号
$conn = connect(); //连接
if(dayData($phoneNum,$conn) === false ){
echo "超过一天次数";
}else{
if(minData($phoneNum,$conn) === false ){
echo "超过每分钟次数";
}else {
echo "ok";
}
}
//一天10次
function dayData($phone,$redis){
$key = "shortMsg:day:".$phone;
if(!$redis->exists($key)){ //如果不存在
$redis->set($key,0); // 设置0次
$redis->expireat($key,endTime()); //设置当天23:59:59过期
}
$count = $redis->incr($key); //加1
if($count > 10){
return false;
}else {
return true;
}
}
//一分钟1次
function minData($phone,$redis){
$key = "shortMsg:min:".$phone;
if(!$redis->exists($key)){ //如果不存在
$redis->set($key,1,array("EX"=>60)); //设置值 60秒过期
return true;
}else{
return false;
}
}
//连接
function connect(){
$redis = new Redis();
$redis->connect('192.168.17.160',6379); //连接服务器 返回【true | false】
$redis->auth('123'); //登录验证密码,返回【true | false】
return $redis;
}
//获取当天 23:59:59秒的时间戳
function endTime(){
return mktime(23, 59, 59, date("m"), date("d"), date("Y"));
}