Go新项目-调研关于go项目中redis的使用场景,lua实战(7)

文章目录

参考地址

redis的使用场景的解释

下面一一来分析下Redis的应用场景都有哪些。

1、缓存

缓存现在几乎是所有中大型网站都在用的必杀技,合理的利用缓存不仅能够提升网站访问速度,还能大大降低数据库的压力。Redis提供了键过期功能,也提供了灵活的键淘汰策略,所以,现在Redis用在缓存的场合非常多。

2、排行榜

很多网站都有排行榜应用的,如京东的月度销量榜单、商品按时间的上新排行榜等。Redis提供的有序集合数据类构能实现各种复杂的排行榜应用。

3、计数器

什么是计数器,如电商网站商品的浏览量、视频网站视频的播放数等。为了保证数据实时效,每次浏览都得给+1,

并发量高时如果每次都请求数据库操作无疑是种挑战和压力。Redis提供的incr命令来实现计数器功能,内存操作,性能非常好,非常适用于这些计数场景。

4、分布式会话

集群模式下,在应用不多的情况下一般使用容器自带的session复制功能就能满足,当应用增多相对复杂的系统中,一般都会搭建以Redis等内存数据库为中心

的session服务,session不再由容器管理,而是由session服务及内存数据库管理。

5、分布式锁

在很多互联网公司中都使用了分布式技术,分布式技术带来的技术挑战是对同一个资源的并发访问,如全局ID、减库存、秒杀等场景,

并发量不大的场景可以使用数据库的悲观锁、乐观锁来实现,但在并发量高的场合中,利用数据库锁来控制资源的并发访问是不太理想的,

大大影响了数据库的性能。可以利用Redis的setnx功能来编写分布式的锁,如果设置返回1说明获取锁成功,否则获取锁失败,实际应用中要考虑的细节要更多。

6、社交网络

点赞、踩、关注/被关注、共同好友等是社交网站的基本功能,社交网站的访问量通常来说比较大,而且传统的关系数据库类型不适合存储这种类型的数据,

Redis提供的哈希、集合等数据结构能很方便的的实现这些功能。

7、最新列表

Redis列表结构,LPUSH可以在列表头部插入一个内容ID作为关键字,LTRIM可用来限制列表的数量,这样列表永远为N个ID,无需查询最新的列表,

直接根据ID去到对应的内容页即可。

8、消息系统

消息队列是大型网站必用中间件,如ActiveMQ、RabbitMQ、Kafka等流行的消息队列中间件,主要用于业务解耦、流量削峰及异步处理实时性低的业务。

Redis提供了发布/订阅及阻塞队列功能,能实现一个简单的消息队列系统。另外,这个不能和专业的消息中间件相比。

9、地理位置

使用Redis的Geo数据类型可以存储地理位置信息,实现地理位置相关的查询和分析。

10、搜索引擎

Redis的Sorted Set可以用来存储有序数据,例如排行榜、搜索结果等。

在Go语言中,可以使用ZADD、ZRANGE等命令来实现对Sorted Set的操作,实现搜索引擎的功能。

常用命令

  • SET 和 GET:用于设置和获取字符串类型的值;
  • HSET、HGET、HMSET、HMGET:用于设置和获取哈希类型的值;
  • LPUSH、RPUSH、LPOP、RPOP:用于操作列表类型的值;
  • SADD、SREM、SMEMBERS:用于操作集合类型的值;
  • ZADD、ZREM、ZRANGE:用于操作有序集合类型的值;
  • INCR、INCRBY、DECR、DECRBY:用于对整数类型的值进行原子性的加减操作;
  • EXPIRE、TTL:用于设置和查询键的过期时间;
  • PUBLISH、SUBSCRIBE:用于实现 Redis 的发布订阅功能;
  • MULTI、EXEC、WATCH、UNWATCH:用于实现 Redis 的事务功能;
  • SCAN:用于迭代大量的键,避免阻塞 Redis 服务器。

