惰性队列
惰性队列消息堆积问题当生产者发送消息的速度超过了消费者处理消息的速度,就会导致队列中的消息堆积,直到队列存储消息达到上限。之后发送的消息就会成为死信,可能会被丢弃,这就是消息堆积问题。 解决消息堆积有两种思路: 增加更多消费者,提高消费速度。也就是我们之前说的work queue模式 扩大队列容积,提高堆积上限 要提升队列容积,把消息保存在内存中显然是不行的。 惰性队列从RabbitMQ的3.6.0版本开始,就增加了Lazy Queues的概念,也就是惰性队列。惰性队列的特征如下: 接收到消息后直接存入磁盘而非内存 消费者要消费消息时才会从磁盘中读取并加载到内存 支持数百万条的消息存储 基于命令行设置lazy-queue而要设置一个队列为惰性队列,只需要在声明队列时,指定x-queue-mode属性为lazy即可。可以通过命令行将一个运行中的队列修改为惰性队列: 1rabbitmqctl set_policy Lazy "^lazy-queue$" '{"queue-mode":"lazy&...
死信及延迟队列
死信初识死信交换机什么是死信交换机什么是死信? 当一个队列中的消息满足下列情况之一时,可以成为死信(dead letter): 消费者使用basic.reject或 basic.nack声明消费失败,并且消息的requeue参数设置为false 消息是一个过期消息,超时无人消费 要投递的队列消息满了,无法投递 如果这个包含死信的队列配置了x-dead-letter-exchange属性,指定了一个交换机,那么队列中的死信就会投递到这个交换机中,而这个交换机称为死信交换机(Dead Letter Exchange,检查DLX)。 如果创建的死信交换机的类型是direct路由,或者topics主题模式,那么需要指定消息的x-dead-letter-routing-key,将被投递到哪个队列中,因为交换机下可能绑定了多个队列,交换机与队列之间绑定了一个key ,即BindingKey,投递消息时指定一个RoutingKey,只有BindingKey与RoutingKey匹配成功,该条消息才会被交换机投递到相应BindingKey的队列 如图,一个消息被消费者拒绝了,变成了死信: ...
生产RabbitMQ队列阻塞处理
现象 RabbitMQ的管控台有几万条消息处于ready状态,还有几百条unacked的消息。 队列阻塞-分析原因 consumer消费处理错误消息失败后没有正常进行ack, 正常的消息也不再被消费, 随即导致队里阻塞 但为什么正常消息也没有被正常消费呢? 其实这是RabbitMQ的一种保护机制。防止当消息激增的时候,海量的消息进入consumer而引发consumer宕机。 RabbitMQ提供了一种QOS(服务质量保证)功能,即在非自动确认的消息的前提下,限制信道上的消费者所能保持的最大未确认的数量。可以通过设置PrefetchCount实现。 举例说明:可以理解为在consumer前面加了一个缓冲容器,容器能容纳最大的消息数量就是PrefetchCount。如果容器没有满RabbitMQ就会将消息投递到容器内,如果满了就不投递了。当consumer对消息进行ack以后就会将此消息移除,从而放入新的消息。 12345678910listener: simple: # 消费端最小并发数 concurrency: 1 # 消费端最大并发数 m...
Redis 单机、集群安装
本章是基于CentOS7下的Redis集群教程,包括: 单机安装Redis Redis主从 Redis分片集群 1.单机安装Redis首先需要安装Redis所需要的依赖: 1yum install -y gcc tcl 然后将Redis安装包上传到虚拟机的任意目录: 例如,我放到了/tmp目录: 解压缩: 1tar -xvf redis-6.2.4.tar.gz 解压后: 进入redis目录: 1cd redis-6.2.4 运行编译命令: 1make && make install 如果没有出错,应该就安装成功了。 然后修改redis.conf文件中的一些配置: 1234# 绑定地址,默认是127.0.0.1,会导致只能在本地访问。修改为0.0.0.0则可以在任意IP访问bind 0.0.0.0# 数据库数量,设置为1databases 1 启动Redis: 1redis-server redis.conf 停止redis服务: 1redis-cli shutdown 2.Redis主从集群2.1.集群结构我们搭建的主从集...
BigKey 处理方案
Bigkey 是指当 Redis 的字符串类型过大,非字符串类型元素过多。 危害| 内存空间不均匀(平衡)例如在 Redis Cluster 中,大量 bigkey 落在其中一个 Redis 节点上,会造成该节点的内存空间使用率比其他节点高,造成内存空间使用不均匀。 | 请求倾斜对于非字符串类型的 bigkey 的请求,由于其元素较多,很可能对于这些元素的请求都落在 Redis cluster 的同一个节点上,造成请求不均匀,压力过大。 | 超时阻塞由于 Redis 单线程的特性,操作 bigkey 比较耗时,也就意味着阻塞 Redis 可能性增大。这就是造成生产事故的罪魁祸首!导致 Redis 间歇性卡死、影响线上正常下单! | 网络拥塞每次获取 bigkey 产生的网络流量较大,假设一个 bigkey 为 1MB,每秒访问量为 1000,那么每秒产生 1000MB 的流量,对于普通的千兆网卡(按照字节算是 128MB/s)的服务器来说简直是灭顶之灾。 而且一般服务器会采用单机多实例的方式来部署,也就是说一个 bigkey 可能会对其他实例造成影响,其后果不堪设想...
Redis 原理
Redis原理篇1. Redis 数据结构1.1 动态字符串(SDS)我们都知道 Redis 中保存的 Key 是字符串,value 往往是字符串或者字符串的集合。可见字符串是 Redis 中最常用的一种数据结构。 不过 Redis 没有直接使用 C 语言中的字符串,因为 C 语言字符串存在很多问题: 获取字符串长度需要通过运算 非二进制安全 不可修改 Redis 构建了一种新的字符串结构,称为简单动态字符串(Simple Dynamic String),简称 SDS。例如,我们执行命令: 那么 Redis 将在底层创建两个 SDS,其中一个是包含 "name" 的 SDS,另一个是包含 "虎哥" 的 SDS。 Redis 是 C 语言实现的,其中 SDS 是一个结构体,源码如下: 例如,一个包含字符串“name”的sds结构如下: SDS 之所以叫做动态字符串,是因为它具备动态扩容的能力,例如一个内容为 "hi" 的 SDS: 假如我们要给 SDS 追加一段字符串 ",Amy",...
Redis 基础
Redis 快速入门1. 初识 RedisRedis是一种键值型的NoSql数据库,这里有两个关键字: 键值型 NoSql 其中键值型,是指 Redis 中存储的数据都是以 key、value 对的形式存储,而 value 的形式多种多样,可以是字符串、数值、甚至 JSON: 而 NoSQL 则是相对于传统关系型数据库而言,有很大差异的一种数据库。 1.1. 认识 NoSQLNoSQL 可以翻译做 Not Only SQL(不仅仅是 SQL),或者是 No SQL(非 SQL 的)数据库。是相对于传统关系型数据库而言,有很大差异的一种特殊的数据库,因此也称之为非关系型数据库。 1.1.1.结构化与非结构化传统关系型数据库是结构化数据,每一张表都有严格的约束信息:字段名、字段数据类型、字段约束等等信息,插入的数据必须遵守这些约束: 而NoSql则对数据库格式没有严格约束,往往形式松散,自由。 可以是键值型: 也可以是文档型: 甚至可以是图格式: 1.1.2.关联和非关联传统数据库的表与表之间往往存在关联,例如外键: 而非关系型数据...
Redis 数据迁移
需求需要将一个redis实例中(或是具体到某一个db)的部分keys,转移到另一个redis实例(或是具体到某一个db) 使用Redis自身支持的指令源实例与目标实例版本相同使用dump命令12345678910111213141516171819202122232425262728293031#!/bin/bash#redis 源ipsrc_ip=127.0.0.1#redis 源portsrc_port=6392#redis 源密码src_auth=#redis 源库src_db=#redis 目的ipdest_ip=127.0.0.1#redis 目的portdest_port=6393#redis 目的密码dest_auth=#redis 目的库dest_db=#要迁移的key前缀key_prefix=testi=1redis-cli -h $src_ip -p $src_port -a $src_auth -n $src_db keys "${key_prefix}*" | while read keydo redis-cl...
保证缓存与数据库数据一致性
更新数据时的操作主要分为两种:写时更新和读时更新 什么是写时更新和读时更新写时更新:当我们往数据库写数据的时候我们去更新缓存,包括先更新缓存再更新数据库和先更新数据库再更新缓存。写时删除,读时更新:当我们往数据库写数据的时候我们直接删除缓存,然后其他请求读数据的时候更新缓存。包括先删除缓存再更新数据和先更新数据库再删除缓存。 缓存更新到底是读更新好还是写更新好?对比写时更新方案,读时更新更好,为什么? 如果你是一个写数据库场景比较多,而读数据场景比较少的业务需求,采用这种方案就会导致,数据压根还没读到,缓存就被频繁的更新,浪费性能。 同时有请求A和请求B进行更新操作,那么会出现 (1)线程A更新了数据库 (2)线程B更新了数据库 (3)线程B更新了缓存 (4)线程A更新了缓存。这就出现请求A更新缓存应该比请求B更新缓存早才对,但是因为网络等原因,B却比A更早更新了缓存。这就导致了脏数据,因此不考虑。 那么也就是说,如果是写更新的话,不管从性能的角度还是从线程安全的角度来说这种方案都不好。 读时更新有没有什么问题?前面我们说了,如果是写更新,会有效率和线程安全性的问题,那如...
Redis 最佳实践
Redis高级篇之最佳实践今日内容 Redis键值设计 批处理优化 服务端优化 集群最佳实践 1、Redis键值设计1.1、优雅的key结构Redis的Key虽然可以自定义,但最好遵循下面的几个最佳实践约定: 遵循基本格式:[业务名称]:[数据名]:[id] 长度不超过44字节 不包含特殊字符 例如:我们的登录业务,保存用户信息,其key可以设计成如下格式: 这样设计的好处: 可读性强 避免key冲突 方便管理 更节省内存: key是string类型,底层编码包含int、embstr和raw三种。embstr在小于44字节使用,采用连续内存空间,内存占用更小。当字节数大于44字节时,会转为raw模式存储,在raw模式下,内存空间不是连续的,而是采用一个指针指向了另外一段内存空间,在这段空间里存储SDS内容,这样空间不连续,访问的时候性能也就会收到影响,还有可能产生内存碎片 1.2、拒绝BigKeyBigKey通常以Key的大小和Key中成员的数量来综合判定,例如: Key本身的数据量过大:一个String类型的Key,它的值为5 MB Key中的成员数过...
