聊聊redis中多样的数据类型,以及集群相关的知识


本篇文章带大家了解一下redis中多样的数据类型,以及集群相关的知识,带大家搞懂集群,希望对大家有所帮助!

聊聊redis中多样的数据类型,以及集群相关的知识

多样的数据类型

string 类型简单方便,支持空间预分配,也就是每次会多分配点空间,这样 string 如果下次变长的话,就不需要额外的申请空了,当然前提是剩余的空间够用。【相关推荐:Redis视频教程】

List 类型可以实现简单的消息队列,但是注意可能存在消息丢失哦,它并不持 ACK 模式。

Hash 表有点像关系型数据库,但是当 hash 表越来越大的时候,请注意,避免使用 hgetall 之类的语句,因为请求大量的数据会导致redis阻塞,这样后面的兄弟们就得等待了。

set 集合类型可以帮你做一些统计,比如你要统计某天活跃的用户,可以直接把用户ID扔到集合里,集合支持一些骚操作,比如 sdiff 可以获取集合之间的差集,sunion 可以获取集合之间的并集,功能很多,但是一定需要谨慎,因为牛逼的功能是有代价的,这些操作需要耗费一些 CPU 和IO 资源,可能会导致阻塞,因此大集合之间的骚操作要慎用,

zset 可以说是最闪耀的星,可以做排序,因为可以排序,因此应用场景挺多,比如点赞前xx名用户,延时队列等等。

bitmap 位图的好处就是在于节省空间,特别在做一些统计类的方面,比如要统计某一天有多少个用户签到了并且某个用户是否签到了,如果不用bitmap的话,你可能会想到用set。

SADD day 1234//签到就添加到集合
SISMEMBER day 1234//判断1234是否签到
SCARD day   //有多少个签到的

set 在功能上可以满足,但是相比bitmap的话,set要更耗费存储空间,set的底层主要是由整数集合或者 hashtable 组成,整数集合只有在数据量非常小的情况下才会使用,一般是小于512个元素,同时元素必须都是整数,对于set来说,整数集合的数据更加紧凑,他们在内存是上连续的,查询的话只能是二分查找了,时间复杂度是O(logN),而 hashtable 就不同了,这里的 hashtable 和 redis 的5大数据类型中的hash是一样的,只不过没有 value 而已,value 指向个 null,同时也不存在冲突,因为这里是集合,但是需要考虑 rehash 相关问题。ok,扯的有点远,我们说的用户签到问题,在用户非常多的情况下,set 的话肯定会用到 hashtable,hashtable 的话,其实每个元素都是个 dictEntry 结构体

typedef struct dictEntry {
    // 键
    void *key;
    // 值
    union {
        void *val;
        uint64_t u64;
        int64_t s64;
    } v;
    // 指向下个哈希表节点,形成链表
    struct dictEntry *next;

} dictEntry;

从这个结构体可以看到什么呢?首先虽然值 union(没有 value)和 next(没有冲突)是空的,但是结构体本身需要空间,还需要加上个 key,这个占用空间是实打实的,而如果用 bitmap 的话,一个bit位就可以代表一个数字,很省空间,我们来看看 bitmap 的方式如何设置和统计。

SETBIT day 1234 1//签到
GETBIT day 1234//判断1234是否签到
BITCOUNT day//有多少个签到的

bf 这是 redis4.0 之后支持的布隆过滤器 RedisBloom,但是需要单独加载对应的 module,当然我们也可以基于上述的 bitmap 来实现自己的布隆过滤器,不过既然 redis 已经支持了,通过 RedisBloom 可以减少我们的开发时间,布隆过滤器是干嘛的,我这里就不赘述了,直接来看看 RedisBloom 相关的用法吧。

# 可以通过docker的方式快速拉取镜像来玩耍
docker run -p 6379:6379 --name redis-redisbloom redislabs/rebloom:latest
docker exec -it redis-redisbloom bash
redis-cli
# 相关操作
bf.reserve sign 0.001 10000
bf.add sign 99 //99这个用户加入
bf.add exists 99//判断99这个用户是否存在

