【面试题】如何在亿级别用户中检查用户名是否存在?

alt

前言

不知道大家有没有留意过,在使用一些app或者网站注册的时候,提示你用户名已经被占用了,比如我们熟知的《英雄联盟》有些人不知道取啥名字,干脆就叫“不知道取啥名”。

alt

但是有这样困惑的可不止他一个,于是就出现了“不知道取啥名1”...“不知道取啥名99” alt

需要更换一个,这是如何实现的呢?你可能想这不是很简单吗,去数据库里查一下有没有不就行了吗,那么假如用户数量很多,达到数亿级别呢,这又该如何是好? alt

解决思路

到底有哪些方案呢? 数据库可行吗? 有什么缺点呢?缓存呢?还有什么更好的方法吗?

alt

具体实现方案

关系型数据库

alt 遇事不决,先想到数据库,很多时候,数据库虽说不是最好的方案,但是都可以成为一种保底方案,所以在面试的时候,如果想到不到其他方案我们可以首先想到数据库(这里所的当然是关系型数据库啦),那数据库到底应该怎么实现呢,说来也很简单,将用户信息的name列设置为唯一索引,这样有两个好处,首先索引可以提升查询的效率,同时还能利用唯一索引的特性,将用户的名字自动去重,查询的时候,直接"select id(或name) from user where name =用户名", 如果能返回查询结果,则说明用户已经存在,需要重新写新的名字,同时我还要告诉你,这句SQL这样写还能避免回表查询,这样也会在一定程度上提升查询的效率。

这种方案虽然实现了功能,但是这样做会带来一个比较致命的问题,那就是查询速度比较慢,亿级别数据是很大的,这时候还考虑mysql的话,他的查询速度将会非常慢,这样用户的体验将会非常不好,有人可能会说了呀,那你可以分库分表呀,是的,可以这么做,但是就算分库分表你还是得扫描整个库表,这种做法解决不了根本问题。同时数据库对并发连接和资源有限制。如果注册率继续增长,数据库服务器可能难以处理数量增加的传入请求。比如像英雄联盟这种大型游戏,突然有什么活动,用户大批量涌入,进行注册,就会出现数据库难以处理持续增长的请求。

使用缓存

alt

试想一下,数据库能实现的话,我们的缓存可以实现吗?

对哦,redis天生有set这种类型的数据,我们可以设置一个key,比如:register_user,然后每次注册用户直接向缓存添加用户名,如果能成功则说明用户不重复,不能添加成功则说明用户已经被注册。这些操作都是在缓存中进行的,虽然查询速度会比mysql快,但是又会引入一个新的问题,那就是redis的大key问题。

这里补充一下什么是redis的大key问题: 普遍认同的规范是:value > 10kb,即认定为大 key,同时像list,set,hash 等容器类型的 redis key,元素数量 > 5000,即认定为大 key。

那大key会带来什么问题呢?

大 key 会带来以下四种影响:

  • 客户端超时阻塞:由于 Redis 执行命令是单线程处理,然后在操作大 key 时会比较耗时,那么就会阻塞 Redis,从客户端这一视角看,就是很久很久都没有响应。

  • 引发网络阻塞:每次获取大 key 产生的网络流量较大,如果一个 key 的大小是 1 MB,每秒访问量为 1000,那么每秒会产生 1000MB 的流量,这对于普通千兆网卡的服务器来说是灾难性的。

  • 阻塞工作线程:如果使用 del 删除大 key 时,会阻塞工作线程,这样就没办法处理后续的命令。

  • 内存分布不均:集群模型在 slot 分片均匀情况下,会出现数据和查询倾斜情况,部分有大 key 的 Redis 节点占用内存多,QPS 也会比较大。

