面试题总结-2-redis

1、UV和PV的含义?

 PV(page view) 即页面浏览量或点击量,衡量一个网站或网页用户访问量。

具体说:PV就是所有访问者24小时(0点到24点)内看了某个网站多少个页面或某个网页多少次。

PV是指页面刷新的次数,每一次页面刷新,就算做一次PV流量。

 UV即独立访客数,指访问某个站点或点击某个网页的不同IP地址的人数。在同一天内,UV只记录第一次进入网站的具有独立IP的访问者

 2、redis如何存储PV和UV?

 UV使用hyperloglog数据结构,是一种概率数据结构,用来估算数据的基数

Redis 的 HashMap,BitMap 和 HyperLogLog都可以做集合基数的统计,前两个在统计时,大大消耗内存,hyperloglog牺牲准确性,降低内存消耗,12k可以存储,能够统计2^64个数据。所以 HyperLogLog 适合在比如统计日活月活此类的对精度要不不高的场景

 Redis 提供了 PFADD 、 PFCOUNT 和 PFMERGE 三个命令来供用户使用 HyperLogLog

 

 从表中可以明显看出,一万数量级时 BitMap 消耗内存最小, 一千万数量级时 HyperLogLog 消耗内存最小,但是总体来看,HyperLogLog 消耗的内存都是 14392 字节,可见 HyperLogLog 在内存消耗方面有自己的独到之处

在使用redis存储用户UV的时候,最好的两种方案,分别是hyperloglog,还有bitmap

1、要求精确度,对于内存使用有一定容忍度,可以用bitmap

2、不要求精确度,对于内存使用要求较低内存,可以使用hyperloglog

 3、如何统计今天的UV?

 

<?php
//该方式较好
// 存入6天内用户上线情况
for ($i=0; $i < 6; $i++) {
    // 模拟在线用户
    $online_user_num = mt_rand(100000, 300000); 

    for ($j=1; $j < $online_user_num; $j++) { 
        $user_id = mt_rand(1, 1000000);
        $redis->setbit('003|online_users_day_'.$i, $user_id, 1);
    }
}
// 注  mt_rand  效率比rand要好很多

 

<?php

//统计某个用户在某个时间段是否上线
var_dump($userid = mt_rand(1, 1000000));
var_dump($redis->getbit('003|online_users_day_5', $userid));

//统计某个时间段UV
var_dump($redis->bitcount('003|online_users_day_5'));

//统计6天内 每天都上线的用户数量
var_dump($redis->bitop('AND', '003|online_users_day_both_6', '003|online_users_day_0', '003|online_users_day_1', '003|online_users_day_2', '003|online_users_day_3', '003|online_users_day_4', '003|online_users_day_5'));
var_dump($redis->bitcount('003|online_users_day_both_6'));

//求并集 统计6天内总共上线人数
var_dump($redis->bitop('OR', '003|online_users_day_total_6', '003|online_users_day_0', '003|online_users_day_1', '003|online_users_day_2', '003|online_users_day_3', '003|online_users_day_4', '003|online_users_day_5'));
var_dump($redis->bitcount('003|online_users_day_total_6'));

//统计6天内只有一次上线人数
var_dump($redis->bitop('XOR', '003|online_users_day_only_one_6', '003|online_users_day_0', '003|online_users_day_1', '003|online_users_day_2', '003|online_users_day_3', '003|online_users_day_4', '003|online_users_day_5'));
var_dump($redis->bitcount('003|online_users_day_only_one_6'));

统计今天UV,做日期为键,bitcount,可以计算出每天的UV

 4、redis中 hash结构是否存储过,使用场景?

 概念:dictht是一个散列表结构,使用拉链法保存哈希冲突的dictEntry

存储:在存用户购物车商品时,用hash存储的购物车信息

 5、bitmap应用在哪种场景当中?

 bitmap一般用在签到,统计用户UV中,非常好用

tip(小技巧)------->bitmap在使用时,可以初始化一个最大的位,避免每次使用时频繁的内存分配

可以存储10万用户86400秒,也就是一天之内的心跳状态,每秒跳一次

  6、redis中list的应用场景?

 它是链表不是数组,意味着list的插入和删除操作非常快,时间复杂度为O(1),但是索引定位很慢,时间复杂度为O(n),另外当列表弹出了最后一个元素之后,该数据结构自动被删除,内存被回收。

 应用场景:链表用来做异步队列

        将需要延后处理的任务(结构体序列化)(JSON)成字符串塞进Redis的列表

        Lpush+Lpop = stack     先进后出的栈

        Lpush+Rpop = queue  先进先出的队列

        Lpush + Ltrim = capped collection 有限集合

        Lpush + brpop = message queue 消息队列

