Python--Redis实战:第二章:使用Redis构建Web应用:第四节:数据行缓存

上一篇文章: Python--Redis实战:第二章:使用Redis构建Web应用:第三节:网页缓存
下一篇文章: Python--Redis实战:第二章:使用Redis构建Web应用:第五节:网页分析

到目前为止,咱们已经:数据库

  • 将本来由关系数据库和网页浏览器实现的登陆和访客会话转移到了Redis上面实现;
  • 将本来有关系数据库实现的购物车也放到了Redis上面实现;
  • 将全部页面缓存到了Redis里面;

这一系列工做提高了网站的性能,下降了关系数据库的负载并较少了网站的成本。json

如今通过分析,咱们的网站的商品页面一般只会从数据库里面载入一两行数据,包括已登陆用户的用户信息【这些信息能够经过AJAX动态载入,因此不会对页面缓存形成影响】和商品自己的信息。即便是那些没法被整个缓存起来的页面:好比用户帐号页面、记录用户以往购买商品的页面等等,程序也能够经过缓存页面载入时所需的数据库行来减小载入页面所需的时间。segmentfault

为了展现数据行缓存的做用,咱们假设咱们的网站为了清空旧库存和吸引客户消费,决定开始新一轮的促销活动:这个活动天天都会推出一些特价商品供用户抢购,全部特价商品的数量都是限定的,卖完即止。在这种状况下,网址是不能对整个促销页面进行缓存的,由于这可能会致使用户看到错误的特价商品的剩余数量,可是每次载入页面都从数据库里面取出特价商品的剩余数量的话,又会给数据库带来巨大的压力,并致使咱们须要花费额外的成原本扩展数据库。浏览器

为了应对促销互动带来的大量负载,咱们须要对数据行进行缓存,具体的作法是:编写一个持续运行的守护进程函数,让这个函数将指定的数据行缓存到Redis里面,并不按期地对这些缓存进行更新。缓存函数会将数据行编码【encode】为JSON字典并存储在Redis的字符串里面,其中,数据列【column】的名字会被映射为JSON字典的键,而数据行的值则会被映射为JSON字典的值。缓存

程序使用了两个有序集合来记录应该在什么时候对缓存进行更新:函数

  • 第一个有序集合为调度【schedule】有序集合,它的成员为数据行的行ID,而分值则是一个时间戳,这个时间戳记录了应该在什么时候将制定的数据行缓存到Redus里面
  • 第二个有序集合为延时【delay】有序集合,它的成员也是数据行的ID,而分值则记录了指定数据行的缓存须要每隔多少秒更新一次。

为了让缓存函数按期的缓存数据行,程序首先须要将行ID和给定的延迟值添加到延迟有序集合里面,而后再将行ID和当前时间的时间戳添加到调度有序集合里面。实际执行缓存操做的函数须要用到数据行的延迟值,若是某个数据行的延迟值不存在,那么程序将取消对这个数据行的调度。若是咱们想要移除某个数据行已有的缓存,而且让缓存函数再也不缓存那个数据行,那么只须要把那个数据行的延迟值设置为小于或等于0就能够了。性能

#负责调度缓存和终止缓存的函数
import time

def schedule_row_cache(conn,row_id,delay):
    #先设置数据行的延迟值
    conn.zadd('delay:',row_id,delay)
    #当即对须要缓存的数据行进行调度
    conn.zadd('schedule:',row_id,time.time())

如今咱们已经完成了调度部分,那么接下来该如何对数据进行缓存呢?负责缓存数据行的函数会尝试读取调度有序集合的第一个元素以及该元素的分值,若是调度有序集合没有包含任何元素,或者分值存储的时间戳所指定的时间还没有来临,那么函数会先休眠50毫秒,而后再从新进行检查。当缓存函数发现了一个须要理解进行更新的数据行时,缓存函数会检查这个数据行的延迟值:若是数据行的延迟值小于或者等于0,那么缓存函数会从延迟有序集合和调度有序集合里面移除这个数据行ID,并从缓存里面删除这个数据行已有的缓存,而后再从新进行检查;对于延迟值大于0的数据行来讲,缓存函数会中数据库里面取出这些行,将他们编码为JSON格式并存储到Redis里面,而后更新这些行的调度时间。学习

def cahce_rows(conn):
    while not QUIT:
        #尝试获取下一个须要被缓存的数据行以及该行的调度时间戳,命令会返回一个包含0或1个元祖【tuple】的列表
        next=conn.zrange('schedule:',0,0,withscores=True)
        now=time.time()

        if not next or next[0][3]>now:
            #暂时没有行须要被缓存,休眠50毫秒后重试
            time.sleep(.05)
            continue
        row_id=next[0][0]

        #获取下一次调度的延迟水岸
        delay=conn.zscore('delay:',row_id)
        if delay<=0:
            #没必要再缓存这个行,将他从缓存中移除
            conn.zrem('delay:',row_id)
            conn.delete('inv:'+row_id)
            continue

        #读取行数据
        row=Inventory.get(row_id)
        #更新调度时间并设置缓存值
        conn.zadd('schedule:',row_id,now+delay)
        conn.set('inv:'+row_id,json.dumps(row.to_dict()))

经过组合使用调度函数和持续运行缓存函数,咱们实现了一种重复进行调度的自动缓存机制,而且能够为所欲为地控制缓存行缓存的更新频率:若是数据行记录的是特价促销商品的剩余数量,而且参与促销活动的用户很是多的话,那么咱们最好每隔几秒更新一次数据行缓存;另外一方面,若是数据并不常常改变,或者商品缺货是能够接受的,那么咱们能够每分钟更新一次缓存。网站

在这一节中,咱们学习了如何将数据行缓存到Redis里面,在下面一节中,咱们经过只缓存一部分页面来减小时间页面缓存所需的内存数量。编码

上一篇文章: Python--Redis实战:第二章:使用Redis构建Web应用:第三节:网页缓存
下一篇文章: Python--Redis实战:第二章:使用Redis构建Web应用:第五节:网页分析
相关文章
相关标签/搜索