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")); }