因为布隆过滤器是存在误判的,所有 bf 支持自定义误判率,0.001就代表误判率,10000 代表布隆过滤器可以存储的元素个数,当实际存储的元素个数超过这个值的时候,误判率会提高。

HyperLogLog 可以用于统计,它的优点就是占用的存储空间极小,只需要 12KB 的内存就可以统计 2^64 个元素,那它主要统计什么呢?其实主要就是基数统计,比如像 UV 这种,从功能上来说 UV 可以用 set 或者 hash 来存储,但是缺点就是耗费存储,容易使之变成大 key,如果想要节省空间,bitmap 也可以,12KB 空间的 bitmap 只能统计 12*1024*8=98304个元素,而 HyperLogLog 却可以统计 2^64 个元素,但是这么牛逼的技术其实是有误差的,HyperLogLog 是基于概率来统计的,标准误算率是 0.81%,在统计海量数据并且对精度要求不那么高的场景下,HyperLogLog 在节省空间这块还是很优秀的。

PFADD uv 1 2 3 //1 2 3是活跃用户
PFCOUNT uv //统计

GEO 是可以应用在地理位置的业务上,比如微信附近的人或者附近的车辆等等,先来看一下如果没有GEO 这种数据结构,你如何知道你附近的人?首先得上报自己的地理位置信息吧,比如经度 116.397128,纬度 39.916527,此时可以用 string、hash 数据类型存储,但是如果要查找你附近的人,string 和 hash 这种就无能为例了,你不可能每次都要遍历全部的数据来判断,这样太耗时了,当然你也不可能通过 zset 这种数据结构来把经纬度信息当成权重,但是如果我们能把经纬度信息通过某种方式转换成一个数字,然后当成权重好像也可以,这时我们只需通过zrangebyscore key v1 v2也可以找到附近的人。真的需要这么麻烦吗?于是 GEO 出现了,GEO 转换经纬度为数字的方法是“二分区间,区间编码”,这是什么意思呢?以经度为例,它的范围是[-180,180],如果要采用3位编码值,那么就是需要二分3次,二分后落在左边的用0表示,右边的用1表示,以经度是121.48941 来说,第一次是在[0,180]这个区间,因此记1,第二次是在[90,180],因此再记1,第三次是在[90,135],因此记0。纬度也是同样的逻辑,假设此时对应的纬度编码后是010,最后把经纬度合并在一起,需要注意的是经度的每个值在偶数位,纬度的每个值在奇数位。

1 1 0   //经度
 0 1 0  //纬度
------------
101100 //经纬度对应的数值

原理是这样,我们再来看看 redis 如何使用 GEO:

GEOADD location 112.123456 41.112345 99 //上报用户99的地理位置信息
GEORADIUS location  112.123456 41.112345 1 km ASC COUNT 10 //获取附近1KM的人

搞懂集群

生产环境用单实例 redis 的应该比较少,单实例的风险在于:

  • 单点故障即服务故障,没有backup

  • 单实例压力大,又要提供读,又要提供写

于是我们首先想到的就是经典的主从模式,而且往往是一主多从,这是因为大部分应用都是读多写少的情况,我们的主负责更新,从负责提供读,就算我们的主宕机了,我们也可以选择一个从来充当主,这样整个应用依然可以提供服务。

复制过程的细节

当一个 redis 实例首次成为某个主的从的时候,这时主得把数据发给它,也就是 rdb 文件,这个过程 master 是要 fork 一个子进程来处理的,这个子进程会执行 bgs*e 把当前的数据重新保存一下,然后准备发给新来的从,bgs*e 的本质是读取当前内存中的数据然后保存到 rdb 文件中,这个过程涉及大量的 IO,如果直接在主进程中来处理的话,大概率会阻塞正常的请求,因此使用个子进程是个明智的选择。

那 fork 的子进程在 bgs*e 过程中如果有新的变更请求会怎么办?