实际场景

  • 缓存
  • 数据共享分布式
  • 分布式锁
  • 全局ID
  • 计数器
  • 限流
  • 位统计
  • 购物车
  • 用户消息时间线timeline
  • 消息队列
  • 抽奖
  • 点赞、签到、打卡
  • 商品标签
  • 商品筛选
  • 用户关注、推荐模型
  • 排行榜
1、缓存

String类型

例如:热点数据缓存(例如报表、明星出轨),对象缓存、全页缓存、可以提升热点数据的访问数据。

2、数据共享分布式

String 类型,因为 Redis 是分布式的独立服务,可以在多个应用之间共享

例如:分布式Session

<dependency> 
 <groupId>org.springframework.session</groupId> 
 <artifactId>spring-session-data-redis</artifactId> 
</dependency>
3、分布式锁

String 类型setnx方法,只有不存在时才能添加成功,返回true

public static boolean getLock(String key) {
Long flag = jedis.setnx(key, "1");
if (flag == 1) {
jedis.expire(key, 10);
}
return flag == 1;
}

public static void releaseLock(String key) {
jedis.del(key);
}
4、全局ID

int类型,incrby,利用原子性

incrby userid 1000

分库分表的场景,一次性拿一段

5、计数器
int类型,incr方法

例如:文章的阅读量、微博点赞数、允许一定的延迟,先写入Redis再定时同步到数据库

6、限流

int类型,incr方法

以访问者的ip和其他信息作为key,访问一次增加一次计数,超过次数则返回false

7、位统计

String类型的bitcount(1.6.6的bitmap数据结构介绍)

字符是以8位二进制存储的

set k1 a
setbit k1 6 1
setbit k1 7 0
get k1
/* 6 7 代表的a的二进制位的修改
a 对应的ASCII码是97,转换为二进制数据是01100001
b 对应的ASCII码是98,转换为二进制数据是01100010

因为bit非常节省空间(1 MB=8388608 bit),可以用来做大数据量的统计。
*/

例如:在线用户统计,留存用户统计

setbit onlineusers 01
setbit onlineusers 11
setbit onlineusers 20

支持按位与、按位或等等操作

BITOPANDdestkeykey[key...] ,对一个或多个 key 求逻辑并,并将结果保存到 destkey 。       
BITOPORdestkeykey[key...] ,对一个或多个 key 求逻辑或,并将结果保存到 destkey 。
BITOPXORdestkeykey[key...] ,对一个或多个 key 求逻辑异或,并将结果保存到 destkey 。
BITOPNOTdestkeykey ,对给定 key 求逻辑非,并将结果保存到 destkey 。

计算出7天都在线的用户

BITOP "AND" "7_days_both_online_users" "day_1_online_users" "day_2_online_users" ...  "day_7_online_users"
8、购物车

String 或hash。所有String可以做的hash都可以做

key:用户id;field:商品id;value:商品数量。
+1:hincr。-1:hdecr。删除:hdel。全选:hgetall。商品数:hlen。
9、用户消息时间线timeline

list,双向链表,直接作为timeline就好了。插入有序

10、消息队列

List提供了两个阻塞的弹出操作:blpop/brpop,可以设置超时时间

blpop:blpop key1 timeout 移除并获取列表的第一个元素,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
brpop:brpop key1 timeout 移除并获取列表的最后一个元素,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
上面的操作。其实就是java的阻塞队列。学习的东西越多。学习成本越低
  • 队列:先进先除:rpush blpop,左头右尾,右边进入队列,左边出队列
  • 栈:先进后出:rpush brpop
11、抽奖

自带一个随机获得值

spop myset
12、点赞、签到、打卡

假如上面的微博ID是t1001,用户ID是u3001

用 like:t1001 来维护 t1001 这条微博的所有点赞用户

  • 点赞了这条微博:sadd like:t1001 u3001
  • 取消点赞:srem like:t1001 u3001
  • 是否点赞:sismember like:t1001 u3001
  • 点赞的所有用户:smembers like:t1001
  • 点赞数:scard like:t1001
