【RabbitMQ】一文详解消息可靠性
目录:
1.前言
2.生产者
3.数据持久化
4.消费者
5.死信队列
1.前言
RabbitMQ 是一款高性能、高可靠性的消息中间件,广泛应用于分布式系统中。它允许系统中的各个模块进行异步通信,提供了高度的灵活性和可伸缩性。然而,这种通信模式也带来了一些挑战,其中最重要的之一是确保消息的可靠性。
影响消息可靠性的因素主要有以下几点:
- 发送消息时连接RabbitMQ失败
- 发送时丢失:
- 生产者发送的消息未送达交换机;
- 消息到达交换机后未到达队列;
- MQ 宕机,队列中的消息会丢失;
- 消费者接收到消息后未消费就宕机了。
2.生产者
2.1.生产者重连机制
生产者发送消息时,出现了网络故障,导致与MQ的连接中断。为了解决这个问题,RabbitMQ提供的消息发送时的重连机制。即:当RabbitTemplate
与MQ连接超时后,多次重试。
在生产者yml文件添加配置开启重连机制
spring:rabbitmq:connection-timeout: 1s # 设置MQ的连接超时时间template:retry:enabled: true # 开启超时重试机制initial-interval: 1000ms # 失败后的初始等待时间multiplier: 1 # 失败后下次的等待时长倍数,下次等待时长 = initial-interval * multipliermax-attempts: 3 # 最大重试次数
当网络不稳定的时候,利用重试机制可以有效提高消息发送的成功率。但是RabbitMQ提供的重试机制是阻塞式的重试。 如果对于业务性能有要求,建议禁用重试机制。如果一定要使用,就需要合理配置等待时长和重试次数,或者使用异步线程来执行发送消息的代码
2.2.生产者确认机制
RabbitMQ的生产者确认机制(Publisher Confirm)是一种确保消息从生产者发送到MQ过程中不丢失的机制。当消息发送到 RabbitMQ 后,系统会返回一个结果给消息的发送者,表明消息的处理状态。这个结果有两种可能的值:
返回结果有两种方式:
- publisher-confirm(发送者确认)
- 消息成功投递到交换机,返回ACK。
- 消息未投递到交换机,返回NACK。(可能是由于网络波动未能连接到RabbitMQ,可利用生产者重连机制解决)
- publisher-return(发送者回执)
- 消息投递到交换机了,但是没有路由到队列。返回ACK和路由失败原因。(这种问题一般是因为路由键设置错误,可以人为规避)
通过这种机制,生产者在发送消息后获取返回的回执结果,从而采取对应的策略,如消息重发或记录失败信息。
3.数据持久化
3.1.配置持久化
在默认情况下,RabbitMQ会将接收到的信息保存在内存中以降低消息收发的延迟。这样会导致两个问题
- RabbitMQ宕机,存在内存中的消息会丢失。
- 内存空间有限,当消费者故障或处理过慢时,会导致消息积压,引发MQ阻塞。
为了提升性能,默认情况下MQ的数据都是在内存存储的临时数据,重启后就会消失。RabbitMQ可以通过配置数据持久化,从而将消息保存在磁盘,包括:
- 交换机持久化(确保RabbitMQ重启后交换机仍然存在)
- 队列持久化(确保RabbitMQ重启后队列仍然存在)
- 消息持久化(确保RabbitMQ重启后队列中的消息仍然存在)
由于Spring会在创建队列时默认将交换机和队列设置为持久化,发送消息时也默认指定消息为持久化消息,因此不需要额外配置。
// 将消息指定为持久化消息
Message message = MessageBuilder.withBody("hello".getBytes(standardcharsets.UTF_8)).setDeliveryMode(MessageDeliveryMode.PERSISTENT).build();
// 给队列发送消息
rabbitTemplate.convertAndSend("simple.queue", message);
3.2.惰性队列
从RabbitMQ的3.6.0版本开始,就增加了Lazy Queue
的概念,也就是惰性队列。
在3.12版本后,所有队列都是Lazy Queue模式,无法更改。
惰性队列的特点如下:
-
接收到消息后直接存入磁盘而非内存(内存中只保留最近的消息,默认2048条)
-
消费者要消费消息时才会从磁盘中读取并加载到内存
-
支持数百万条的消息存储
对于低于3.12版本的情况,可以使用注解的arguments来指定
@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "grade.queue", durable = "true"),exchange = @Exchange(name = "intel.topic", type = ExchangeTypes.TOPIC),key = "intel.grade",arguments = @Argument(name = "x-queue-mode", value = "lazy")))
3.3.为什么需要数据持久化?
数据持久化在 RabbitMQ 中有以下重要作用:
队列和交换机的持久化:
- 防止重启后丢失:将队列和交换机设置为持久化,可以防止 RabbitMQ 服务器重启后丢失这些队列和交换机,确保它们的存在和绑定关系保持不变。
消息的持久化:
- 安全性:
- 防止数据丢失:消息持久化后,可以防止 RabbitMQ 服务器重启或宕机时数据丢失,方便数据恢复,保证消息的可靠性和耐久性。
- 性能:
- 内存管理:未持久化的临时消息默认存储在内存中。内存空间有限,大量消息涌入时会导致内存占满,系统需要进行
page out
操作将消息写入磁盘。频繁的page out
操作会严重影响性能。 - 预防内存溢出:通过持久化消息,可以缓解内存压力,防止因内存溢出导致的系统性能问题和崩溃。
- 内存管理:未持久化的临时消息默认存储在内存中。内存空间有限,大量消息涌入时会导致内存占满,系统需要进行
4.消费者
4.1.消费者确认机制
为了确认消费者是否正确处理了消息,RabbitMQ提供了消费者确认机制。当消费者处理消息后,会返回回执信息给RabbitMQ。回执有三种值:
- ack:消息处理成功,RabbitMQ从队列中删除消息。
- nack:消息处理失败,RabbitMQ需要再次投递消息。
- reject:消息处理失败并拒绝该消息,RabbitMQ从队列中删除消息。
在SpringBoot项目中,我们可以通过配置文件选择回执信息的处理方式,一共有三种处理方式:
-
none:不处理。RabbitMQ 假定消费者获取消息后会一定会成功处理,因此消息投递后立即返回
ack
,将消息从队列中删除。 -
manual:手动模式。需要在业务代码结束后,调用SpringAMQP提供的API发送
ack
或reject
,存在代码侵入问题,但比较灵活。 -
auto:自动模式。SpringAMQP利用AOP对我们的消息处理逻辑进行了环绕增强,返回结果如下:
-
如果消费者正常处理消息,自动返回
ack
并删除队列的消息。 -
如果消费者消息处理失败,自动返回
nack
并重新向消费者投递消息。 -
如果消息校验异常,自动返回
reject
并删除队列中的消息。
-
注意: 手动模式返回回执消息时通常需要显式指定
requeue
参数,当requeue=true
时,表明消息需要重新入队;当requeue=false
时,RabbitMQ将从队列删除消息。
spring:rabbitmq:listener:simple:prefetch: 1acknowledge-mode: auto # none,关闭ack;manual,手动ack;auto,自动 ack
4.2.消息失败重试机制
当消费者出现异常后,消息会不断requeue(重新入队)到队列,再重新发送给消费者,然后再次异常,再次requeue无限循环,导致mq的消息处理飙升,带来不必要的压力。
可以通过设置yml文件开启失败重试机制,在消息异常时利用本地重试,而不是无限制的进行requeue操作。
spring:rabbitmq:listener:simple:retry:enabled: true # 开启消费者失败重试initial-interval: 1000 # 初识的失败等待时长为1秒multiplier: 1 # 失败的等待时长倍数,下次等待时长 = multiplier * last-intervalmax-attempts: 3 # 最大重试次数stateless: true # true无状态;false 有状态。如果业务中包含事务,这里改为 false
4.3.消息失败处理策略
在开启重试模式后,重试次数耗尽,如果消息依然失败,则需要有 MessageRecoverer 接口来处理,它包含三种不同的实现:
- RejectAndDontRequeueRecoverer:重试次数耗尽后,直接
reject
,丢弃消息,这是默认采取的方式; - ImmediateRequeueMessageRecoverer:重试次数耗尽后,返回
nack
,消息重新入队; - RepublishMessageRecoverer:重试耗尽后,将失败消息投递到指定的交换机。
5.死信队列
尽管通过以上设置可以确保消息在生产者、消息队列和消费者之间的传递过程中不会丢失,但在某些情况下,消费者仍可能无法成功处理消息(如消息重试次数耗尽后仍无法被消费)。这时候,我们需要一个机制来妥善处理这些无法被正常消费的消息。死信队列便是用于解决这一问题的兜底机制。
5.1.死信
当一个队列中的消息满足下列情况之一时,可以成为死信(dead letter):
- 消息被拒绝: 当消费者明确拒绝一个消息并且设置不再重新入队(requeue=false)时,这个消息会被标记为死信。
- 消息过期: 每个消息或队列可以设置一个TTL(Time-To-Live),即消息的存活时间。如果消息在队列中停留的时间超过了这个TTL,消息会被认为过期,并被转移到死信队列。
- 队列达到最大长度: 如果队列设置了最大长度并且达到了这个限制,那么新进入的消息会被转移到死信队列中。
5.2.创建死信队列
5.2.1.创建死信交换机和死信队列
正常使用注解,创建交换机和队列即可
@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "dead.queue", durable = "true",arguments = @Argument(name = "x-queue-mode", value = "lazy")),exchange = @Exchange(name = "dead.exchange", type = ExchangeTypes.TOPIC),key = "dead.key"
))
public void deadLetterQueue(String msg) {System.out.println("您的消息已经死亡:" + msg);
}
5.2.2.绑定死信交换机
如果队列通过dead-letter-exchange
属性指定了一个交换机,那么该队列中的死信就会投递到这个交换机中。这个交换机称为死信交换机(Dead Letter Exchange,简称DLX)
可以通过@Argument
注解指定死信交互机和路由键,如下。
@RabbitListener(bindings = @QueueBinding(value = @Queue(name = "simple.queue", durable = "true",arguments = {@Argument(name = "x-queue-mode", value = "lazy"),@Argument(name = "x-dead-letter-exchange", value = "dead.exchange"),@Argument(name = "x-dead-letter-routing-key", value = "dead.key")}),exchange = @Exchange(name = "simple.topic",type = ExchangeTypes.TOPIC),key = "simple.key"))
相关文章:
![](https://i-blog.csdnimg.cn/direct/11158fac96564b9ab318056374b3ff09.png#pic_center)
【RabbitMQ】一文详解消息可靠性
目录: 1.前言 2.生产者 3.数据持久化 4.消费者 5.死信队列 1.前言 RabbitMQ 是一款高性能、高可靠性的消息中间件,广泛应用于分布式系统中。它允许系统中的各个模块进行异步通信,提供了高度的灵活性和可伸缩性。然而,这种通…...
![](https://www.ngui.cc/images/no-images.jpg)
RuntimeError: Unexpected error from cudaGetDeviceCount
RuntimeError: Unexpected error from cudaGetDeviceCount 0. 引言1. 临时解决方法 0. 引言 使用 vllm-0.4.2 部署时,多卡正常运行。升级到 vllm-0.5.1 时,报错如下: (VllmWorkerProcess pid30692) WARNING 07-12 08:16:22 utils.py:562] U…...
![](https://www.ngui.cc/images/no-images.jpg)
uboot学习:(一)基础认知
目录 uboot是一个裸机程序(bootloader) 作用 要运行linux系统时,如何从外置的flash拷贝到DDR中,才能启动 uboot使用步骤 步骤1中的命令例子 注意 uboot源码获取方法 uboot是一个裸机程序(bootloader)…...
![](https://www.ngui.cc/images/no-images.jpg)
每天一个数据分析题(四百二十六)- 总体方差
为了比较两个总体方差,我们通常检验两个总体的() A. 方差差 B. 方差比 C. 方差乘积 D. 方差和 数据分析认证考试介绍:点击进入 题目来源于CDA模拟题库 点击此处获取答案 数据分析专项练习题库 内容涵盖Python,SQL,统计学&a…...
![](https://i-blog.csdnimg.cn/direct/0b4ee8b4271747679a4cf4268bd422eb.png#pic_center)
【C++】设计一套基于C++与C#的视频播放软件
在开发一款集视频播放与丰富交互功能于一体的软件时,结合C的高性能与C#在界面开发上的便捷性,是一个高效且实用的选择。以下,我们将概述这样一个系统的架构设计、关键技术点以及各功能模块的详细实现思路。 一、系统架构设计 1. 架构概览 …...
![](https://www.ngui.cc/images/no-images.jpg)
数学建模中的辅助变量、中间变量、指示变量
在数学建模中,除了决策变量外,还有一些其他类型的变量,如中间变量、辅助变量和指示变量。每种变量在模型中都有特定的用途和意义。以下是对这些变量的详细解释: 1. 决策变量(Decision Variables) 定义&am…...
![](https://www.ngui.cc/images/no-images.jpg)
python的seek()和tell()
seek() seek() 是用来在文件中移动指针位置的方法。它的作用是将文件内部的当前位置设置为指定的位置。 seek(offset, whence) 参数说明 offset: 这是一个整数值,表示相对于起始位置的偏移量。如果是正数,表示向文件末尾方向移动;如果是负…...
![](https://i-blog.csdnimg.cn/direct/c0fe79faa4b44adc9068cd1e30f204fa.png)
Go泛型详解
引子 如果我们要写一个函数分别比较2个整数和浮点数的大小,我们就要写2个函数。如下: func Min(x, y float64) float64 {if x < y {return x}return y }func MinInt(x, y int) int {if x < y {return x}return y }2个函数,除了数据类…...
![](https://i-blog.csdnimg.cn/direct/01d0c42965a8459d8613664f1da4da3f.png)
【每日一练】python之sum()求和函数实例讲解
在Python中, sum()是一个内置函数,用于计算可迭代对象(如列表、元组等)中所有元素的总和。如下实例: """ 收入支出统计小程序 知识点:用户输入获取列表元素添加sum()函数,统计作用 "&…...
![](https://i-blog.csdnimg.cn/direct/b90d7b9e5972442fbad7e235b0ea988b.png)
打造智慧校园德育管理,提升学生操行基础分
智慧校园的德育管理系统内嵌的操行基础分功能,是对学生日常行为规范和道德素养进行量化评估的一个创新实践。该功能通过将抽象的道德品质转化为具体可量化的指标,如遵守纪律、尊师重道、团结协作、爱护环境及参与集体活动的积极性等,为每个学…...
![](https://i-blog.csdnimg.cn/direct/4ce1ad0e50d148269a561892232a728c.png)
自定义函数---随机数系列函数
大家有没有发现平常在写随机数的时候,需要引入很多的头文件,然后还需要用一些复杂的函数,大家可能不太习惯,于是我就制作了一个头文件 // random_number.h #ifndef RANDOM_NUMBER_H // 预处理指令,防止头文件被重复包含…...
![](https://img-blog.csdnimg.cn/img_convert/9c02eecbf4079f67318b00e81f0b6c85.png)
一文了解5G新通话技术演进与业务模型
5G新通话简介 5G新通话,也被称为VoNR,是基于R16及后续协议产生的一种增强型语音通话业务。 它在IMS网络里新增数据通道(Data Channel),承载通话时的文本、图片、涂鸦、菜单等信息。它能在传统话音业务基础上提供更多服…...
![](https://www.ngui.cc/images/no-images.jpg)
视频使用操作说明书-T80002系列视频编码器如何对接海康NVR硬盘录像机,包括T80002系列高清HDMI编码器、4K超高清HDMI编码器
视频使用操作说明书-T80002系列视频编码器如何对接海康NVR硬盘录像机,包括T80002系列高清HDMI编码器、4K超高清HDMI编码器。 视频使用操作说明书-T80002系列视频编码器如何对接海康NVR硬盘录像机,包括T80002系列高清HDMI编码器、4K超高清HDMI编码器 同三…...
![](https://www.ngui.cc/images/no-images.jpg)
el-input-number计数器change事件校验数据,改变绑定数据值后change方法失效问题的原因及解决方法
在change事件中如果对el-input-number绑定的数据进行更改,会出现change事件失效的问题 试过:this.$set()及赋值等方法,都无法解决 解决方法:用$nextTick函数对绑定值进行更改( this.$nextTick(() > { this.绑定…...
![](https://i-blog.csdnimg.cn/direct/2f410e39246a4bbf97ef390b5cc0a695.png)
将vue项目整合到springboot项目中并在阿里云上运行
第一步,使用springboot中的thymeleaf模板引擎 导入依赖 <!-- thymeleaf 模板 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency> 在r…...
![](https://www.ngui.cc/images/no-images.jpg)
AC修炼计划(AtCoder Regular Contest 179)A~C
A - Partition A题传送门 这道题不难发现,如果数字最终的和大于等于K,我们可以把这个原数列从大到小排序,得到最终答案。 如果和小于K,则从小到大排序,同时验证是否符合要求。 #pragma GCC optimize(3) //O2优化开启…...
![](https://i-blog.csdnimg.cn/direct/5ace765f04354246aaab9f135b2a06c9.png)
开发编码规范笔记
前言 (1)该博客仅用于个人笔记 格式转换 (1)查看是 LF 行尾还是CRLF 行尾。 # 单个文件,\n 表示 LF 行尾。\r\n 表示 CRLF 行尾。 hexdump -c <yourfile> # 单个文件,$ 表示 LF 行尾。^M$ 表示 CRLF …...
![](https://www.ngui.cc/images/no-images.jpg)
spring boot easyexcel
1.pom <!-- easyexcel 依赖 --><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.1.1</version></dependency><dependency><groupId>org.projectlombok</group…...
![](https://i-blog.csdnimg.cn/direct/81c733b4c8d9477dbd8307c424c842d6.png)
Docker 部署 ShardingSphere-Proxy 数据库中间件
文章目录 Github官网文档ShardingSphere-Proxymysql-connector-java 驱动下载conf 配置global.yamldatabase-sharding.yamldatabase-readwrite-splitting.yamldockerdocker-compose.yml Apache ShardingSphere 是一款分布式的数据库生态系统, 可以将任意数据库转换为…...
![](https://i-blog.csdnimg.cn/direct/11962bb04e474ae7b135e2d8c54422b3.png)
Qt常用快捷键
Qt中的常用快捷键 F1查看帮助F2快速到变量声明 从cpp→hShift F2 函数的声明和定义之间快速切换 ;选中函数名 ,从h→cppF4在 cpp 和 h 文件切换 Shift F4在cpp/h文件与 界面文件中切换Ctrl /注释当前行 或者选中的区域Ctrl I自动缩进当前…...
![](https://www.ngui.cc/images/no-images.jpg)
关于RiboSeq分析流程的总结
最近关注了一下RiboSeq的分析方法,方法挺多的,但是无论哪种软件,都会存在或多或少的问题,一点问题不存在的软件不存在,问题的原因出在,1.有的脚本是用python2编写的,目前python2已经不能用了 2.…...
![](https://i-blog.csdnimg.cn/direct/4f5bf040138f480c8c7e1d07d62da0c1.png)
NLP任务:情感分析、看图说话
我可不向其他博主那样拖泥带水,我有代码就直接贴在文章里,或者放到gitee供你们参考下载,虽然写的不咋滴,废话少说,上代码。 gitee码云地址: 卢东艺/pytorch_cv_nlp - 码云 - 开源中国 (gitee.com)https:/…...
![](https://i-blog.csdnimg.cn/direct/723a2a6e55a849deb47392889ed35a5b.png)
Linux桌面溯源
X窗口系统(X Window System) Linux起源于X窗口系统(X Window System),亦即常说的X11,因其版本止于11之故。 X窗口系统(X Window System,也常称为X11或X)是一种以位图方式显示的软件窗口系统。…...
![](https://i-blog.csdnimg.cn/direct/ceefa3555fda49e9b95d4bbe758fcb66.png)
深入Linux:权限管理与常用命令详解
文章目录 ❤️Linux常用指令🩷zip/unzip指令🩷tar指令🩷bc指令🩷uname指令🩷shutdown指令 ❤️shell命令以及原理❤️什么是 Shell 命令❤️Linux权限管理的概念❤️Linux权限管理🩷文件访问者的分类&#…...
![](https://www.ngui.cc/images/no-images.jpg)
Mojo 编程语言:AI开发者的新宠儿
Mojo(Meta Object Oriented programming for Java Objects)是一种面向对象的编程语言,旨在简化和加速Java应用程序的开发过程。作为近年来新兴的编程语言,Mojo因其与Java的紧密集成以及AI开发领域的应用潜力而逐渐成为AI开发者的新…...
![](https://www.ngui.cc/images/no-images.jpg)
ARM/Linux嵌入式面经(十):极氪
开篇强调两个事情: pdf文件都在百度网盘群:911289806一定要把超链接里面的文章看了,那都是为了你们写的。老板!!!现在多学点,涨个2k工资,真的很值得。要不吃学习的苦,要不吃生活的苦。 1. 自我介绍 专开新篇,等我! 2. 项目介绍,提问 专开新篇,等我! 3. SPI通信和…...
![](https://img-blog.csdnimg.cn/img_convert/20a71d897073249ee6c06412eeb78101.png)
【PVE】新增2.5G网卡作为主网卡暨iperf测速流程
【PVE】新增2.5G网卡作为主网卡暨iperf测速流程 新增网卡 新增网卡的首先当然需要关闭PVE母机,把新网卡插上,我用淘宝遥现金搞了个红包,花了26元买了块SSU的2.5G网卡。说实话这个价位连散热片都没有,确实挺丐的。稍后测下速度看…...
![](https://i-blog.csdnimg.cn/direct/c02f28efc7ac4858bb2d3411378975d0.png)
数学建模美赛入门
数学建模需要的学科知识 高等数学线性代数 有很多算法的掌握是需要高等数学和线代的相关知识 如:灰色预测模型需要微积分知识;神经网络需要用到导数知识;图论和层次分析法等都需要用到矩阵计算的相关知识等; 概率论与数理统计&am…...
![](https://www.ngui.cc/images/no-images.jpg)
两段序列帧动画播放,在ios机型上出现闪屏
使用场景:两段序列帧动画连接播放,先播放第一段播一次,再播放第二段,第二段循环播放,在ios机型上出现动画闪动,播放不正常。 错误的写法:把每一段序列帧动画单独写在了定义的动画里 .gacha-bg…...
![](https://i-blog.csdnimg.cn/direct/d577686cfe594e6b969543029c402cee.png)
【C++深度探索】全面解析多态性机制(二)
🔥 个人主页:大耳朵土土垚 🔥 所属专栏:C从入门至进阶 这里将会不定期更新有关C/C的内容,欢迎大家点赞,收藏,评论🥳🥳🎉🎉🎉 前言 我…...
![](/images/no-images.jpg)
wordpress主题 her/嘉兴优化公司
一.yum源理解 yum源仓库的地址 在/etc/yum.repos.d/,并且只能读出第一层的repo文件 yum仓库的文件都是以.repo结尾的 二.下载阿里云的.repo仓库文件 ,放到/etc/yum.repos.d/ 备份原本的仓库文件 cd /etc/yum.repos.d/ mkdir allbak mv ./* allbak #此…...
![](https://img-blog.csdnimg.cn/20190701135136246.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L01yc19jaGVucw==,size_16,color_FFFFFF,t_70)
网站建设的一般过程/站长之家网站排名
Java基础系列(基础):搞清楚Java异常机制! 前言 今天博主将为大家分享:Java基础系列(基础):搞清楚Java异常机制!不喜勿喷,如有异议欢迎讨论! 一:异…...
![](/images/no-images.jpg)
大连网站建设怎么做/百度推广登录平台
建議在流覽器中使用Less僅用於開發,或者當您需要動態編譯較少的代碼並且無法做到這一點。這是因為less.js是一個大型的JavaScript檔,並且在用戶可以看到該頁面意味著用戶的延遲之前編譯Less。另外,考慮到移動設備編譯速度會更慢。對於開發考慮…...
![](https://img-blog.csdnimg.cn/816bf225fccb4db2aee10a62f6b1b21f.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA55-l5b-D5a6d6LSd,size_20,color_FFFFFF,t_70,g_se,x_16)
长沙市芙蓉区关于疫情最新消息/搜索引擎推广seo
目录 一、前言 二、安装教程 1.打开下载链接 2.配置插件 三、使用教程 1.页面介绍 2.功能布局 四、脚本功能兼容油猴脚本安装使用 1.安装油猴脚本 2.油猴脚本使用教程 五、超神的脚本推荐 1.Github 增强 - 高速下载 2.右键在新标签中打开图片时显示最优化图像质量…...
![](https://img-blog.csdnimg.cn/img_convert/5f099ca0d39eeee2d3fbf1c9a11c34ac.gif)
wordpress图片lazyload/排行榜
手把手教你打造迷蒙漂亮的闪烁霓虹灯效果。教程详尽易懂,光影得当,作为GIF效果的入门教程非常不错,背景图素材(另存即可):霓虹灯一般只在夜晚工作,所以这个场景显然太亮了。我用色阶工具把它变暗点。再给一点冷色系。O…...
![](https://img-blog.csdnimg.cn/img_convert/c1bad8f83bceb7d1308f530e78028806.png)
政府网站建设简报/深圳优化怎么做搜索
在使用Java NIO时,会经常和ByteBuffer打交道(吐槽下,每次手动flip切换读写模式太不友好)。在空Buffer创建时,有两种方式:ByteBuffer.allocateDirect(capacity)ByteBuffer.allocate(capacity)那么这两种Buffer的分配又有什么不一样…...