前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布

redis

原创
作者头像
大学里的混子
修改2019-04-02 10:46:06
8780
修改2019-04-02 10:46:06
举报
文章被收录于专栏:LeetCode

NoSQL 中的 CAP 原理

CAP概述

CAP理论 是由 EricBrewer 教授 提出的,在设计和部署分布式应用的时候,存在三个核心的系统需求,这个三个需求之间存在一定的特殊关系。三个需求如下:

  • C: Consistency (一致性)
  • A: Availability (可用性)
  • P: Partition Tolerance (分区容错性)

CAP理论的核心是:一个分布式系统不可能同时很好的满足 一致性,可用性和分区容错性这三个需求,最多只能同时较好的满足两个。

因此,根据CAP原理,将NoSQL数据库分成满足CA原则、CP原则和AP原则 三大类: CA - 单点集群,满足一致性,可用性的系统,通常在可扩展性上不太强大。 (传统数据库) CP - 满足一致性,分区容忍性的系统,通常性能不是特别高。 (Redis、MongoDB) AP - 满足可用性,分区容忍性的系统,通常可能对一致性要求低一些。 (大多数网站架构的选择

Java中Collection和Collections的区别

1、java.util.Collection 是一个集合接口(集合类的一个顶级接口)。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式,其直接继承接口有List与Set。

 Collection    ├List    │├LinkedList    │├ArrayList    │└Vector    │ └Stack    └Set

2、Collections则是集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。

25、Redis中的管道有什么用?

一次请求/响应服务器能实现处理新的请求即使旧的请求还未被响应。这样就可以将多个命令发送到服务器,而不用等待回复,最后在一个步骤中读取该答复。

这就是管道(pipelining),是一种几十年来广泛使用的技术。例如许多POP3协议已经实现支持这个功能,大大加快了从服务器下载新邮件的过程。

26、怎么理解Redis事务?

事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。

事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。

27、Redis事务相关的命令有哪几个?

MULTI、EXEC、DISCARD、WATCH

32、Redis如何做大量数据插入?

Redis2.6开始redis-cli支持一种新的被称之为pipe mode的新模式用于执行大量数据插入工作。

45、Redis是单线程的,如何提高多核CPU的利用率?

可以在同一个服务器部署多个Redis的实例,并把他们当作不同的服务器来使用,在某些时候,无论如何一个服务器是不够的, 所以,如果你想使用多个CPU,你可以考虑一下分片(shard)。

47、Redis常见性能问题和解决方案?

(1) Master最好不要做任何持久化工作,如RDB内存快照和AOF日志文件

(2) 如果数据比较重要,某个Slave开启AOF备份数据,策略设置为每秒同步一次

(3) 为了主从复制的速度和连接的稳定性,Master和Slave最好在同一个局域网内

(4) 尽量避免在压力很大的主库上增加从库

(5) 主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1 <- Slave2 <- Slave3...

这样的结构方便解决单点故障问题,实现Slave对Master的替换。如果Master挂了,可以立刻启用Slave1做Master,其他不变。

使用 Redis 统计在线用户人数

在构建应用的时候, 我们经常需要对用户的一举一动进行记录, 而其中一个比较重要的操作, 就是对在线的用户进行记录。

本文将介绍四种使用 Redis 对在线用户进行记录的方案, 这些方案虽然都可以对在线用户的数量进行统计, 但每个方案都有一些自己特有的操作, 并且各个方案的性能特征以及资源消耗也各有不同。

添加描述

方案 1 :使用有序集合

每当一个用户上线时, 我们就执行 ZADD 命令, 将这个用户以及它的在线时间添加到指定的有序集合中:

代码语言:javascript
复制
ZADD "online_users" <user_id> <current_timestamp>

通过使用 ZSCORE 命令检查指定的用户 ID 在有序集合中是否有相关联的分值, 我们可以知道该用户是否在线:

代码语言:javascript
复制
ZSCORE "online_users" <user_id>

而通过执行 ZCARD 命令, 我们可以知道总共有多用户在线:

代码语言:javascript
复制
ZCARD "online_users"

使用有序集合储存在线用户的强大之处在于, 它是本文介绍的所有方案当中, 能够执行最多聚合操作的一个方案, 原因在于, 这一方案既可以通过有序集合的成员(也即是用户的 ID)进行聚合操作, 也可以根据有序集合的分值(也即是用户的登录时间)进行聚合操作。

首先, 通过 ZINTERSTOREZUNIONSTORE 命令, 我们可以对多个记录了在线用户的有序集合进行聚合计算:

代码语言:javascript
复制
# 计算出 7 天之内都有上线的用户,并将它储存到 7_days_both_online_users 有序集合当中
ZINTERSTORE 7_days_both_online_users 7 "day_1_online_users" "day_2_online_users" ... "day_7_online_users"

# 计算出 7 天之内总共有多少人上线了
ZUNIONSTORE 7_days_total_online_users 7 "day_1_online_users" ... "day_7_online_users"

此外, 通过 ZCOUNT 命令, 我们可以统计出在指定的时间段之内有多少用户在线, 而 ZRANGEBYSCORE 命令则可以让我们获取到这些用户的名单:

代码语言:javascript
复制
# 统计指定时间段内上线的用户数量
ZCOUNT "online_users" <start_timestamp> <end_timestamp>

# 获取指定时间段内上线的用户名单
ZRANGEBYSCORE "online_users" <start_timestamp> <end_timestamp> WITHSCORES

通过这一方法, 我们可以知道网站在不同时间段的上线人数以及上线用户名单, 比如说, 我们可以用这个方法来分别获知网站在早晨、上午、中午、下午和夜晚的上线人数。

方案 2 :使用集合

正如上一节所说, 使用有序集合能够同时储存在线用户的名单以及各个用户的上线时间, 但如果我们只想要记录在线用户的名单, 而不想要储存用户的上线时间, 那么也可以使用集合来代替有序集合, 对在线的用户进行记录。

在这种情况下, 每当一个用户上线时, 我们就执行以下 SADD 命令, 将它添加到在线用户名单当中:

代码语言:javascript
复制
SADD "online_users" <user_id>

通过使用 SISMEMBER 命令, 我们可以检查一个指定的用户当前是否在线:

代码语言:javascript
复制
SISMEMBER "online_users" <user_id>

而统计在线人数的工作则可以通过执行 SCARD 命令来完成:

代码语言:javascript
复制
SCARD "online_users"

通过集合运算操作, 我们可以像有序集合方案一样, 对不同时间段或者日期的在线用户名单进行聚合计算。 比如说, 通过 SINTER 或者 SINTERSTORE 命令, 我们可以计算出一周都有在线的用户:

代码语言:javascript
复制
SINTER "day_1_online_users" "day_2_online_users" ... "day_7_online_users"

此外, 通过 SUNION 命令或者 SUNIONSTORE 命令, 我们可以计算出一周内在线用户的总数量:

代码语言:javascript
复制
SUNION "day_1_online_users" "day_2_online_users" ... "day_7_online_users"

而通过执行 SDIFF 命令或者 SDIFFSTORE 命令, 我们可以知道哪些用户今天上线了, 但是昨天没有上线:

代码语言:javascript
复制
SDIFF "today_online_users" "yesterday_online_users"

又或者工作日上线了, 但是假日没有上线:

代码语言:javascript
复制
# 计算工作日上线名单
SINTERSTORE "weekday_online_users" "monday_online_users" "tuesday_online_users" ... "friday_online_users"
# 计算假日上线名单
SINTERSTORE "holiday_online_users" "saturday_online_users" "sunday_online_users"
# 计算工作日上线但是假日未上线的名单
SDIFF "weekday_online_users" "holiday_online_users"

诸如此类。

方案 3 :使用 HyperLogLog

虽然使用有序集合和集合能够很好地完成记录在线人数的工作, 但以上这两个方案都有一个明显的缺点, 那就是, 这两个方案耗费的内存会随着被统计用户数量的增多而增多: 如果你的网站用户数量比较多, 又或者你需要记录多天/多个时段的在线用户名单并进行聚合计算, 那么这两个方案可能会消耗你大量内存。

另一方面, 在有些情况下, 我们只想要知道在线用户的人数, 而不需要知道具体的在线用户名单, 这时有序集合和集合储存的信息就会显得多余了。

在需要尽可能地节约内存并且只需要知道在线用户数量的情况下, 我们可以使用 HyperLogLog 来对在线用户进行统计: HyperLogLog 是一个概率算法, 它可以对元素的基数进行估算, 并且每个 HyperLogLog 只需要耗费 12 KB 内存, 对于用户数量非常多但是内存却非常紧张的系统, 这一方案无疑是最佳之选。

在这一方案下, 我们使用 PFADD 命令去记录在线的用户:

代码语言:javascript
复制
PFADD "online_users" <user_id>

使用 PFCOUNT 命令获取在线人数:

代码语言:javascript
复制
PFCOUNT "online_users"

因为 HyperLogLog 也提供了计算交集的 PFMERGE 命令, 所以我们也可以用这个命令计算出多个给定时间段或日期之内, 上线的总人数:

代码语言:javascript
复制
# 统计 7 天之内总共有多少人上线了
PFMERGE "7_days_both_online_users" "day_1_online_users" "day_2_online_users" ... "day_7_online_users"
PFCOUNT "7_days_both_online_users"

方案 4 :使用位图(bitmap)

回顾上面介绍的三个方案, 我们可以得出以上结论:

  • 使用有序集合或者集合能够储存具体的在线用户名单, 但是却需要消耗大量的内存;
  • 而使用 HyperLogLog 虽然能够有效地减少统计在线用户所需的内存, 但是它却没办法准确地记录具体的在线用户名单。

那么是否存在一种既能够获得在线用户名单, 又可以尽量减少内存消耗的方法存在呢? 这种方法的确存在 —— 使用 Redis 的位图就可以办到。

Redis 的位图就是一个由二进制位组成的数组, 通过将数组中的每个二进制位与用户 ID 进行一一对应, 我们可以使用位图去记录每个用户是否在线。

当一个用户上线时, 我们就使用 SETBIT 命令, 将这个用户对应的二进制位设置为 1 :

代码语言:javascript
复制
# 此处的 user_id 必须为数字,因为它会被用作索引
SETBIT "online_users" <user_id> 1

通过使用 GETBIT 命令去检查一个二进制位的值是否为 1 , 我们可以知道指定的用户是否在线:

代码语言:javascript
复制
GETBIT "online_users" <user_id>

而通过 BITCOUNT 命令, 我们可以统计出位图中有多少个二进制位被设置成了 1 , 也即是有多少个用户在线:

代码语言:javascript
复制
BITCOUNT "online_users"

跟集合一样, 用户也能够对多个位图进行聚合计算 —— 通过 BITOP 命令, 用户可以对一个或多个位图执行逻辑并、逻辑或、逻辑异或或者逻辑非操作:

代码语言:javascript
复制
# 计算出 7 天都在线的用户
BITOP "AND" "7_days_both_online_users" "day_1_online_users" "day_2_online_users" ... "day_7_online_users"

# 计算出 7 在的在线用户总人数
BITOP "OR" "7_days_total_online_users" "day_1_online_users" "day_2_online_users" ... "day_7_online_users"

# 计算出两天当中只有其中一天在线的用户
BITOP "XOR" "only_one_day_online" "day_1_online_users" "day_2_online_users"

HyperLogLog 方案记录一个用户是否在线需要花费 1 个二进制位, 对于用户数为 100 万的网站来说, 使用这一方案只需要耗费 125 KB 内存, 而对于用户数为 1000 万的网站来说, 使用这一方案也只需要花费 1.25 MB 内存。

虽然位图节约内存的效果不及 HyperLogLog 那么显著, 但是使用位图可以准确地判断一个用户是否上线, 并且能够像集合和有序集合一样, 对在线用户名单进行聚合计算。 因此对于想要尽量节约内存, 但又需要准确地知道用户是否在线, 又或者需要对用户的在线名单进行聚合计算的应用来说, 使用位图可以说是最佳之选。

总结

以下表格总结了以上四个方案的特点:

方案

特点

有序集合

能够同时储存在线用户的名单以及用户的上线时间,能够执行非常多的聚合计算操作,但是耗费的内存也非常多。

集合

能够储存在线用户的名单,也能够执行聚合计算,消耗的内存比有序集合少,但是跟有序集合一样,这个方案消耗的内存也会随着用户数量的增多而增多。

HyperLogLog

无论需要统计的用户有多少,只需要耗费 12 KB 内存,但由于概率算法的特性,只能给出在线人数的估算值,并且也无法获取准确的在线用户名单。

位图

在尽可能节约内存的情况下,记录在线用户的名单,并且能够对这些名单执行聚合操作。

因为 Redis 同时支持多种数据结构, 所以一个问题常常可以在 Redis 里面找多种不同的解法, 并且每种解法都有各自的优点和缺点, 本文介绍的问题就是一个很好的例子。

关于统计在线用户的方法就介绍到这里, 希望这些方案会给大家带来帮助和启发。

想要知道更多有趣和实用的 Redis 用法, 请关注我的新书《Redis使用教程》(RedisGuide.com)。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • NoSQL 中的 CAP 原理
    • CAP概述
    • Java中Collection和Collections的区别
    • 使用 Redis 统计在线用户人数
      • 方案 1 :使用有序集合
        • 方案 2 :使用集合
          • 方案 3 :使用 HyperLogLog
            • 方案 4 :使用位图(bitmap)
              • 总结
              相关产品与服务
              云数据库 Redis
              腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档