严格来说子进程出来的一瞬间,要保存的数据应该就是当时那个点的快照数据,所以是直接把当时的内存再复制一份吗?不复制的话,如果这期间又有变更改怎么办?其实这要说到写实复制(COW)机制,首先从表象上来看内存是一整块空间,其实这不太好维护,因此操作系统会把内存分成一小块一小块的,也就是内存分页管理,一页的大小一般是4K、8K或者16K等等,redis 的数据都是分布在这些页面上的,出于效率问题,fork 出来的子进程是和主进程是共享同一块的内存的,并不会复制内存,如果这期间主进程有数据变更,那么为了区分,这时最快捷的做法就是把对应的数据页重新复制一下,然后主的变更就在这个新的数据页上修改,并不会修改来的数据页,这样就保证了子进程处理的还是当时的快照。

SONIFY.io SONIFY.io

设计和开发音频优先的产品和数据驱动的解决方案

SONIFY.io 83 查看详情 SONIFY.io

以上说的变更是从快照的角度来考虑的,如果从数据的一致性来说,当快照的 rdb 被从库应用之后,这期间的变更该如何同步给从库?答案是缓冲区,这个缓冲区叫做 replication buffer,主库在收到需要同步的命令之后,会把期间的变更都先保存在这个缓冲区中,这样在把 rdb 发给从库之后,紧接着会再把 replication buffer 的数据也发给从库,最终主从就保持了一致。

replication buffer不是万能的补给剂

我们来看看 replication buffer 持续写入的时间有多长。

  • 我们知道主从同步的时候,主库会执行 fork 来让子进程完成相应地工作,因此子进程从开始执行 bgs*e 到执行完毕这期间,变更是要写入 replication buffer 的。

  • rdb 生成好之后,需要把它发送给从库,这个网络传输是不是也需要耗点时间,这期间也是要写入 replication buffer 的。

  • 从库在收到 rdb 之后需要把 rdb 应用到内存里,这期间从库是阻塞的,无法提供服务,因此这期间也是要写入 replication buffer 的。

replication buffer 既然是个 buffer,那么它的大小就是有限的,如果说上面3个步骤中,只要有一个耗时长,就会导致 replication buffer 快速增长(前提是有正常的写入),当 replication buffer 超过了限制之后就会导致主库和从库之间的连接断开,断开之后如果从库再次连接上来就会导致重新开始复制,然后重复同样的漫长的复制步骤,因此这个 replication buffer 的大小还是很关键的,一般需要根据写入的速度、每秒写入的量和网络传输的速度等因素来综合判断。

从库网络不好和主库断了该怎么办?

正常来说,只要主从之间的连接建立好了,后面主库的变更可以直接发给从库,让从库直接回放,但是我们并不能保证网络环境是百分百的通畅的,因此也要考虑从库和主库之间的断联问题。

应该是在 redis2.8 以前,只要从库断联,哪怕只有很短的时间,后面从库再次连接上来的时候,主库也会直接无脑的进行全量同步。在 2.8 版本及以后,开始支持增量复制了,增量复制的原理就是得有个缓冲区来保存变更的记录,这里这个缓冲区叫做repl_backlog_buffer,这个缓冲区从逻辑上来说是个环形缓冲区,写满了就会从头开始覆盖,所以也有大小限制。在从库重新连接上来的时候,从库会告诉主库:“我当前已经复制到了xx位置”,主库收到从库的消息之后开始查看xx位置的数据是否还在 repl_backlog_buffer 中,如果在的话,直接把xx后面的数据发给从库即可,如果不在的话,那无能为力了,只能再次进行全量同步。

需要一个管理者

在主从模式下,如果主库挂了,我们可以把一个从库升级成主库,但是这个过程是手动的,靠人力来操作,不能使损失降到最低,还是需要一套自动管理和选举的机制,这就是哨兵,哨兵它本身也是个服务,只不过它不处理数据的读写而已,它只负责管理所有的 redis 实例,哨兵每隔一段时间会和各个 redis 通信(ping 操作),每个 redis 实例只要在规定的时间内及时回复,就可以表明自己的立场。当然哨兵本身也可能存在宕机或者网络不通的情况,因此一般哨兵也会搭建个哨兵集群,这个集群的个数最好是奇数,比如3个或者5这个这种,奇数的目的主要就是为了选举(少数服从多数)。