通过命令lPUSH(BLPUSH)把消息入队

通过命令RPOP(BRPOP)获取消息

注意:list 是一个双向链表 ,左侧是头,右侧是尾,两端都可以进出数据 

// 插播一条 这里讲解一下redis9中数据类型

redis提供了丰富的数据类型,常见的有五种,String(字符串),Hash(哈希),List(列表),Set(集合),Zset(有序集合)

// 放一条连接   https://www.cnblogs.com/xiaolincoding/p/16370783.html

随着Redis版本更新,后面又支持了四种数据类型,BitMap(2.2版新增),HyperLogLog(2.8版新增),GEO(3.2版本新增),Stream(5.0版新增)

1)
string 中 value最多可以容纳的数据长度是512M
底层数据结构实现 主要是int 和 SDS(简单动态字符串)

SDS使用len属性的值,而不是空字符来判断字符串是否结束
SDS所有API都会以二进制方式来处理SDS存放在buf[]数组里的数据
而且能保存图片、视频、音频、压缩文件这样的二进制数据
获取字符串长度的时间复杂度为O(1)
C语言的字符串并不记录自身长度,所以获取长度的复杂度为O(n);而SDS结构里用len属性记录了字符串长度,所以复杂度为O(1)
Redis SDS API 是安全的,拼接字符串不会造成缓冲区溢出,因为SDS在拼接字符串之前会检查SDS空间是否满足要求,如果空间不够会自动扩容,所以不会导致缓冲区溢出的问题










restful api  7 种路由

 

 

 redis布隆过滤器的使用

 布隆过滤器是什么?

 布隆过滤器可以理解为一个不怎么精确的 set 结构,当你使用它的 contains 方法判断某个对象是否存在时,它可能会误判。但是布隆过滤器也不是特别不精确,只要参数设置的合理,它的精确度可以控制的相对足够精确,只会有小小的误判概率。当布隆过滤器说某个值存在时,这个值可能不存在;当它说不存在时,那就肯定不存在

布隆过滤器的原理

其本质就是一个只包含0和1的数组。具体操作当一个元素被加入到集合里面后,该元素通过K个Hash函数运算得到K个hash后的值,然后将K个值映射到这个位数组对应的位置,把对应位置的值设置为1。查询是否存在时,我们就看对应的映射点位置如果全是1,他就很可能存在(跟hash函数的个数和hash函数的设计有关),如果有一个位置是0,那这个元素就一定不存在

布隆过滤器基本使用

 

主要命令有

  • bf.add 添加元素

  • bf.exists 查询元素是否存在

  • bf.madd 一次添加多个元素

  • bf.mexists 一次查询多个元素是否存在

在 redis 中有两个值决定布隆过滤器的准确率:

  • error_rate:允许布隆过滤器的错误率,这个值越低过滤器的位数组的大小越大,占用空间也就越大。

  • initial_size:布隆过滤器可以储存的元素个数,当实际存储的元素个数超过这个值之后,过滤器的准确率会下降。

 redis中有一个命令可以来设置这两个值

 

bf.reserve test 0.01 100
  • 第一个值是过滤器的名字。

  • 第二个值为 error_rate 的值。

  • 第三个值为 initial_size 的值。

 注意必须在add之前使用bf.reserve指令显式创建,如果对应的 key 已经存在,bf.reserve会报错。同时设置的错误率越低,需要的空间越大。如果不使用 bf.reserve,默认的error_rate是 0.01,默认的initial_size是 100。

 解决的问题

 主要是解决大规模数据下不需要精确过滤的场景,如检查垃圾邮件地址,爬虫URL地址去重,解决缓存穿透问题等

 深入浅出BloomFilter原理 - 知乎

 Bloom Filter过滤器 发生冲突的概率非常低

单向加密,或者哈希函数,通过一个hash函数进行对输入字符串加密,散列的键不同,可能会产生相同的结果