像我们这种业务场景必定是大key无疑了,虽然我们也可以设计一些算法将key拆分,分成不同的小key,但是又有一个新的问题出现了,假设我们每个用户名字占20个字节,那1亿用户将会耗费20G左右的内存,内存是比较珍稀且昂贵的资源,我们一下就耗费20g资源,能不能想个法子,节约一下成本,让老板觉得你是个人才,以后每次你提离职老板都亲自挽留你,并给你涨工资。(你还真别说,我有同事就是这么干的而且还真成功了,只能羡慕人家技术好啊) alt

布隆过滤器

直接缓存判断内存占用过大,有没有什么更好的办法呢?布隆过滤器就是很好的一个选择。

那究竟什么布隆过滤器呢?

布隆过滤器(Bloom Filter)是一种数据结构,用于快速检查一个元素是否存在于一个大型数据集中,通常用于在某些情况下快速过滤掉不可能存在的元素,以减少后续更昂贵的查询操作。 布隆过滤器的主要优点是它可以提供快速的查找和插入操作,并且在内存占用方面非常高效。 alt 结构如图所示,布隆过滤器的核心思想是使用一个位数组(bit array)和一组哈希函数。

  • 位数组(Bit Array) :布隆过滤器使用一个包含大量位的数组,通常初始化为全0。每个位可以存储两个值,通常是0或1。这些位被用来表示元素的存在或可能的存在。

  • 哈希函数(Hash Functions) :布隆过滤器使用多个哈希函数,每个哈希函数可以将输入元素映射到位数组的一个或多个位置。这些哈希函数必须是独立且具有均匀分布特性。哈希函数的个数越多,产生误判的概率就越低。

那么具体是怎么做的呢?

布隆过滤器的操作分为添加元素和查询元素两个阶段

  • 添加元素:如上图所示,当将字符串“name1”,“name2”插入布隆过滤器时,通过多个哈希函数将元素映射到位数组的多个位置,然后将这些位置的位设置为1。

  • 查询元素:当要检查一个元素是否存在于布隆过滤器中时,通过相同的哈希函数将元素映射到位数组的相应位置,然后检查这些位置的位是否都为1。如果有任何一个位为0,那么可以确定元素不存在于数据集中。但如果所有位都是1,元素可能存在于数据集中,但也可能是误判。

说了那么多他的优点在哪呢?

优点: 节约内存空间,相比使用哈希表等数据结构,布隆过滤器通常需要更少的内存空间,因为它不存储实际元素,而只存储元素的哈希值。

有同学可能要问了呀,你说更少就更少吗?怎么证明他确实省,像京东口号一样,"多快好省"!

alt

这里公司可以参考公式: m = -(n * ln(p)) / (ln(2)^2) 其中:m 是所需要的位数,n 是过滤器中元素的数量,p 是期望的误判率。

举个例子
alt

在这里给大家一个案例,现在有1亿用户,我们把误判率设为0.001在给定的条件下,其中 n 是10^8(1亿),p 是0.001(0.1%),我们可以将这些值带入公式中:m = -(10^8 * ln(0.001)) / (ln(2)^2) 运算后,我们得到的结果 m 大约为2.88*10^9位。为了将位转换为字节(1字节 = 8位),我们需要除以8:m_in_bytes = m / 8这将得到大约3.6*10^8字节,或者说约 0.36 GB 的内存需求。 相比原理的20G一下减少了19G还多,而且查询的时候也是O(1)的时间复杂度,对其他实现方案来说,这将是一场屠杀

难道只有优点吗?

alt

缺点 布隆过滤器在判断元素是否存在时,有一定的误判率。这意味着在某些情况下,它可能会错误地报告元素存在,但不会错误地报告元素不存在。不能删除元素,布隆过滤器通常不支持从集合中删除元素,因为删除一个元素会影响其他元素的哈希值,增加了误判率。

参看文献

https://web.archive.org/web/20110930114037/http://en.wikipedia.org/wiki/Bloom_filter#Probability_of_false_positives

https://blog.csdn.net/J_bean/article/details/135996254

https://juejin.cn/post/7293786247655129129