当某个哨兵在发起 ping 后没有及时收到 pong,那么就会把这个 redis 实例标记下线,此时它还是不是真正的下线,这时其他的哨兵也会判定当前这个哨兵是不是真正的下线,当大多数哨兵都认定这个 redis 是下线状态,那么就会把它从集群中踢出去,如果下线的是从库,那么还好,直接踢出去就ok,如果是主库还要触发选举,选举也不是盲目选举,肯定是要选出最合适的那个从来充当新的主库。这个最合适充当主库的库,一般会按照以下优先级来确定:

  • 权重,每个从库其实都可以设置一个权重,权重越高的从库会被优先选择

  • 复制的进度,每个从库复制的进度可能是不一样的,优先选择当前和主库数据差距最小的那个

  • 服务的 ID,其实每个 redis 实例都有自己的 ID,如果以上条件都一样,那么会选择 ID 最小的那个库来充当主库

更强的横向伸缩性

主从模式解决了单点故障问题,同时读写分离技术使得应用支撑能力更强,哨兵模式可以自动监管集群,实现自动选主,自动剔除故障节点的能力。

正常来说只要读的压力越来越大,我们可以添加从库来缓解,那如果主库压力很大怎么办?这就得提到接下来要说的分片技术了,我们只需要把主库切成几片,部署到不同的机器上即可。这个分片就是 redis 中的概念了,当分片的时候,redis 会默认分成 0~16383 也就是一共 16384 个槽,然后把这些槽平均分到每个分片节点上就可以起到负载均衡的作用了。每个 key 具体该分到哪个槽中,主要是先 CRC16 得到一个 16bit 的数字,然后这个数字再对 16384 取模即可:

crc16(key)%16384

然后客户端会缓存槽信息,这样每当一个 key 到来时,只要通过计算就知道该发给哪个实例来处理来了。但是客户端缓存的槽信息并不是一成不变的,比如在增加实例的时候,这时候会导致重新分片,那么原来客户端缓存的信息就会不准确,一般这时候会发生两个常见的错误,严格来说也不是错误,更像一种信息,一个叫做MOVED,一个叫做ASK。moved的意思就说,原来是实例A负责的数据,现在被迁移到了实例B,MOVED 代表的是迁移完成的,但是 ASK 代表的是正在迁移过程中,比如原来是实例A负责的部分数据,现在被迁移到了实例B,剩下的还在等待迁移中,当数据迁移完毕之后 ASK 就会变成 MOVED,然后客户端收到 MOVED 信息之后就会再次更新下本地缓存,这样下次就不会出现这两个错误了。

更多编程相关知识,请访问:编程入门!!

以上就是聊聊redis中多样的数据类型,以及集群相关的知识的详细内容,更多请关注其它相关文章!


# 单点  # 潍坊网站建设路串串  # 附近的seo技巧  # 长沙seo主管  # 如皋网站推广方案  # 梅州seo写作  # 临城附近网站建设公司  # 潜江网站建设策划招聘  # 丽水seo软件免费  # 厦门网站运营优化系统  # 焦作seo推广运营公司  # 是有  # redis  # 也会  # 都是  # 的是  # 是在  # 是个  # 自己的  # 的人  # 就会  # 集群  # 数据类型 


相关栏目: 【 Google疑问12 】 【 Facebook疑问10 】 【 优化推广96088 】 【 技术知识133117 】 【 IDC资讯59369 】 【 网络运营7196 】 【 IT资讯61894