但是,当多个哈希函数同时对一个字符串分别加密,写入bitmap的偏移量上,这样查询的时候,会采用相同的哈希函数加密,判断每个偏移量上是否是1 如果有一个不是,则肯定输入不同,若都为1,则这样,可以以非常大的概率确定,这个值跟之前输入的值相同。

误判概率,为多个哈希函数的误判率相乘

 Bloom Filter跟单哈希函数Bit-Map不同之处在于:Bloom Filter使用了k个哈希函数,每个字符串跟k个bit对应。从而降低了冲突的概率

布隆过滤器基本思想

 如果直接存储这十亿个元素的话就需要占用很大的空间,所以我们肯定不能直接存储元素。那么我们该怎样存储呢?存储方式也是十分巧妙的,可以采用位数组的方式,不直接存储元素,而是存储元素是否存在的状态,这样就可以节约大量的存储空间

 布隆过滤器PHP调用

1、安装redis的布隆过滤器扩展  redis-安装布隆过滤器插件及PHP调用_raoxiaoya的博客-CSDN博客

2、PHP调用

<?php
$redis = new \Redis();
$redis->connect('127.0.0.1', 6380);
$re = $redis->rawCommand('bf.add', 'users', 'user2');
var_dump($re);

 

 7、redis的GEO

背景:使用地图查询用户周围服务店,如出租侧,理发店,房源等,如果去数据库里查,太过于费时,如果缩小范围,缩小成一个城市范围,还要考虑用户在2个城市边界的原因,对于每一项进行一次计算,太过于耗时,这时,redis的GEO就排上了用场

使用命令 增加地理位置信息

demo:geo add key longitude latitude member [longitude latitude member ...]

向cars:locations中增加车辆编号为1以及车辆编号为2的位置信息

127.0.0.1:6379> geoadd cars:locations 120.346111 31.556381 1 120.375821 31.560368 2

Redis中geo 非常好的讲解 Redis GEO & 实现原理深度分析 - 掘金

8、Redis中的stream?

先放一个连接 别再用 Redis List 实现消息队列了,Stream 专为队列而生 - 掘金

8-1先简单使用流

 

通过将元素ID与时间进行关联,并强制要求新元素的ID必须大于旧元素的ID, Redis从逻辑上将流变成了一种只执行追加操作(append only)的数据结构。

这种特性对于使用流实现消息队列和事件系统的用户来说是非常重要的:

用户可以确信,新的消息和事件只会出现在已有消息和事件之后,就像现实世界里新事件总是发生在已有事件之后一样,一切都是有序进行的。

  • COUNT:表示每个流中最多读取的元素个数;
  • BLOCK:阻塞读取,当消息队列没有消息的时候,则阻塞等待, 0 表示无限等待,单位是毫秒。
  • ID:消息 ID,在读取消息的时候可以指定 ID,并从这个 ID 的下一条消息开始读取,0-0 则表示从第一个元素开始读取

      

 

  • Redis Stream 的结构如上图所示。有一个消息链表,每个消息都有一个唯一的 ID 和对应的内容;
  • 消息持久化;
  • 每个消费组的状态是独立的,不不影响,同一份的 Stream 消息会被所有的消费组消费;
  • 一个消费组可以有多个消费者组成,消费者之间是竞争关系,任意一个消费者读取了消息都会使 last_deliverd_id 往前移动;
  • 每个消费者有一个 pending_ids 变量,用于记录当前消费者读取了但是还没 ack 的消息。它用来保证消息至少被客户端消费了一次
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
关于JavaRedis面试题,你可以参考以下资源: 1. "Java基础教程(入门篇)"这本书中可能包含与JavaRedis相关的基础知识点,例如如何连接和操作Redis以及在Java中使用Redis的常见场景。 2. "java面试大集合"这本书中可能包含JavaRedis面试题,涵盖了Java技术栈以及与Redis相关的问题。你可以浏览这本书中的相关章节以寻找你感兴趣的JavaRedis面试题。 3. "Java基础教程(进阶篇)"这本书可能包含更深入的JavaRedis面试题,例如Java高并发和如何在Java中使用Redis进行缓存。 这些资源可能会给你提供一些有关JavaRedis面试题的参考。你可以根据自己的需求和兴趣选择适合的资源进行学习。希望这些资源能帮助到你。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [redis面试题总结(附答案)](https://blog.csdn.net/guorui_java/article/details/117194603)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [java面试大集合一共485页](https://download.csdn.net/download/wm9028/88268176)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柔情柴少

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值