过期时间
工作原理
当对Redis中的一个键设置过期时间时,键的过期时间会被存储为一个绝对的Unix时间戳。这样做的目的在于,即使Redis服务器宕机了一段时间,这个时间戳也会被持久化到RDB文件中,这个时间戳依然会继续起作用。
在一个键过期之后,当客户端试图访问已经过期键时,redis会立即将其从内存中删除。redis这种删除键的方式叫做被动过期。对于哪些已经过期而且永远不会再访问的键,redis会定期运行一个基于概率的算法来进行主动删除。
应用场景
- 限时的优惠活动信息
- 网站数据缓存(对于一些需要定时更新的数据,例如:积分排行榜)
- 手机验证码
- 限制网站访客访问频率(例如:1分钟最多访问10次)
等等
实践
设计
一个IP请求,限制10秒内请求总数为200次,超过200次就等待,等下一秒。需要存储的信息是
- 用户IP 【作为key】
- 访问次数 【每次访问就Incr】
这里我使用string作为存储数据的结构,同时设置键的过期时间为1s。
127.0.0.1:6379> get 192.168.0.1
(nil)
127.0.0.1:6379> incr 192.168.0.1
(integer) 1
127.0.0.1:6379> get 192.168.0.1
"1"
127.0.0.1:6379> incr 192.168.0.1
(integer) 2
127.0.0.1:6379> get 192.168.0.1
"2"
127.0.0.1:6379> exists 192.168.0.1 -- 查看键是否存在
(integer) 1
127.0.0.1:6379> expire 192.168.0.1 5 --设置键的过期时间
(integer) 1
127.0.0.1:6379> ttl 192.168.0.1 --在键过期前查看剩余时间
(integer) 2
如果键存在但是没有设置过期时间,则ttl命令会返回-1.如果键不存在,那么ttl会返回-2
127.0.0.1:6379> persist 192.168.0.1 -- 让键变成持久的键
(integer) 1
代码
package main
import (
"fmt"
"github.com/go-redis/redis"
"strconv"
)
func createClient() *redis.Client {
client := redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "",
DB: 0,
})
// 通过 cient.Ping() 来检查是否成功连接到了 redis 服务器
_, err := client.Ping().Result()
if err != nil{
panic(err)
}
return client
}
func count_string(client *redis.Client, userip string){
val, err := client.Exists(userip).Result()
if err != nil{
panic(err)
}
if val == 0{ // no exists
_, err := client.Incr(userip).Result()
if err != nil{
panic(err)
}
_, err = client.Expire(userip, 5 * 1000 * 1000 * 1000 * 10).Result() //设置键的过期时间 10s
if err != nil{
panic(err)
}
}else{ //exist
count, err := client.Get(userip).Result()
if err != nil{
panic(err)
}
temp , _:= strconv.Atoi(count)
fmt.Println(temp)
if temp < 200{
_, err = client.Incr(userip).Result()
if err != nil{
panic(err)
}
}else{
fmt.Println("不允许访问")
}
}
}
func main(){
client := createClient()
fmt.Println(client)
count_string(client, "192.168.0.1")
}