相关推荐: c++如何实现观察者设计模式_c++行为型设计模式实战  如何在CSS中清除浮动解决背景颜色不包裹内容问题_clear after技巧  《洛克王国:世界》国家队搭配攻略  LocoySpider如何批量采集电商商品_LocoySpider电商采集的模板应用  多闪电脑版下载_多闪PC端模拟器使用  c++如何使用std::thread::join和detach_c++线程生命周期管理  电脑桌面图标怎么变大变小_Windows个性化设置第一课【新手入门】  Microsoft Edge网页字体太淡看不清怎么办_Microsoft Edge字体渲染优化技巧  极兔快递官网查询入口手机版 手机极兔快递登录查询入口官方  《虎扑》关闭社区内容推荐方法  《腾讯相册管家》注销账号方法  苹果电脑如何快速查看电池状态 苹果电脑电池信息快捷方法  《火影忍者:木叶高手》快速升级攻略  聚水潭ERP后台管理系统登录 聚水潭ERP官方登录通道  圆通快递包裹轨迹查询 圆通速递快件实时位置跟踪  Excel怎么用XLOOKUP函数实现双向查找_ExcelXLOOKUP替代VLOOKUP+HLOOKUP的高级用法  京东快递物流信息不更新怎么办_物流停滞原因与处理方法  手机耗电快是什么原因 延长手机电池续航时间的设置方法【详解】  mysql如何配置从库只读_mysql从库只读设置方法  苹果如何下载nanobanana  大众点评了却看不到是怎么回事  《顺丰同城骑士》查看我的技能方法  CodeIgniter 3 连接 SQL Server:正确获取查询结果的教程  如何测试您的网站全球打开速度-网站海外测速工  海外搜索引擎推广效果怎么样,怎么分析效果!  向日葵客户端怎么进行语音通话_向日葵客户端语音通话功能使用方法  汽水音乐车机版官网5.0 汽水音乐车机版5.0版本下载入口  汽水音乐网页版登录 汽水音乐网页端官方入口  深入理解J*aScript异步操作:setTimeout与调用栈的真相  yy漫画登录页面官方入口_yy漫画在线阅读网址入口  如何修改Windows截图的默认保存位置_告别C盘让桌面更整洁【教程】  realme 10 Pro息屏方案_realme 10 Pro省电策略  豆包AI怎样为教育场景定制答疑逻辑_为教育场景定制豆包AI答疑逻辑方案【方案】  《小宇宙》标记不友善评论方法  C++如何实现矩阵乘法_C++二维数组矩阵运算代码示例  管理打开的编辑器:固定、分组和关闭技巧  PDF文件去水印平台入口 PDF水印删除网址  Sublime怎么格式化HTML代码_Sublime前端代码美化插件使用指南  教资成绩怎么查询  iPhone12是否要更新ios16  Win11怎么开启HDR_Windows 11显示器画质增强设置  向往的生活小游戏启动处_向往的生活小游戏立即启动  vivo浏览器怎么离线保存网页 vivo浏览器下载完整页面以便无网络时阅读  SQLAlchemy 2.0 与 Pydantic 模型类型安全集成指南  《兴业银行》注册登录方法  Go语言反射机制:如何访问被嵌入结构体遮蔽的方法  使用CSS :has() 选择器实现父元素样式控制:从子元素反向应用样式  抖音商城官网是什么_抖音商城官方网址与访问方法  PHP动态导航按钮:根据用户登录状态切换链接与文本  《原神》月之一版本新增书籍一览 

 2022-01-10

了解您产品搜索量及市场趋势,制定营销计划

同行竞争及网站分析保障您的广告效果

点击免费数据支持

提交您的需求,1小时内享受我们的专业解答。

运城市盐湖区信雨科技有限公司


运城市盐湖区信雨科技有限公司

运城市盐湖区信雨科技有限公司是一家深耕海外推广领域十年的专业服务商,作为谷歌推广与Facebook广告全球合作伙伴,聚焦外贸企业出海痛点,以数字化营销为核心,提供一站式海外营销解决方案。公司凭借十年行业沉淀与平台官方资源加持,打破传统外贸获客壁垒,助力企业高效开拓全球市场,成为中小企业出海的可靠合作伙伴。

 8156699

 13765294890

 8156699@qq.com

Notice

We and selected third parties use cookies or similar technologies for technical purposes and, with your consent, for other purposes as specified in the cookie policy.
You can consent to the use of such technologies by closing this notice, by interacting with any link or button outside of this notice or by continuing to browse otherwise.