文章目录
缓存功能
实现思路

整体的思路:
应用服务器访问数据的时候,先查询 Redis
- 如果
Redis
上数据存在了,就直接从Redis
读取数据交给应用服务器,不继续访问数据库了 - 如果
Redis
上数据不存在,再读取MySQL
,把读到的结果,返回给应用服务器。同时,把这个数据也写入到Redis
中
Redis
这样的缓存,经常用来存储"热点"数据(高频被使用的数据)
刚才上述描述的过程,相当于是把最近使用到的数据作为热点数据
- 暗含了一层假设:某个数据一旦被用到了,那么很可能在最近这段时间就会被反复用到
存在的问题
上述策略,存在一个明显的问题:
随着时间的推移,肯定是会有越来越多的 key
在 Redis
上访问不到,从而从 MySQL
读取并写入 Redis
中,此时 Redis
里面的数据不就越来越多了吗?
- 在把数据写给
Redis
的时候,给这个key
设置一个过期时间 Redis
也在内存不足的时候,提供了"淘汰策略"
伪代码实现
- 假设业务是根据用户
uid
获取用户信息
java
UserInfo getUserInfo(long uid) {
...
}
uid
还需要拼接一些前缀:user:info
- 因为 Redis 里面存的信息有很多种,不仅仅只有用户信息
- 所以为了后续进行区分,例如
grade:info
,admin:info
... 需要拼接一个前缀
- 首先从
Redis
获取用户信息,我们假设用户信息保存在"user:info<uid>
"
java
// 根据 uid 得到 Redis的键
String key = "user:info: " + uid;
// 尝试从 Redis 中获取对应的值
String value = Redis 执行命令: get key;
// 如果缓存命中(hit)
if(value != null) {
// 假设我们的用户信息按照 JSON 格式存储
UserInfo userinfo = JSON 反序列化(value);
return userInfo;
}
- 如果没有从
Redis
中得到用户信息及缓存miss
,则进一步从MySQL
中获取对应的信息,随后写入缓存并返回
java
// 如果未命中(miss)
if(value == null) {
// 从数据库中,根据 uid 获取用户信息
UserInfo userInfo = MySQL 执行 SQL: select * from user_info where uid = <uid>
// 如果表中没有 uid 对应的用户信息
if(userInfo == null) {
响应 404
return null;
}
// 将用户信息序列化成 JSON 格式
String value = JSON 序列化(userInfo);
// 写入缓存,为了防止数据腐烂(rot),设置过期时间为 1 小时(3600s)
Redis 执行命令: set key value ex 3600
// 返回用户信息
return userInfo;
}
记数功能
许多应⽤都会使⽤ Redis
作为计数的基础⼯具,它可以实现快速计数、查询缓存的功能,同时数据可以异步处理或者落地到其他数据源。
如图下图所⽰,例如视频⽹站的视频播放次数可以使⽤ Redis
来完成:⽤⼾每播放⼀次视频,相应的视频播放数就会**⾃增 1**。
实现思路

企业为什么老乐意收集用户的数据?
- 因为统计可以进一步明确用户拒的需求,然后根据需求改进和迭代产品
统计
Redis
可以计数,但是不擅长统计
比如,想在上述的 Redis
中,统计播放量前 100
的视频有哪些
- 基于
Redis
搞,就很麻烦 - 相比之下,如果是
MySQL
来存储上述数据,一个SQL
就搞定了
所以在 Redis 计数之后,还需要将播放量同步到"统计数据仓库"中
异步的方式:这里写入统计数据仓库(MySQL/HDFS...)的步骤是异步的
- 不是说,来一个播放请求,这里就必须立马写一个数据
- 不要求两边是同时完成的,只要最后都完成了就行
伪代码实现
java
// 在 Redis 中统计某视频的播放次数
long incrVideoCounter(long vid) {
key = "video: " + vid;
long count = Redis 执行命令: incr key
return counter;
}
实际中要开发一个成熟、稳定的真实技术系统,要面临的挑战远不止如此简单:防作弊、按照不同维度计数、避免单点击问题、数据持久到底层数据源等等