Redis服务器开发,Redis的使用模式之计数器模式实例

Redis 是目前 NoSQL
领域的当红炸子鸡,它象一把瑞士军刀,小巧、锋利、实用,特别适合解决一些使用传统关系数据库难以解决的问题。打算写一系列
Redis 使用模式的文章,深入总结介绍 Redis 常见的使用模式,以供大家参考。

Redis服务器开发(talk abstract)

薄荷网 谢文威

Redis简介

REmote disctionary server remote data structure server

  • key-value nosql data base, string list hash set sorted set
    丰富的数据类型
  • 内存数据库,RDB和AOF
  • 复制,集群 Lua

常见汇总计数器

Redis特点

  • 快 110k读 50k写
  • 简单,命令简单易上手
  • 使用,功能强大
    适合服务端开发使用Relational数据

汇总计数是系统常见功能,比如网站通常需要统计注册用户数,网站总浏览次数等等。
使用 Redis 提供的基本数据类型就能实现汇总计数器,通过 incr
命令实现增加操作。

面试题

比如注册用户数,基本操作命令如下:

实现网站系统消息

  • 管理员发送消息给全体用户
  • 用户获取消息状态,新消息条数
  • 系统消息列表
  • 读某个系统消息的内容

复制代码 代码如下:

关系数据库解决

  • User.id name
  • Message.id title body created_at state
  • UserMessage.id user_id message_id created_at updated_at stat

 # 获取注册用户数
  get total_users
  # 注册用户数增加一位
  incr total_users

问题升级

  • 千万级用户,每个消息都要向user_message插入数据
  • 2/8定律:不是所有人的消息放入user_message,只放入活跃用户记录,减少10%。还是很多
  • 已读未读,只放已读的,不妨未读

按时间汇总的计数器

Redis解决1

  • set数据类型,为每个用户建立已读的message id集合
  • key为user_id

通常计数还要按时间统计,比如注册用户数需要按日统计,处理方法比较简单,把日期带入计数器
key 就可以。

主要操作

  • 发消息
  • 获取消息
  • 置已读消息 sadd user:<id>:msg msg_id
  • 置已读消息计数

还是注册用户计数的例子,基本操作命令如下:

Redis解决2

把usermessage转化为key-value存储

复制代码 代码如下:

主要操作

  • 发消息
  • 获取消息
  • 置已读消息 在集合中

# 假定操作 2014-07-06 数据
  # 获取注册用户数
  get total_users:2014-07-06
  # 2014-07-06 注册用户数增加一位
  incr total_users:2014-07-06
  # 设置 48 小时过期时间 172800 = 48 * 60 * 60
  expire total_users:2014-07-06 172800

Redis解决3

  • redis bit特性,用0/1位来表示某个用户是否已经读过
  • 1Mbit 8000000位
  • key:mes:<id>:bits value: long string

为计数器设置一个 48 小时的过期时间是为了节省计数器占用空间,毕竟 redis
是内存数据库,可以在过期前执行一个任务把计数器存入关系数据库。

对比

redis基于user的message id集合 操作redis次数较少,需要额外维护message
counter
redis基于message的user id集合 需要便利messages,操作redis次数少
redis基于message的user bits, 极简化存储,操作稍微麻烦一点

速度控制

常见Redis使用模式

  • string
  • list
  • set
  • sorted set
  • hash

速度控制也是 Redis 一种常见的计数用途,比如有一个 API
服务,希望控制每一个 IP 每秒请求数不超过 10 次,可以用 IP 和 时间秒作为
key 设置一个计数器,实现控制,伪代码如下所示:

计数器

  • 简单汇总计数,网站用户总数: incr total_users, get total_users

  • 按照时间汇总的计数器,如每日注册用户

    • key users:20140719
    • expire users:20140719 172800
  • Hash记录大批量计数,如用户Page View Click

    • key: users:page_clicks
    • value:
      • hash key: user_id
      • value: clicks
  • 速度控制:爬虫的冲击,对其访问进行控制:大于阈值抛出异常

复制代码 代码如下:

最新列表

 # 每秒最大请求数
  MAX_REQUESTS_PER_SECOND = 10

最新注册用户列表

  • key: rent_user
  • value: list

  # 检查 ip 请求限制
  # @param ip
  # @raise 超过限制,抛出 RuntimeError 异常

论坛最新发表主题

  • key: rent_topics
  • value: list

  def check_request_limitation_for_ip(ip)
    time_tick = Time.now.to_i
    key = “#{ip}:#{time_tick}”
    num = $redis.get(key).to_i
    if num > MAX_REQUEST_PER_SECOND
      raise ‘too many requests’
    else
      $redis.incr(key)
      $redis.expire(key, 10)
    end
  end

集合(set)

  • 对象标签tag
  • 用户关注关系
  • 违规词判断
  • 常见操作:
    • sadd key “ruby”
    • scard key
    • sismember key “rury”
    • smembers key
    • sinter key1 key2
  • Ruby使用正则表达式判断违规词 比较吃力

自动判断文章是否违规,为网警提供支持

使用 Hash 数据类型维护大量计数器

sorted list

  • 用户积分榜 查排名
    • key: user_ranking
    • value: user_id -> score
  • 热门话题排行榜
    • key: topic_ranking
    • value: topic_id -> score
  • 常见操作

有时候需要维护大量计数器,比如每一个论坛主题的查看数,比如每一个用户访问页面次数,因为论坛主题和用户基数可能很大,直接基于论坛主题或用户
ID 生成计数器的话,占用 Redis 资源还是相当可观的,这时可以用 Hash
数据类型压缩所需资源。

hash

  • 会话数据
    • key session_id
    • value hash
  • 用户特性表
    • key: user:<id>:profile
    • value: hash
  • 常见操作
    • hset key name “Ruby”
    • hget key name
    • hgetall key

比如,对应论坛主题查看计数,可以由模式

更多

  • 跨服务器的锁定:
    用户需要生成pdf,如果同时执行多次,资源消耗,存在冲突,所以加跨进程跨服务器的锁。内存共享的方式来实现这样的锁定。直接使用redis的key/value做一个锁定判断。
  • 任务队列:
  • 缓存:本身可以做 与memcache不相上下 还可以持久化
    配置不同,限定总内存大小,设置LRU策略

复制代码 代码如下:

总结

  • 多种类型的key value内存数据库
  • 更多的功能

  key: topic:<topic_id>:views
  value: view count (integer)

转换为模式:

复制代码 代码如下:

 key: topic:views
  value: hash
    hash key: <topic_id>
    hash value: view count (integer)

总结:利用 Redis 实现计数器,可以简单高效实现各种计数功能。

您可能感兴趣的文章:

  • 详解Java多线程编程中CountDownLatch阻塞线程的方法
  • Java多线程编程之CountDownLatch同步工具使用实例
  • java线程并发countdownlatch类使用示例
  • Java数据结构及算法实例:快速计算二进制数中1的个数(Fast Bit
    Counting)
  • js计数器代码
  • PHP计数器的实现代码
  • php计数器的设计与实现
  • ASP
    Access实现网站计数器(访问量)
  • MySQL中实现高性能高并发计数器方案(例如文章点击数)
  • Java中CountDownLatch用法解析

Post Author: admin

发表评论

电子邮件地址不会被公开。 必填项已用*标注