Redis 实现分布式锁
单实例条件下的分布式锁
-- 加锁操作
-- KEYS[1]: 锁的键(lock_key)
-- ARGV[1]: 当前客户端的标识(client_id)
-- ARGV[2]: 锁的过期时间(毫秒)if (redis.call('EXISTS', KEYS[1]) == 0) then-- 如果锁不存在,则进行加锁redis.call('SET', KEYS[1], ARGV[1])redis.call('PEXPIRE', KEYS[1], ARGV[2])return 1
elseif (redis.call('GET', KEYS[1]) == ARGV[1]) then-- 如果锁已存在且是当前客户端持有的,则续期redis.call('PEXPIRE', KEYS[1], ARGV[2])return 1
else-- 如果锁已存在且不是当前客户端持有的,返回失败return 0
end
-- 解锁操作
-- KEYS[1]: 锁的键(lock_key)
-- ARGV[1]: 当前客户端的标识(client_id)if (redis.call('GET', KEYS[1]) == ARGV[1]) then-- 如果当前客户端持有锁,则解锁redis.call('DEL', KEYS[1])return 1
else-- 如果不是当前客户端持有锁,返回失败return 0
end
使用 Redisson 执行 Lua 脚本
@Service
public class RedisLockService {@Autowiredprivate RedissonClient redissonClient;// 加锁操作public boolean lock(String lockKey, String clientId, long expireTime) {String script ="if (redis.call('EXISTS', KEYS[1]) == 0) then " +" redis.call('SET', KEYS[1], ARGV[1]); " +" redis.call('PEXPIRE', KEYS[1], ARGV[2]); " +" return 1; " +"elseif (redis.call('GET', KEYS[1]) == ARGV[1]) then " +" redis.call('PEXPIRE', KEYS[1], ARGV[2]); " +" return 1; " +"else " +" return 0; " +"end";Long result = (Long) redissonClient.getScript().eval(RScript.Mode.READ_WRITE,script,RScript.ReturnType.INTEGER,java.util.Collections.singletonList(lockKey),clientId,String.valueOf(expireTime));return result != null && result == 1;}// 解锁操作public boolean unlock(String lockKey, String clientId) {String script ="if (redis.call('GET', KEYS[1]) == ARGV[1]) then " +" redis.call('DEL', KEYS[1]); " +" return 1; " +"else " +" return 0; " +"end";Long result = (Long) redissonClient.getScript().eval(RScript.Mode.READ_WRITE,script,RScript.ReturnType.INTEGER,java.util.Collections.singletonList(lockKey),clientId);return result != null && result == 1;}
}
使用 lua 脚本实现可重入分布式锁
加锁脚本需要检测当前锁的持有者是否是同一个客户端。如果是同一个客户端,则增加计数器,否则返回失败。
-- 加锁操作
-- KEYS[1]: 锁的键(lock_key)
-- ARGV[1]: 当前客户端的标识(client_id)
-- ARGV[2]: 锁的过期时间(毫秒)-- 检查锁的持有者
local lockOwner = redis.call('HGET', KEYS[1], 'owner')
if lockOwner == false then-- 如果锁不存在,则初始化锁的持有者和计数器redis.call('HSET', KEYS[1], 'owner', ARGV[1])redis.call('HSET', KEYS[1], 'count', 1)redis.call('PEXPIRE', KEYS[1], ARGV[2])return 1
elseif lockOwner == ARGV[1] then-- 如果锁已存在且是当前客户端持有的,则增加计数器local count = redis.call('HINCRBY', KEYS[1], 'count', 1)redis.call('PEXPIRE', KEYS[1], ARGV[2])return count
else-- 如果锁已存在且不是当前客户端持有的,返回失败return 0
end
解锁脚本需要检测当前锁的持有者是否是当前客户端。如果是,则减少计数器,当计数器减到 0 时,才释放锁。
-- 解锁操作
-- KEYS[1]: 锁的键(lock_key)
-- ARGV[1]: 当前客户端的标识(client_id)-- 检查锁的持有者
local lockOwner = redis.call('HGET', KEYS[1], 'owner')
if lockOwner == ARGV[1] then-- 如果是当前客户端持有锁,则减少计数器local count = redis.call('HINCRBY', KEYS[1], 'count', -1)if count == 0 then-- 如果计数器为 0,则删除锁redis.call('DEL', KEYS[1])else-- 如果计数器不为 0,则更新过期时间redis.call('PEXPIRE', KEYS[1], ARGV[2])endreturn count
else-- 如果不是当前客户端持有锁,返回失败return -1
end
使用 Redisson 执行 Lua 脚本
@Service
public class ReentrantLockService {@Autowiredprivate RedissonClient redissonClient;// 加锁操作public boolean lock(String lockKey, String clientId, long expireTime) {String script ="local lockOwner = redis.call('HGET', KEYS[1], 'owner') " +"if lockOwner == false then " +" redis.call('HSET', KEYS[1], 'owner', ARGV[1]) " +" redis.call('HSET', KEYS[1], 'count', 1) " +" redis.call('PEXPIRE', KEYS[1], ARGV[2]) " +" return 1 " +"elseif lockOwner == ARGV[1] then " +" local count = redis.call('HINCRBY', KEYS[1], 'count', 1) " +" redis.call('PEXPIRE', KEYS[1], ARGV[2]) " +" return count " +"else " +" return 0 " +"end";Long result = (Long) redissonClient.getScript().eval(RScript.Mode.READ_WRITE,script,RScript.ReturnType.INTEGER,java.util.Collections.singletonList(lockKey),clientId,String.valueOf(expireTime));return result != null && result > 0;}// 解锁操作public boolean unlock(String lockKey, String clientId, long expireTime) {String script ="local lockOwner = redis.call('HGET', KEYS[1], 'owner') " +"if lockOwner == ARGV[1] then " +" local count = redis.call('HINCRBY', KEYS[1], 'count', -1) " +" if count == 0 then " +" redis.call('DEL', KEYS[1]) " +" else " +" redis.call('PEXPIRE', KEYS[1], ARGV[2]) " +" end " +" return count " +"else " +" return -1 " +"end";Long result = (Long) redissonClient.getScript().eval(RScript.Mode.READ_WRITE,script,RScript.ReturnType.INTEGER,java.util.Collections.singletonList(lockKey),clientId,String.valueOf(expireTime));return result != null && result >= 0;}
}
使用 Redisson 库实现分布式锁
@Configuration
public class RedissonConfig {@Beanpublic RedissonClient redissonClient() {Config config = new Config();config.useSingleServer().setAddress("redis://localhost:6379"); // Redis 单实例地址return Redisson.create(config);}
}
@Service
public class DistributedLockService {@Autowiredprivate RedissonClient redissonClient;/*** 加锁操作** @param lockKey 锁的键* @param leaseTime 锁的过期时间(秒)* @return 是否加锁成功*/public boolean lock(String lockKey, long leaseTime) {RLock lock = redissonClient.getLock(lockKey);try {// 尝试加锁,最多等待 10 秒,锁的租约时间为指定的 leaseTimereturn lock.tryLock(10, leaseTime, TimeUnit.SECONDS);} catch (InterruptedException e) {Thread.currentThread().interrupt();return false;}}/*** 解锁操作** @param lockKey 锁的键*/public void unlock(String lockKey) {RLock lock = redissonClient.getLock(lockKey);if (lock.isHeldByCurrentThread()) {lock.unlock();}}
}
-
使用 Redisson 非常方便,它自动处理了分布式锁的各种边缘情况,例如锁的过期时间、可重入性和网络分区问题。
-
RLock 默认是可重入锁,这意味着同一个客户端(同一线程)可以多次获取同一把锁,所以上面的代码也可以作为可重入锁的代码。
-
如果业务逻辑涉及多线程或长时间操作,Redisson 的内置锁机制能有效管理锁的状态并防止死锁。
- 在使用 Redis 设置分布式锁时,如果任务在锁的过期时间快到了但尚未完成,可以采取以下几种策略来处理:
- 设置合理的过期时间:在任务开始时,根据预估的处理时间合理设置锁的过期时间。如果任务的处理时间通常较长,可以考虑设置一个较长的过期时间,以减少续期的需要。
- 使用线程守护机制:在业务逻辑执行时,可以启动一个线程或使用定时器,在任务执行过程中,可以定期(如每隔一定时间)检查锁的状态,并在必要时延长锁的过期时间。这可以通过调用 PEXPIRE 命令实现。
- 使用 Redisson 加锁可以做到自动续期。
- 在使用 Redis 设置分布式锁时,如果任务在锁的过期时间快到了但尚未完成,可以采取以下几种策略来处理:
集群条件下的分布式锁
使用 Redisson 对 redis 集群进行加锁,具有以下特点:
- 高可靠性:Redisson 能够在 Redis 集群架构下使用主从复制模式,实现锁的高可靠性。
- 这里的高可靠性是限于同一个节点的主从节点范围内的,如果加锁的主从节点都挂了话,那么锁就没有了。
- 易用性:Redisson 封装了复杂的锁定机制,开发者只需要简单的 API 调用即可实现分布式锁。
- 内置支持:Redisson 具有内置的锁过期机制和防止死锁的机制,避免了由于异常导致的锁未释放问题。
- 可重入性:Redisson 对 Redis 集群添加的分布式锁是支持可重入性的。这意味着在同一个线程中,获取锁的线程可以多次获取同一个锁,而无需担心死锁或冲突。
- 这里可重入性的参考维度是客户端,而不是线程。
在 Redis 集群架构下,需要配置 Redisson 客户端连接 Redis 集群。可以在 Spring Boot 项目的配置文件中使用 application.yml 进行配置。
spring:redis:cluster:nodes:- 127.0.0.1:6379- 127.0.0.1:6380- 127.0.0.1:6381
redisson:config: |clusterServersConfig:idleConnectionTimeout: 10000connectTimeout: 10000timeout: 3000retryAttempts: 3retryInterval: 1500scanInterval: 2000nodeAddresses:- redis://127.0.0.1:6379- redis://127.0.0.1:6380- redis://127.0.0.1:6381password: nullsubscriptionsPerConnection: 5clientName: nullidleConnectionTimeout: 10000pingTimeout: 1000keepAlive: truetcpNoDelay: truednsMonitoringInterval: 5000
创建一个配置类,初始化 RedissonClient:
@Configuration
public class RedissonConfig {@Beanpublic RedissonClient redissonClient() {Config config = new Config();// 配置 Redis 集群节点config.useClusterServers().addNodeAddress("redis://127.0.0.1:6379", "redis://127.0.0.1:6380", "redis://127.0.0.1:6381").setScanInterval(2000) // 集群节点扫描间隔.setRetryAttempts(3) // 重试次数.setRetryInterval(1500) // 重试间隔.setConnectTimeout(10000) // 连接超时.setTimeout(3000); // 命令等待响应超时return Redisson.create(config);}
}
使用 Redisson 分布式锁
@Service
public class MyService {@Autowiredprivate RedissonClient redissonClient;public void doSomethingWithLock() {// 获取可重入锁RLock lock = redisson.getLock("myReentrantLock");try {// 尝试获取锁,等待最多 10 秒,锁定时间为 5 秒if (lock.tryLock(10, 5, TimeUnit.SECONDS)) {try {// 第一次加锁成功,执行业务逻辑System.out.println("Lock acquired for the first time!");// 再次获取同一把锁(可重入)lock.lock();System.out.println("Lock acquired again (reentrant)!");// 业务逻辑处理// ...} finally {// 释放锁(可重入锁的计数器递减)lock.unlock();System.out.println("Lock released once!");// 再次释放锁lock.unlock();System.out.println("Lock fully released!");}}} catch (InterruptedException e) {e.printStackTrace();}}
}
可以使用 Lua 脚本在 Redis 集群中实现分布式锁。Lua 脚本在 Redis 中是原子执行的,因此能够有效地确保分布式锁的原子性和一致性。通过 Lua 脚本,可以精确控制锁的获取和释放逻辑,从而避免在高并发环境下的竞态条件。
不过在 Redis 集群架构下,使用 Lua 脚本进行分布式锁需要特别注意一些事项,因为 Redis 集群的数据是分片存储的,每个键可能位于不同的分片节点上。这会导致以下几点挑战:
- Redis 集群不支持跨节点事务:在 Redis 集群模式下,如果 Lua 脚本涉及多个键,这些键必须位于同一个分片上才能保证 Lua 脚本的原子性执行。
- 哈希标签(Hash Tag)解决方案:为了确保多个键位于同一分片,可以使用 哈希标签。哈希标签是指在键名中使用 {} 包裹的部分,Redis 会对这个部分进行一致哈希计算,将具有相同哈希标签的键存储在同一个分片上。
Redis (单例或者集群)添加可重入性分布式锁时,参考维度通常是客户端,而不是线程。这是因为在 Redis 的上下文中,分布式锁是针对客户端的,而不是针对单个线程。
- 单线程模型:Redis 是单线程的,所有的命令在一个线程中处理。因此,Redis 处理的所有操作都是在一个事件循环中执行的。即使在多线程的应用程序中,所有对 Redis 的请求实际上是通过同一个客户端连接发送的。
- 客户端标识:在分布式环境中,锁的持有者通常是一个客户端,而不是单个线程。一个客户端可以有多个线程在操作,但 Redis 只关心哪个客户端持有锁。
- 锁的设计:在实现可重入锁时,需要一个机制来跟踪锁的持有者。这个持有者应该是客户端的标识符(例如 UUID 或其他唯一标识符),以便确保同一个客户端可以多次获取锁,而不会出现死锁。
- 多线程和多进程:如果一个客户端的多个线程或进程尝试获取同一个锁,可以通过使用相同的客户端标识符来实现可重入性。这种设计方式允许同一客户端的不同线程安全地获取和释放锁。
相关文章:
Redis 实现分布式锁
单实例条件下的分布式锁 -- 加锁操作 -- KEYS[1]: 锁的键(lock_key) -- ARGV[1]: 当前客户端的标识(client_id) -- ARGV[2]: 锁的过期时间(毫秒)if (redis.call(EXISTS, KEYS[1]) 0) then-- 如果锁不存在…...
Redis客户端(Jedis、RedisTemplate、Redisson)
1. 简介 Redis作为一个当下很火热的非关系型数据库,Java从业人员基本都离不开对Redis的使用。在Java程序中该数据库,需要借助于市面上的开源客户端,如Jedis、Spring Data Redis、Redisson,它们可以作为操作Redis非关系型数据库的桥…...
虚幻引擎内各个组件的关系
1. GameMode: 关系: GameMode 是游戏规则的制定者和管理者,GameState 则是游戏状态的记录者和同步者。GameMode 通常负责创建和初始化 GameState。 交互: GameMode 可以直接访问和修改 GameState 的属性,例如更新游戏分数、切换游戏阶段等。GameState 的变化会通过 GameMode …...
Python Flask Web框架快速入门
Flask 入门Demo Flask 开发环境搭建,执行如下指令: pip install flask# 第一节: Flask 快速入门from flask import Flask app Flask(__name__)app.route(/flask) def hello_flask():return Hello Flaskapp.run()核心代码剖析: 从flask包导…...
【java学习笔记】Set接口实现类-LinkedHashSet
一、LinkedHashSet的全面说明 (就是把数组不同位置的链表当成一个节点然后相连)...
阿里云ACP云计算模拟试题(附答案解析)
1、将基础设施作为服务的云计算服务类型是_____服务。 A.laas B.Paas C.SaaS D.Daas 答案:A 解析:基础设施即服务有时缩写为 IaaS,包含云 IT 的基本构建块,通常提供对联网功能、计算机(虚拟或专用硬件&#x…...
java 缓存篇2
缓存的部署方式 单机主从哨兵集群 特性主从(Master-Slave)哨兵(Sentinel)集群(Cluster)数据分片不支持不支持支持,基于 slot 进行水平分片高可用性部分支持(手动故障转移ÿ…...
12.11-12.12总结(约瑟夫问题 机器翻译 滑动窗口)
12.11 刷题 《算法竞赛》这本书看了很多了,但是题目没咋做,所以今天来刷一下题 P1996约瑟夫问题 还依稀记得大一的时候被约瑟夫支配的恐惧(哭),但是现在做就感觉很简单(虽然也敲了一会,今早感…...
Elasticsearch+Kibana+IK分词器+拼音分词器安装
目录 ES报错 Kibanaik分词器拼音分词器 安装都比较简单,可以参考这几篇博客 ES 如何在 Linux,MacOS 及 Windows 上进行安装 Elasticsearch 报错 ES启动报错error downloading geoip database [GeoLite2-ASN.mmdb] Kibana KIBANA的安装教程ÿ…...
2020 年“泰迪杯”数据分析职业技能大赛A 题教育平台的线上课程智能推荐策略
2020 年“泰迪杯”数据分析职业技能大赛A 题教育平台的线上课程智能推荐策略 完整代码请私聊 博主 一、 背景 近年来,随着互联网与通信技术的高速发展,学习资源的建设与共享呈现出新的发展趋势,各种网课、慕课、直播课等层出不穷,…...
运维面试题
1 deployment和statefulset区别 Kubernetes (k8s) 中的 Deployment 和 StatefulSet 是两种不同类型的控制器,用于管理应用的生命周期,但它们适用于不同的应用场景。以下是它们在存储、调度顺序和网络分配方面的区别: 存储 Deployment: 适用…...
计算机网络之网络层超详细讲解
个人主页:C忠实粉丝 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C忠实粉丝 原创 计算机网络之网络层超详细讲解 收录于专栏【计算机网络】 本专栏旨在分享学习计算机网络的一点学习笔记,欢迎大家在评论区交流讨论💌 …...
Windows桌面系统管理2:VMware Workstation使用和管理
Windows桌面系统管理0:总目录-CSDN博客 Windows桌面系统管理1:计算机硬件组成及组装-CSDN博客 Windows桌面系统管理2:VMware Workstation使用和管理 Windows桌面系统管理3:Windows 10操作系统部署与使用-CSDN博客 Windows桌面系统管理4:Windows 10操作系统运维管理-…...
深入理解 CSS 文本换行: overflow-wrap 和 word-break
前言 正常情况下,在固定宽度的盒子中的中文会自动换行。但是,当遇到非常长的英文单词或者很长的 URL 时,文本可能就不会自动换行,而会溢出所在容器。幸运的是,CSS 为我们提供了一些和文本换行相关的属性;今…...
【Linux】Ubuntu:安装系统后配置
hostname:更改主机名 打开终端。 使用hostnamectl命令更改主机名。 sudo hostnamectl set-hostname 新的主机名你可以使用hostnamectl 命令来验证更改是否成功: hostnamectlChrome:更换默认浏览器 以下是从 Ubuntu 中移除预装的 Snap 版 Fi…...
我们来学mysql -- MSI安装(安装篇)
主题 书接上文,在《探讨win安装方式》中官方推荐MSI要是把大厂的标准奉为圭臬,说啥认啥,他一翻脸,小丑不就是咱了再说了,都干到家门口了8.4版本官方文档,还不给他梭罗下 MSI 点击**.msi弹出MySQL Install…...
MySQL其一,概念学习,可视化软件安装以及增删改查语句
目录 MySQL 1、数据库的概念 2、数据库分类 3、MySQL的安装 4、安装过程中的问题 DataGrip的使用: SQLynx的使用: 5、编写SQL语句 6、DDL语句 7、DML 新增数据: 删除数据: 修改数据: MySQL SQL其实是一门…...
SpringCloud 题库
这篇文章是关于 SpringCloud 面试题的汇总,包括微服务的概念、SpringCloud 的组成及相关技术,如服务注册与发现、负载均衡、容错等,还涉及 Nacos 配置中心、服务注册表结构等原理,以及微服务架构中的日志采集、服务网关、相关概念…...
【ETCD】[源码阅读]深度解析 EtcdServer 的 processInternalRaftRequestOnce 方法
在分布式系统中,etcd 的一致性与高效性得益于其强大的 Raft 协议模块。而 processInternalRaftRequestOnce 是 etcd 服务器处理内部 Raft 请求的核心方法之一。本文将从源码角度解析这个方法的逻辑流程,帮助读者更好地理解 etcd 的内部实现。 方法源码 …...
数据分析与机器学习全解析
一、数据分析基础要点 (一)数据收集 确定数据源:明确是内部数据库、外部公开数据、传感器采集还是用户调研等来源,不同来源数据质量与获取难度各异。例如内部销售数据可直接获取,而市场调研数据需设计问卷并投入人力收…...
Qt 一个简单的QChart 绘图
Qt 一个简单的QChart 绘图 先上程序运行结果图: “sample9_1QChart.h” 文件代码如下: #pragma once#include <QtWidgets/QMainWindow> #include "ui_sample9_1QChart.h"#include <QtCharts> //必须这么设置 QT_CHARTS_USE_NAME…...
力扣——322. 零钱兑换
给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。 计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。 你可以认为每种硬币的数量是无限的。 示…...
Qt之网络监测
在Qt中,网络监测通常涉及到检测网络连接状态、网络延迟、带宽使用情况等。Qt提供了一些类和模块来帮助开发者实现这些功能。以下是一些常用的方法和类: 1. 检测网络连接状态 QtNetwork模块中的QNetworkConfigurationManager类可以用来检测设备的网络连…...
抓包软件fiddler和wireshark使用手册
fiddler官方文档 Fiddler 抓包教程1 Fiddler 抓包教程2 wireshark抓包学习 2添加链接描述 ip 过滤 ip.src_host ip.dst_host ip.addr mac 过滤 eth.src eth.dst eth.addr 端口过滤 tcp.port tcp.srcport tcp.dstport 协议类型过滤 arp dhcp 规则组合 and or...
【从零开始入门unity游戏开发之——C#篇03】变量和常量
文章目录 一、变量1、什么是变量?2、申明变量的固定写法3、变量的类型值和引用类型的区别无符号和有符号位——表示变量所占用的内存空间的大小范围——表示变量的取值范围取值范围和存储单位的关系为什么byte的范围是 0 到 255?为什么 sbyte 的范围是 -…...
SpringBoot 手动实现动态切换数据源 DynamicSource (上)
大家好,我是此林。 在实际开发中,经常可能遇到在一个SpringBoot Web应用中需要访问多个数据源的情况。 下面来介绍一下多数据源的使用场景、底层原理和手动实现。 一、 多数据源经典使用场景 场景一:业务复杂,数据量过大 1. 业务…...
ERROR Error: command failed: yarnError: command failed: yarn
1、异常信息 2、解决 解决方法一: WinR进入命令行,重新安装npm(如果报镜像源问题建议镜像源也重新配置) 输入命令,重新安装npm/yarn #npm npm install#npm 配置镜像源 npm config set registry https://registry.npmmirror.com#npm 查看镜…...
【java】finalize方法
目录 1. 说明2. 调用过程3. 注意事项 1. 说明 1.finalize方法是Java中Object类的一个方法。2.finalize方法用于在对象被垃圾回收之前执行一些清理工作。3.当JVM(Java虚拟机)确定一个对象不再被引用、即将被回收时,会调用该对象的finalize方法…...
C++ 内存管理和模板与STL
此篇目是之后各种C库的基础 目录 内存管理 内存分布 内存管理方式 new和delete operator new 与 operator delete函数 实现原理 定位new表达式(placement-new) 模板基础 泛型编程 模板 函数模板 类模板 STL 组成部分 内存管理 内存分布 int globalVar 1; //全局变量 静…...
同一个局域网下的两台电脑实现定时或者实时拷贝数据
【亲测能用】 需求:从数据库服务器上将数据库备份文件*.bak,每天定时拷贝到局域网下另一台电脑上,实现异机备份。 本文中192.168.1.110是本机,192.168.1.130是异机(备份机)。需求是每天定时从192.168.1.1…...
Python毕业设计选题:基于django+vue的汽车租赁管理网站
开发语言:Python框架:djangoPython版本:python3.7.7数据库:mysql 5.7数据库工具:Navicat11开发软件:PyCharm 系统展示 用户管理 汽车品牌管理 汽车信息管理 汽车租赁管理 汽车商品信息管理 汽车租赁 购物…...
scrapy对接rabbitmq的时候使用post请求
之前做分布式爬虫的时候,都是从push url来拿到爬虫消费的链接,这里提出一个问题,假如这个请求是post请求的呢,我观察了scrapy-redis的源码,其中spider.py的代码是这样写的 1.scrapy-redis源码分析 def make_request_from_data(self, data):"""Returns a Reques…...
Netty 性能优化与调试指南
Netty 是一款高性能的网络通信框架,其高性能得益于良好的设计和优化。但是在实际使用中,如果配置或实现不当,可能会导致性能下降或调试困难。本文将从性能优化和调试两方面入手,详细讲解如何在使用 Netty 时提高应用性能和诊断问题…...
网络安全产品之认识WEB应用防火墙
随着B/S架构的广泛应用,Web应用的功能越来越丰富,蕴含着越来越有价值的信息,应用程序漏洞被恶意利用的可能性越来越大,因此成为了黑客主要的攻击目标。传统防火墙无法解析HTTP应用层的细节,对规则的过滤过于死板&#…...
R学习——因子
目录 1 定义因子(factor函数) 2因子的作用 一个数据集中的 只需要考虑可以用哪个数据来进行分类就可以了,可以用来分类就可以作为因子。 Cy1这个因子对应的水平level是4 6 8: 1 定义因子(factor函数) 要…...
2024 亚马逊云科技re:Invent:Werner Vogels架构哲学,大道至简 六大经验助力架构优化
在2024亚马逊云科技re:Invent全球大会第四天的主题演讲中,亚马逊副总裁兼CTO Dr.Werner Vogels分享了 The Way of Simplexity,繁简之道,浓缩了Werner在亚马逊20年构建架构的经验。 Werner表示,复杂性总是会“悄无声息”地渗透进来…...
【代码随想录day58】【C++复健】 117. 软件构建(拓扑排序);47. 参加科学大会(dijkstra(朴素版)精讲)
117. 软件构建(拓扑排序) 继续边看解析边做题,思考时的问题做个如下的总结: 1. 存边用什么数据结构? 在题目中,我们需要存储节点之间的依赖关系(边信息)。选择适合的数据结构非常重…...
单目深度估计模型 lite-mono 测试
lite-mono 使用工业数据集kitti 进行训练,目的使用单目摄像头实现物体深度预测,关于kitti数据集的介绍和下载参考 (二)一文带你了解KITTI数据集-CSDN博客文章浏览阅读2.7w次,点赞64次,收藏294次。文章介绍…...
JAVA基础学习笔记_网络编程
文章目录 网络编程网络编程三要素IPIPv4细节InetAddress 端口号协议 UDPUDP协议(发数据)UDP协议(接受数据)UDP聊天室单播,组播,广播 TCP中文乱码问题代码细节,三次握手和四次挥手 网络编程 计算机之间通过网络进行数据传输 软件结构 C/S,Client/Server,客户端服务器,精美但麻…...
说下JVM中一次完整的GC流程?
大家好,我是锋哥。今天分享关于【说下JVM中一次完整的GC流程?】面试题。希望对大家有帮助; 说下JVM中一次完整的GC流程? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在JVM中,垃圾回收(GC&am…...
鸿蒙NEXT开发案例:保质期计算
【引言】 保质期计算应用是一个基于鸿蒙NEXT框架开发的数字和文本统计组件。用户可以输入商品的生产日期和保质期天数,应用会自动计算并展示相关信息,包括保质状态、剩余天数、生产日期和到期日期。 【环境准备】 • 操作系统:Windows 10 …...
LLM并发加速部署方案(llama.cpp、vllm、lightLLM、fastLLM)
大模型并发加速部署 解析当前应用较广的几种并发加速部署方案! llama.cpp、vllm、lightllm、fastllm四种框架的对比: llama.cpp:基于C,①请求槽,②动态批处理,③CPU/GPU混合推理vllm:基于Pyth…...
用最小的代价解决mybatis-plus关于批量保存的性能问题
1.问题说明 问题背景说明,在使用达梦数据库时,mybatis-plus的serviceImpl.saveBatch()方法或者updateBatchById()方法的时候,随着数据量、属性字段的增加,效率越发明显的慢。 serviceImpl.saveBatch(); serviceImpl.updateBatch…...
蓝桥杯历届真题 --#递推 翻硬币(C++)
文章目录 思路完整代码结语 原题链接 思路 通过观察测试用例,我们猜测,从左到右依次对比每一个位置上的状态,如果不一样我们就翻一次,最终得到的答案即为正解。 完整代码 //这里是引入了一些常用的头文件,和一些常规操作 //第一…...
BurpSuite-8(FakeIP与爬虫审计)
声明:学习视频来自b站up主 泷羽sec,如涉及侵权马上删除文章 感谢泷羽sec 团队的教学 视频地址:IP伪造和爬虫审计_哔哩哔哩_bilibili 一、FakeIP 1.配置环境 BurpSuite是java环境下编写的,而今天的插件是python编写的,…...
JAVA8、Steam、list运用合集
Steam运用 Java Stream API为开发人员提供了一种函数式和声明式的方式来表达复杂的数据转换和操作,使代码更加简洁和富有表现力。 1、使用原始流以获得更好的性能【示例:求和】 使用 int、long 和 double 等基本类型时,请使用IntStream、LongStream 和 DoubleStream 等基本流…...
深入详解人工智能机器学习:强化学习
目录 强化学习概述 强化学习的基本概念 定义 关键组件 强化学习过程 常用算法 应用示例 示例代码 代码解释 应用场景 强化学习核心概念和底层原理 核心概念 底层原理 总结 强化学习概述 强化学习(Reinforcement Learning, RL)是机器学习中的…...
docker的简单使用
文章目录 docker简介docker架构镜像和容器镜像有关的常用命令容器相关常用命令 docker简介 Docker是一个开源的应用容器引擎,基于Go语言并遵从Apache2.0协议开源。 Docker可以让开方子打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到…...
启动的docker容器里默认运行dockerd
问题 已在Dockerfile里yum install docker 但docker run 启动容器后, docker ps等命令无法执行 ps -aux 没有dockerd 进程 临时解决 另开一个终端 docker exec -it 容器名 bash 手动启 dockerd 默认启动 分析 现在启动容器的默认命令是 /sbin/init sbin/init 是根文件系统…...
Python爬虫技术的最新发展
在互联网的海洋中,数据就像是一颗颗珍珠,而爬虫技术就是我们手中的潜水艇。2024年,爬虫技术有了哪些新花样?让我们一起潜入这个话题,看看最新的发展和趋势。 1. 异步爬虫:速度与激情 随着现代Web应用的复…...