13、商品标签

老规矩,用 tags:i5001 来维护商品所有的标签。

sadd tags:i5001 画面清晰细腻
sadd tags:i5001 真彩清晰显示屏
sadd tags:i5001 流程至极
14、商品筛选
// 获取差集
sdiff set1 set2
// 获取交集(intersection)
sinter set1 set2
// 获取并集
sunion set1 set2

假如:iPhone15 上市了

sadd brand:apple iPhone11
sadd brand:ios iPhone11
sad screensize:6.0-6.24 iPhone11
sad screentype:lcd iPhone 11

筛选商品,苹果的、ios的、屏幕在6.0-6.24之间的,屏幕材质是LCD屏幕

sinter brand:apple brand:ios screensize:6.0-6.24 screentype:lcd
15、用户关注、推荐模型

follow 关注 fans 粉丝

相互关注:

sadd 1:follow 2
sadd 2:fans 1
sadd 1:fans 2
sadd 2:follow 1

我关注的人也关注了他(取交集):

sinter 1:follow 2:fans

可能认识的人:

用户1可能认识的人(差集):sdiff 2:follow 1:follow
用户2可能认识的人:sdiff 1:follow 2:follow
16、排行榜

id 为6001 的新闻点击数加1:

zincrby hotNews:20190926 1 n6001

获取今天点击最多的15条:

zrevrange hotNews:20190926 0 15 withscores

go的incr+expire原子性操作之调用lua脚本

  • 它实现了 incr 和 expire 的原子化操作,并且在 key 不存在和 key 已经过期的情况下也能正常工作。

    package main

    import (
    "context"
    "fmt"
    "github.com/go-redis/redis/v8"
    "time"
    )

    // Lua脚本
    // 通过执行一个 Lua 脚本来实现原子化的 incr 和 expire 操作。如果该 key 的过期时间已经设置为 -1,
    // 则表示该 key 没有过期时间,此时通过 expire 命令为该 key 设置过期时间。
    func main(){
    client := redis.NewClient(&redis.Options{
    Addr: "localhost:6379",
    Password: "123456",
    DB: 10,
    })
    defer client.Close()

     result1, err1 := IncrWithTTL(client, "counter", 3600)
     if err1 != nil {
         fmt.Println(err1)
     } else {
         fmt.Println(result1)
     }
    

    }

    func IncrWithTTL(client *redis.Client, key string, ttl time.Duration) (int64, error) {
    script := redis.NewScript( local value = redis.call("incr", KEYS[1]) if redis.call("ttl", KEYS[1]) == -1 then redis.call("expire", KEYS[1], ARGV[1]) end return value )
    result, err := script.Run(context.Background(), client, []string{key}, ttl.String()).Result()
    if err != nil {
    return 0, err
    }
    return result.(int64), nil
    }

相关推荐
CoderIsArt40 分钟前
Redis的三种模式:主从模式,哨兵与集群模式
数据库·redis·缓存
ketil275 小时前
Redis - String 字符串
数据库·redis·缓存
红黑色的圣西罗7 小时前
Lua 怎么解决闭包内存泄漏问题
开发语言·lua
王佑辉7 小时前
【redis】延迟双删策略
redis
生命几十年3万天7 小时前
redis时间优化
数据库·redis·缓存
Shenqi Lotus8 小时前
Redis-“自动分片、一定程度的高可用性”(sharding水平拆分、failover故障转移)特性(Sentinel、Cluster)
redis·sentinel·cluster·failover·sharding·自动分片·水平拆分
qq_1728055911 小时前
GIN 反向代理功能
后端·golang·go
__AtYou__12 小时前
Golang | Leetcode Golang题解之第535题TinyURL的加密与解密
leetcode·golang·题解
YMY哈12 小时前
Redis常见面试题(二)
redis
元气满满的热码式12 小时前
Redis常用的五大数据类型(列表List,集合set)
数据库·redis·缓存