使用Redis做数据缓存

目的

本关目的:使用Redis实现数据缓存。

相关知识

本文将将会你掌握:1.将数据加入缓存队列,2.缓存数据。

在我之前的文章中提到了实现了使用 Redis 做动态页面缓存,以此提高访问速度,但同时我们也提到了还有少部分动态页面是不可以对整个页面进行缓存的,例如商品页面,用户详情页面等。尽管这些页面不可以使用页面缓存,但我们仍可以对其中动态内容所需要的数据进行缓存,从而加快动态页面绘制时读取数据的速度,减少页面载入所需的时间。

使用 Redis 做数据缓存的做法是:

  • 编写一个将数据加入缓存队列的函数
    • 通过一个有序集合 cache:list 存储数据加入缓存的时间
      • 成员为数据 ID(唯一标识)
  • 分值为当前时间(time.time()
    • 通过一个有序集合 cache:delay 存储数据更新周期
      • 成员为数据 ID(唯一标识)
  • 分值为更新周期,单位为秒
  • 编写一个定时缓存数据的函数
    • 将数据转换成 JSON 格式
    • 然后将上述 JSON 存储到 Redis 
    • 根据缓存更新周期定时更新 Redis 中的缓存键

JSON

一种轻量级的数据交换格式。大多数编程语言都能高效地编码/解码 JSON 格式的数据。

将数据加入缓存队列

有序集合 cache:list 作为缓存队列,其需要依赖数据更新周期有序集合 cache:delay,加入某数据的更新周期不存在,那么我们则需要删除掉该数据的缓存。在这里,我们采用一种更便捷的方式避免数据缓存和取消数据缓存,那就是将该数据的更新周期设置为小于等于 0

将数据加入缓存队列需要同时操作这两个有序集合:

def add_cache_list(data_id, delay):
conn.zadd('cache:delay', data_id, delay)
conn.zadd('cache:list', data_id, time.time())
缓存数据

我们将数据加入到缓存队列后,就将有序集合 cache:list 的分值看作下一次要更新的时间,所以我们可以根据分值对有序集合 cache:list 进行排序,并连同分值一起取出从小到大顺序的第一个成员(最可能需要更新的成员):

conn.zrange('cache:list', 0, 0, withscores=True)

其中 withscores=True 会告诉 Redis 在返回成员时一同返回成员的分值,返回一个由零或一个元组组成的列表,例如:[(member1, score1)]

接下来,我们再判断该成员的分值:

  • 成员不存在/成员分值大于当前时间(还没有达到下一次更新的时间)
    • 等待 100 毫秒
    • 继续后续操作
  • 从有序集合 cache:delay 中取出该成员的更新周期
    • 若更新周期小于等于 0
  • 从有序集合 cache:delay 中删除该成员
  • 从有序集合 cache:list 中删除该成员
  • 删除该成员的缓存键 cache:data:*,其中 * 是数据 ID(唯一标识)
    • 若更新周期大于 0:
      • 将当前时间加上该成员的更新周期,重新存入有序集合 cache:list 中
      • 从数据库中获取到该数据值(这里可以使用伪造数据替代,例如:{'id':id, 'data':'fake data'}
      • 更新该成员的缓存键 cache:data:*,值为:上述数据编码成 JSON 格式 json(dumps(data))

将这些过程编写为 cache_row() 方法:

def cache_data():
    # 从有序集合'cache:list'中获取排名第一的元素及其分数(score)
    next = conn.zrange('cache:list', 0, 0, withscores=True)
    # 获取当前时间
    now = time.time()
    # 如果没有下一个元素或者下一个元素的时间戳大于当前时间,则休眠0.1秒
    if not next or next[0][1] > now:
        time.sleep(0.1)

    # 获取下一个元素的ID
    data_id = next[0][0]
    # 获取该元素在有序集合'cache:delay'中的分数,即延迟值
    delay = conn.zscore('cache:delay', data_id)
    # 如果延迟值小于等于0,则表示数据已过期
    if delay <= 0:
        # 从'cache:delay'集合中移除该数据的ID
        conn.zrem('cache:delay', data_id)
        # 从'cache:list'集合中移除该数据的ID
        conn.zrem('cache:list', data_id)
        # 删除键为'cache:data:' + data_id的相关数据
        conn.delete('cache:data:' + data_id)
    else:
        # 创建一个包含虚假数据的字典对象
        data = {'id': data_id, 'data': 'fake data'}
        # 更新有序集合'cache:list'中该数据的时间戳,使其在延迟之后再次被处理
        conn.zadd('cache:list', data_id, now + delay)
        # 将虚假数据存储在键为'cache:data:' + data_id的Redis键中
        conn.set('cache:data:' + data_id, json.dumps(data))

你可能感兴趣的:(缓存,redis,python,oracle,开发语言,数据结构,spring,boot)