https://blog.csdn.net/weixin_62827806/article/details/136290340

alt

本文由 mdnice 多平台发布

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/800337.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何从应用商店Microsoft Store免费下载安装HEVC视频扩展插件

在电脑上打开一张HEIC类型的图片提示缺少HEVC解码器,无法打开查看,现象如下: 这种情况一般会提示我们需要下载安装HEVC解码器,点击“立即下载并安装”会跳转到应用商店,但是我们发现需要付费7元才能下载安装 免费安装…

6. Z 字形变换(Java)

目录 题目描述:输入:输出:代码实现: 题目描述: 将一个给定字符串 s 根据给定的行数 numRows ,以从上往下、从左到右进行 Z 字形排列。 比如输入字符串为 “PAYPALISHIRING” 行数为 3 时,排列如…

mac | Windows 本地部署 Seata2.0.0,Nacos 作为配置中心、注册中心,MySQL 存储信息

1、本人环境介绍 系统 macOS sonama 14.1.1 MySQL 8.2.0 (官方默认是5.7版本) Seata 2.0.0 Nacos 2.2.3 2、下载&数据库初始化 默认你已经有 Nacos、MySQL,如果没有 Nacos 请参考我的文章 : Docker 部署 Nacos(单机…

订阅edk2社区邮件列表

给社区发邮件步骤 UEFI订阅邮件列表 开发者订阅邮箱 develedk2.groups.io | Home 点击Join This Group,按照步骤填写自己邮箱地址(该地址是edk2,发送邮件到该邮箱的地址) 自己邮箱确认就可以自动收到邮件了 比如:

虚拟串口工具vspd.exe的使用

关于vspd虚拟串口工具的获取: 工具下载 (1、 虚拟串口工具官方下载链接 2、通过本文资源下载)工具按照步骤(过于简单,此处省略) 关于vspd虚拟串口工具的使用: 打开软件,如下&…

鸡哥的蛋糕大作战(蓝桥杯)

文章目录 鸡哥的蛋糕大作战问题描述模拟 鸡哥的蛋糕大作战 问题描述 鸡哥是一位著名的糕点师傅,他特别擅长做各种形状的蛋糕。他有一种特殊的蛋糕制作方法,那就是在蛋糕上开洞。有一天,他想到一个有趣的想法:不同的数字可以代表…

Ethernet 汇总

Ethernet系统 硬件最小系统 CPU:可以是复杂的芯片,也可以是小的单片机DMA:用于减轻CPU负担,搬运数据系统Memory<->FIFOMAC:可以集成在芯片里面,用于CPU和PHY之间的通信MII:接口用于MAC和PHY的通信,包括控制MDIO和数据DataPHY:模拟器件,最底层,数据收发源头软件…

【json.dump()】的用法和【pickle.dump()】的用法

json.dump()写入 json.dump() 函数用于将 Python 对象序列化为 JSON 格式的字符串,并将该字符串写入文件。它接受两个参数:要序列化的 Python 对象和要写入的文件对象。 下面是 json.dump() 函数的基本用法示例: import json# 要序列化的 Python 对象 data = {"name…

本地电脑渲染不行怎么解决?自助式渲染助你渲染无忧

有时候&#xff0c;即使购买了昂贵的新电脑&#xff0c;我们也可能会遇到渲染速度缓慢、画质不佳或渲染失败等问题。这些问题可能由多种因素引起。针对该问题&#xff0c;为大家推荐了自助式的渲染&#xff0c;解决你本地电脑渲染不佳问题。 电脑渲染不行原因 新电脑渲染效果不…

【Vue】Vue3开发从入门到实战目录【最新版本vue3+typescript前端开发教程】

Vue3开发从入门到实战目录 1. vue3简介与环境配置 2. 创建vue3项目 3. 我的第一个组件 4. 编写简单页面效果 5. OptionsAPI与CompositionAPI 6. setup概述与使用 7. ref基本类型的响应式数据 8. ref对象类型的响应式数据 9. reactive对象类型的响应式数据 10…

Node.js从基础到高级运用】二十二、同步执行的子进程

引言 在 Node.js 的应用程序中&#xff0c;我们有时候需要在父进程中同步地执行子进程&#xff0c;这对于需要顺序执行任务或者处理命令行工具的输出特别有用。child_process 模块在 Node.js 中用于创建子进程&#xff0c;并且提供了几种同步执行子进程的方法。在 Windows 系统…

MongoDB主从复制模式基于银河麒麟V10系统

MongoDB主从复制模式基于银河麒麟V10系统 背景介绍 MongoDB自4.0版本开始已经不再建议使用传统的master/slave复制架构,而是全面采用了复制集(Replica Sets)作为标准的复制和高可用性解决方案。 复制集是MongoDB的一种数据复制和高可用性机制,通过异步同步数据至多个服务…

为什么企业推广需要品牌故事?媒介盒子分享

从时代来看&#xff0c;我们正处“信息超载的商业时代”&#xff0c;品牌传播面临着“产品同质化”和“信息超载化”的困境。近日小米SU7的出圈除了汽车本身的话题度外&#xff0c;离不开小米的品牌故事、创始人雷军的话题等等。今天媒介盒子就来和大家聊聊&#xff1a;为什么企…

postgresql发布和订阅

一、发布订阅介绍 发布和订阅使用了pg的逻辑复制的功能&#xff0c;通过发布端创建publication与表绑定&#xff0c;订阅端创建subscription同时会在发布端创建逻辑复制槽实现逻辑复制功能 逻辑复制基于 发布&#xff08;Publication&#xff09; 与 订阅&#xff08;Subscri…

【go】模板展示不同k8s命名空间的deployment

gin模板展示k8s命名空间的资源 这里学习如何在前端单页面&#xff0c;调用后端接口展示k8s的资源 技术栈 后端 -> go -> gin -> gin模板前端 -> gin模板 -> html jsk8s -> k8s-go-client &#xff0c;基本资源(deployment等) 环境 go 1.19k8s 1.23go m…

Idea调试热更新那些事

用惯了Eclipse,对于eclipse的调试过程中HotSwap生效感觉很爽&#xff0c;更换为IDEA后&#xff0c;总觉得别扭得很&#xff0c;非要手动触发“Recompile *.java"这个才能生效。最开始老是感觉我哪里理解不到位&#xff0c;或者我的环境配置哪里有问题&#xff0c;反正就是…

根据生辰八字四柱命理测算童子命童子煞算法

#小李子9479# #不讲废话# 真童子命算法口诀: 1。春秋寅子贵 //命造生在春季或秋季的(以月令算),日支或时支见寅或子的2。冬夏卯未辰 //命造生在冬季或夏季的(以月令算),日支或时支见卯、未或辰的3。金木马卯和 //年柱纳音为金或木的,日支或时支见午或卯的4。水火遇鸡…

多域名单点登录信息未同步问题

一个网站有多个域名&#xff0c;其中四个域名指向的是同一个页面&#xff0c;另外还有一个地址指向前面页面里面的某个功能。 https://www.xxx.cn/ https://xxx.cn/ https://www.xxx.com.cn/ https://xxx.com.cn/ xxx.com.cn网站下某个功能跳转到https://ab.xxx.com.cn/在ab.x…

QT6 Android设置程序图标及名称

一.APP应用图标设置 1.在工程目录中,创建一个Android_sources文件夹,在build-XXX

Centos7 安装GitLab

安装环境: 虚拟机:Centos7 最小安装 4核8G 下载GitLab 本次实验下载的是 gitlab-ce-14.1.0-ce.0.el7.x86_64.rpm 官网截图 清华源截图 安装包下载地址(官网;下载CE版本,EE是收费版本):https://packages.gitlab.com/gitlab/gitlab-ce国内镜像源下载地址(清华源):htt…