分布式锁设计与实践
分布式锁设计与实践
1. 分布式锁是什么
分布式锁即在分布式环境下锁定共享资源,让请求处理串行化,实际表现为互斥锁。分布式锁可以解决业务中的幂等性问题。
分布式锁是主要是可重入的排它锁,主要具有如下特点:
1)释放锁的节点,一定是持有锁的节点。
2)持有锁的节点宕机了,不会因此而出现死锁,就像synchronized一样,当持有锁的线程异常退出了,锁会被自动释放。
3)排他性,很好理解,一个节点持有锁,其他节点就不能持有了。
4)可重入性,很好理解,持有锁的节点,可以重复持有锁。
2. 分布式锁应用场景
两个常见的应用场景:(1)防止用户重复下单 (2)mq消息去重
2.1. 防止用户重复下单
正常情况下用户短时间内肯定是只会下单一次的,但是如果出现了超时用户点击了多次,那么如果前端的同学也没有控制住,这个时候如果服务层面不做任何控制就会出现同时下单多笔的情况,这个肯定是不正常的。当然如果在我们的服务没做水平扩容前我们加个本地锁就搞定了,但是如果我们的服务做了水平扩容:
这个时候就算我们的服务层面有本地锁,也还是不能解决问题的。比如第一次下单请求落在业务逻辑层1,而后面的重复下单落在业务逻辑层2、业务逻辑层3、业务逻辑层N,那我们的重复下单就真的重复下单了,所以这个时候我们需要分布式锁来解决这个问题:
这样每次下单请求过来的时候我们可以使用UserId作为关键信息先去分布式锁服务拿锁,如果能拿到请求继续执行,如果拿不到(被其他进程或线程占用)就丢弃掉当前请求。
2.2.MQ消息去重
还是用户下单的操作,这一次我们为了提升吞度量采用了水平分层异步架构,用户进行下单操作,这里我假设在网关层生成了订单号(正常情况下应该是专门的订单服务做处理),然后把请求丢到MessageQueue。这种场景下我们如果要对MQ消息去重,一般我们会有两种想法:
发送端去重
消费端去重
我们先来分析发送端去重,如果第一次发送端生成了消息丢到MQ,正常情况下MQ是会返回一个Ack给发送端的,那如果超时了,这个时候发送端重试又生成一个消息丢到MQ,我们可以思考下这种情况下我们能做到去重吗?肯定是做不到的吧,因为2次生成消息就会生成2个不同的MsgId。那我们再来看看消费端去重,其实这个时候我们要想既然MsgId我们不能唯一识别,那什么是我们能唯一识别的?肯定是订单号吧,那我们只要在消费端对订单号加锁就ok了吧。同样的如果没有做水平扩容的情况下我们本地锁是不是就可以搞定?但是水平扩容之后呢?
同样的道理,如果消息第一次被业务逻辑层1消费,后面重复的消息被业务逻辑层2、业务逻辑层3、业务逻辑层N消费,本地锁在这种情况下肯定搞不定。我们也需要分布式锁来做这个事:
这样每次消费消息的时候我们可以使用OrderId作为关键信息先去分布式锁服务拿锁,如果能拿到请求继续执行,如果拿不到(被其他进程或线程占用)就丢弃掉当前消息。
这里有一个需要注意的事情,我们的分布式锁只能处理短时间内的重复请求或者消息,如果过了锁的时间,那锁是无法处理的,这个时候怎么办呢?很简单,使用幂等处理。
通过分析上面2种业务场景,我们可以得出一个结论。这两种场景存在的共性是要处理共享的资源(订单、消息),那解决方案也就是实现共享资源的互斥,共享资源的串行化,那最后转换出来就是锁的问题了,锁又有本地锁和分布式锁。在分布式环境下,本地锁已经不奏效了,只能使用分布式锁。
3.分布式锁设计与实现
3.1. redis实现分布式锁
使用redis唯一工作线程来处理
3.1.1. 利用 SETNX 和 SETEX
基本命令主要有:
· SETNX(SET If Not Exists):当且仅当 Key 不存在时,则可以设置,否则不做任何动作。
· SETEX:可以设置超时时间
其原理为:通过 SETNX 设置 Key-Value 来获得锁,随即进入死循环,每次循环判断,如果存在 Key 则继续循环,如果不存在 Key,则跳出循环,当前任务执行完成后,删除 Key 以释放锁。
这种方式可能会导致死锁,为了避免这种情况,需要设置超时时间。
下面,请看具体的实现步骤。
1.创建一个 Maven 工程并在 pom.xml 加入以下依赖:
```xml
org.springframework.boot
spring-boot-starter-parent
2.0.2.RELEASE
UTF-8
UTF-8
1.8
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-data-redis
```
2.创建启动类 Application.java:
```java @SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
} ```
3.添加配置文件 application.yml:
```yaml server:
port: 8080
spring:
redis:
host: localhost
port: 6379 ```
4.创建全局锁类 Lock.java:
```java /**
* 全局锁,包括锁的名称
*/
public class Lock {
private String name;
private String value;
public Lock(String name, String value) {
this.name = name;this.value = value;
}
public String getName() {
return name;
}
public String getValue() {
return value;
}
} ```
5.创建分布式锁类 DistributedLockHandler.java:
```java @Component
public class DistributedLockHandler {
private static final Logger logger = LoggerFactory.getLogger(DistributedLockHandler.class);
private final static long LOCK_EXPIRE = 30 * 1000L;//单个业务持有锁的时间30s,防止死锁
private final static long LOCK_TRY_INTERVAL = 30L;//默认30ms尝试一次
private final static long LOCK_TRY_TIMEOUT = 20 * 1000L;//默认尝试20s
@Autowired
private StringRedisTemplate template;
/**
* 尝试获取全局锁
*
* @param lock 锁的名称
* @return true 获取成功,false获取失败
*/
public boolean tryLock(Lock lock) {
return getLock(lock, LOCK_TRY_TIMEOUT, LOCK_TRY_INTERVAL, LOCK_EXPIRE);
}
/**
* 尝试获取全局锁
*
* @param lock 锁的名称
* @param timeout 获取超时时间 单位ms
* @return true 获取成功,false获取失败
*/
public boolean tryLock(Lock lock, long timeout) {
return getLock(lock, timeout, LOCK_TRY_INTERVAL, LOCK_EXPIRE);
}
/**
* 尝试获取全局锁
*
* @param lock 锁的名称
* @param timeout 获取锁的超时时间
* @param tryInterval 多少毫秒尝试获取一次
* @return true 获取成功,false获取失败
*/
public boolean tryLock(Lock lock, long timeout, long tryInterval) {
return getLock(lock, timeout, tryInterval, LOCK_EXPIRE);
}
/**
* 尝试获取全局锁
*
* @param lock 锁的名称
* @param timeout 获取锁的超时时间
* @param tryInterval 多少毫秒尝试获取一次
* @param lockExpireTime 锁的过期
* @return true 获取成功,false获取失败
*/
public boolean tryLock(Lock lock, long timeout, long tryInterval, long lockExpireTime) {
return getLock(lock, timeout, tryInterval, lockExpireTime);
}
/**
* 操作redis获取全局锁
*
* @param lock 锁的名称
* @param timeout 获取的超时时间
* @param tryInterval 多少ms尝试一次
* @param lockExpireTime 获取成功后锁的过期时间
* @return true 获取成功,false获取失败
*/
public boolean getLock(Lock lock, long timeout, long tryInterval, long lockExpireTime) {
try {if (StringUtils.isEmpty(lock.getName()) || StringUtils.isEmpty(lock.getValue())) {return false;}long startTime = System.currentTimeMillis();do{if (!template.hasKey(lock.getName())) {ValueOperations<String, String> ops = template.opsForValue();ops.set(lock.getName(), lock.getValue(), lockExpireTime, TimeUnit.MILLISECONDS);return true;} else {//存在锁logger.debug("lock is exist!!!");}if (System.currentTimeMillis() - startTime > timeout) {//尝试超过了设定值之后直接跳出循环return false;}Thread.sleep(tryInterval);}while (template.hasKey(lock.getName())) ;} catch (InterruptedException e) {logger.error(e.getMessage());return false;}return false;
}
/**
* 释放锁
*/
public void releaseLock(Lock lock) {
if (!StringUtils.isEmpty(lock.getName())) {template.delete(lock.getName());}
}
} ```
6.最后创建 HelloController 来测试分布式锁。
```java @RestController
public class HelloController {
@Autowired
private DistributedLockHandler distributedLockHandler;
@RequestMapping("index")
public String index(){
Lock lock=new Lock("lynn","min");if(distributedLockHandler.tryLock(lock)){try {//为了演示锁的效果,这里睡眠5000毫秒System.out.println("执行方法");Thread.sleep(5000);}catch (Exception e){e.printStackTrace();}distributedLockHandler.releaseLock(lock);}return "hello world!";
}
} ```
7.测试。
启动 Application.java,连续访问两次浏览器:http://localhost:8080/index,控制台可以发现先打印了一次“执行方法”,说明后面一个线程被锁住了,5秒后又再次打印了“执行方法”,说明锁被成功释放。
通过这种方式创建的分布式锁存在以下问题:
\1. 高并发的情况下,如果两个线程同时进入循环,可能导致加锁失败。
\2. SETNX 是一个耗时操作,因为它需要判断 Key 是否存在,因为会存在性能问题。
因此,Redis 官方推荐 Redlock 来实现分布式锁。
3.1.2. 使用Redlock
通过 Redlock 实现分布式锁比其他算法更加可靠,继续改造上一例的代码。
1.pom.xml 增加以下依赖:
```xml
<groupId>org.redisson</groupId><artifactId>redisson</artifactId><version>3.7.0</version>
```
2.增加以下几个类:
```java /**
* 获取锁后需要处理的逻辑
*/
public interface AquiredLockWorker{
T invokeAfterLockAquire() throws Exception;
}
/**
* 获取锁管理类
*/
public interface DistributedLocker {
/**
* 获取锁
* @param resourceName 锁的名称
* @param worker 获取锁后的处理类
* @param
* @return 处理完具体的业务逻辑要返回的数据
* @throws UnableToAquireLockException
* @throws Exception
*/
T lock(String resourceName, AquiredLockWorkerworker) throws UnableToAquireLockException, Exception;
T lock(String resourceName, AquiredLockWorkerworker, int lockTime) throws UnableToAquireLockException, Exception;
}
/**
* 异常类
*/
public class UnableToAquireLockException extends RuntimeException {
public UnableToAquireLockException() {
}
public UnableToAquireLockException(String message) {
super(message);
}
public UnableToAquireLockException(String message, Throwable cause) {
super(message, cause);
}
}
/**
* 获取RedissonClient连接类
*/
@Component
public class RedissonConnector {
RedissonClient redisson;
@PostConstruct
public void init(){
redisson = Redisson.create();
}
public RedissonClient getClient(){
return redisson;
}
}
@Component
public class RedisLocker implements DistributedLocker{
private final static String LOCKER_PREFIX = "lock:";
@Autowired
RedissonConnector redissonConnector;
@Override
public T lock(String resourceName, AquiredLockWorkerworker) throws InterruptedException, UnableToAquireLockException, Exception {
return lock(resourceName, worker, 100);
}
@Override
public T lock(String resourceName, AquiredLockWorkerworker, int lockTime) throws UnableToAquireLockException, Exception {
RedissonClient redisson= redissonConnector.getClient();RLock lock = redisson.getLock(LOCKER_PREFIX + resourceName);// Wait for 100 seconds seconds and automatically unlock it after lockTime secondsboolean success = lock.tryLock(100, lockTime, TimeUnit.SECONDS);if (success) {try {return worker.invokeAfterLockAquire();} finally {lock.unlock();}}throw new UnableToAquireLockException();
}
}
3.修改 HelloController:
@RestController
public class HelloController {
@Autowired
private DistributedLocker distributedLocker;
@RequestMapping("index")
public String index()throws Exception{
distributedLocker.lock("test",new AquiredLockWorker<Object>() {@Overridepublic Object invokeAfterLockAquire() {try {System.out.println("执行方法!");Thread.sleep(5000);}catch (Exception e){e.printStackTrace();}return null;}});return "hello world!";
}
} ```
4.按照上节的测试方法进行测试,我们发现分布式锁也生效了。
Redlock 是 Redis 官方推荐的一种方案,因此可靠性比较高。
3.2. zookeeper实现分布式锁
3.2.1. 节点概念
让我们来回顾一下Zookeeper节点的概念:
Zookeeper的数据存储结构就像一棵树,这棵树由节点组成,这种节点叫做Znode。
Znode分为四种类型:
1.持久节点 (PERSISTENT)
默认的节点类型。创建节点的客户端与zookeeper断开连接后,该节点依旧存在 。
2.持久节点顺序节点(PERSISTENT_SEQUENTIAL)
所谓顺序节点,就是在创建节点时,Zookeeper根据创建的时间顺序给该节点名称进行编号:
3.临时节点(EPHEMERAL)
和持久节点相反,当创建节点的客户端与zookeeper断开连接后,临时节点会被删除:
4.临时顺序节点(EPHEMERAL_SEQUENTIAL)
顾名思义,临时顺序节点结合和临时节点和顺序节点的特点:在创建节点时,Zookeeper根据创建的时间顺序给该节点名称进行编号;当创建节点的客户端与zookeeper断开连接后,临时节点会被删除。
3.2.2. zookeeper分布式锁的原理
Zookeeper分布式锁恰恰应用了临时顺序节点。具体如何实现呢?让我们来看一看详细步骤:
获取锁
首先,在Zookeeper当中创建一个持久节点ParentLock。当第一个客户端想要获得锁时,需要在ParentLock这个节点下面创建一个临时顺序节点 Lock1。
之后,Client1查找ParentLock下面所有的临时顺序节点并排序,判断自己所创建的节点Lock1是不是顺序最靠前的一个。如果是第一个节点,则成功获得锁。
这时候,如果再有一个客户端 Client2 前来获取锁,则在ParentLock下载再创建一个临时顺序节点Lock2。
Client2查找ParentLock下面所有的临时顺序节点并排序,判断自己所创建的节点Lock2是不是顺序最靠前的一个,结果发现节点Lock2并不是最小的。这意味着Client2抢锁失败,进入了等待状态。
于是,Client2向排序仅比它靠前的节点Lock1注册Watcher,用于监听Lock1节点是否存在。
这时候,如果又有一个客户端Client3前来获取锁,则在ParentLock下载再创建一个临时顺序节点Lock3。
Client3查找ParentLock下面所有的临时顺序节点并排序,判断自己所创建的节点Lock3是不是顺序最靠前的一个,结果同样发现节点Lock3并不是最小的。
于是,Client3向排序仅比它靠前的节点Lock2注册Watcher,用于监听Lock2节点是否存在。这意味着Client3同样抢锁失败,进入了等待状态。
这样一来,Client1得到了锁,Client2监听了Lock1,Client3监听了Lock2。这恰恰形成了一个等待队列,很像是Java当中ReentrantLock所依赖的
释放锁
释放锁分为两种情况:
1.任务完成,客户端显示释放
当任务完成时,Client1会显示调用删除节点Lock1的指令。
2.任务执行过程中,客户端崩溃
获得锁的Client1在任务执行过程中,如果Duang的一声崩溃,则会断开与Zookeeper服务端的链接。根据临时节点的特性,相关联的节点Lock1会随之自动删除。
由于Client2一直监听着Lock1的存在状态,当Lock1节点被删除,Client2会立刻收到通知。这时候Client2会再次查询ParentLock下面的所有节点,确认自己创建的节点Lock2是不是目前最小的节点。如果是最小,则Client2顺理成章获得了锁。
同理,如果Client2也因为任务完成或者节点崩溃而删除了节点Lock2,那么Client3就会接到通知。
最终,Client3成功得到了锁。
3.2.3. 代码实现
创建 DistributedLock 类:
```java public class DistributedLock implements Lock, Watcher{
private ZooKeeper zk;
private String root = "/ParentLock";//根
private String lockName;//竞争资源的标志
private String waitNode;//等待前一个锁
private String myZnode;//当前锁
private CountDownLatch latch;//计数器
private CountDownLatch connectedSignal=new CountDownLatch(1);
private int sessionTimeout = 30000;
/**
* 创建分布式锁,使用前请确认config配置的zookeeper服务可用
* @param config localhost:2181
* @param lockName 竞争资源标志,lockName中不能包含单词_lock_
*/
public DistributedLock(String config, String lockName){
this.lockName = lockName;// 创建一个与服务器的连接try {zk = new ZooKeeper(config, sessionTimeout, this);connectedSignal.await();Stat stat = zk.exists(root, false);//此去不执行 Watcherif(stat == null){// 创建根节点zk.create(root, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);}} catch (IOException e) {throw new LockException(e);} catch (KeeperException e) {throw new LockException(e);} catch (InterruptedException e) {throw new LockException(e);}
}
/**
* zookeeper节点的监视器
*/
public void process(WatchedEvent event) {
//建立连接用if(event.getState()== Event.KeeperState.SyncConnected){connectedSignal.countDown();return;}//其他线程放弃锁的标志if(this.latch != null) {this.latch.countDown();}
}
public void lock() {
try {if(this.tryLock()){System.out.println("Thread " + Thread.currentThread().getId() + " " +myZnode + " get lock true");return;}else{waitForLock(waitNode, sessionTimeout);//等待锁}} catch (KeeperException e) {throw new LockException(e);} catch (InterruptedException e) {throw new LockException(e);}
}
public boolean tryLock() {
try {String splitStr = "_lock_";if(lockName.contains(splitStr))throw new LockException("lockName can not contains \\u000B");//创建临时子节点myZnode = zk.create(root + "/" + lockName + splitStr, new byte[0], ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL_SEQUENTIAL);System.out.println(myZnode + " is created ");//取出所有子节点List<String> subNodes = zk.getChildren(root, false);//取出所有lockName的锁List<String> lockObjNodes = new ArrayList<String>();for (String node : subNodes) {String _node = node.split(splitStr)[0];if(_node.equals(lockName)){lockObjNodes.add(node);}}Collections.sort(lockObjNodes);if(myZnode.equals(root+"/"+lockObjNodes.get(0))){//如果是最小的节点,则表示取得锁System.out.println(myZnode + "==" + lockObjNodes.get(0));return true;}//如果不是最小的节点,找到比自己小1的节点String subMyZnode = myZnode.substring(myZnode.lastIndexOf("/") + 1);waitNode = lockObjNodes.get(Collections.binarySearch(lockObjNodes, subMyZnode) - 1);//找到前一个子节点} catch (KeeperException e) {throw new LockException(e);} catch (InterruptedException e) {throw new LockException(e);}return false;
}
public boolean tryLock(long time, TimeUnit unit) {
try {if(this.tryLock()){return true;}return waitForLock(waitNode,time);} catch (Exception e) {e.printStackTrace();}return false;
}
private boolean waitForLock(String lower, long waitTime) throws InterruptedException, KeeperException {
Stat stat = zk.exists(root + "/" + lower,true);//同时注册监听。//判断比自己小一个数的节点是否存在,如果不存在则无需等待锁,同时注册监听if(stat != null){System.out.println("Thread " + Thread.currentThread().getId() + " waiting for " + root + "/" + lower);this.latch = new CountDownLatch(1);this.latch.await(waitTime, TimeUnit.MILLISECONDS);//等待,这里应该一直等待其他线程释放锁this.latch = null;}return true;
}
public void unlock() {
try {System.out.println("unlock " + myZnode);zk.delete(myZnode,-1);myZnode = null;zk.close();} catch (InterruptedException e) {e.printStackTrace();} catch (KeeperException e) {e.printStackTrace();}
}
public void lockInterruptibly() throws InterruptedException {
this.lock();
}
public Condition newCondition() {
return null;
}
public class LockException extends RuntimeException {
private static final long serialVersionUID = 1L;public LockException(String e){super(e);}public LockException(Exception e){super(e);}
}
} ```
3.3. ETCD实现分布式锁
ETCD实现分布式锁内容较多,篇幅太长,以后专题介绍
3.4. 三种分布式锁比较
4. CAP定律
2000年,Eric Brewer教授提出CAP猜想,2年后,被Seth Gilbert和Nancy Lynch大佬所证明。
CAP是指:Consistency(强一致性),Availability(可用性),Partition tolerance(分区容错性),分布式系统,三者同时满足两者。
由于分布式系统中,一定是存在分区的,所有cap模型中常用的只能是是:AP或CP模型了。
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
相关文章
- 缓存雪崩 缓存击穿 缓存雪崩出现原因及解决方案
文章目录缓存雪崩出现原因一解决方案方案一 差异化设置过期时间方案二 服务降级方案三 不设置过期时间出现原因二解决方案方案一 服务熔断方案二 请求限流方案三 Redis构建高可靠集群缓存击穿解决方案方案一 分布式锁方案二 热点数据不设置过期时间缓存穿透出现原因解决方案方案…...
2024/5/6 1:08:04 - PCL:关于pcd数据显示乱码
将bin 格式的点云转换成pcd 的格式有可能乱码,需要将pcd 另存一份 代码在git 代码在git ^W^Y<87>B?<9d>^_<86>B<98>n?d;^_^P<86>B ?)\^_^B<86>BZd?<8b>l^_y©<86>B^L^B^C^B^_<87><96><8…...
2024/5/5 21:30:57 - 华为运营商级路由器配置示例 | IPv4浮动静态路由
组网需求 路由器各接口及主机的IP地址和掩码如图1所示。在DeviceA上配置两条去往10.1.5.0/24的IPv4静态路由,其中优先级较高的主静态路由经过DeviceB,浮动静态路由经过DeviceC。 图1 配置IPv4浮动静态路由组网图 配置思路 首先配置各路由器各接口的IP…...
2024/4/18 12:35:55 - Jupyter Notebook介绍、安装及使用教程
链接:https://www.jianshu.com/p/91365f343585/ 来源:简书 一、什么是Jupyter Notebook? 1. 简介 Jupyter Notebook是基于网页的用于交互计算的应用程序。其可被应用于全过程计算:开发、文档编写、运行代码和展示结果。——Jup…...
2024/5/5 16:50:31 - 华为运营商级路由器配置示例 | IPv4静态路由
组网需求 路由器各接口及主机的IP地址和掩码如图1所示。要求采用静态路由,使图中任意两台主机之间都能互通。 图1 配置IPv4静态路由组网图 配置思路 首先配置各路由器各接口的IPv4地址,使网络互通。在路由器上配置到目的地址的IPv4静态路由及缺省路由…...
2024/4/13 11:03:03 - [MRCTF2020]Ezaudit
[MRCTF2020]Ezaudit 文章目录[MRCTF2020]Ezaudit伪随机数php_mt_rand()知识点:伪随机数mt_rand() 源码泄露:www.zip 下载后,是个index.php <?php header(Content-type:text/html; charsetutf-8); error_reporting(0); if(isset($_POST[…...
2024/4/14 0:02:23 - 算法@SHA1算法逆向与还原
SHA1算法逆向与还原 概述 sha1算法加密后的字符串长度是40位,sha256长度是64位 一般sha1算法还原 目标程序加密结果跟SHA1算法对不上 看下伪代码,SHA1算法跟MD5是类似的,也会用调用SHA1Update函数 把盐字符串拼接上就对了 SHA1Init常量变…...
2024/4/30 6:49:46 - 区块链开发技术
1.ethers.js、web3.js 区块链框架 2.花点时间学习Solidity和Truffle Solidity是以太坊推出的智能合约编程语言;Truffle是目前最常用的以太坊开发框架。作为区块链开发者,你必须对Solidity和Truffle非常熟悉。其实,Solidity上手的门槛并不高&a…...
2024/5/5 17:24:26 - 《道德经》全文 (马王堆出土帛书版)
01 道可道也,非恒道也。名可名也,非恒名也。无名万物之始也,有名万物之母也。故:恒无欲也,以观其眇;恒有欲也,以观其徼。两者同出,异名同谓。玄之又玄,众妙之门。 02 …...
2024/5/5 18:24:08 - 2022年2月8日学习总结
8:30~11:00 做一套英语四级真题,记单词。 11:00~12:30 复习高数 1:00~3:00 教妹妹高中数学 3:00~5:00 在网络上学习bmp 【neko】KMP算法【算法编程#7】_哔哩哔哩_bilibili KMP算法—终于全部弄懂了_dark_cy的博客-CSDN博客_kmp算法 KMP算法--c…...
2024/4/13 11:02:43 - 华为运营商级路由器配置示例 | 静态BFD for IPv4静态路由
组网需求 如图1所示,DeviceA通过SwithC和DeviceB相连。在DeviceA上配置静态缺省路由可以与外部进行正常通信。同时,在DeviceA和DeviceB之间配置BFD会话来快速检测链路故障。 图1 配置静态BFD for IPv4静态路由组网图 配置思路 在DeviceA和DeviceB上配…...
2024/5/5 21:33:52 - 我在研究MySQL online DDL 更改Varchar的字段长度
MySQL online DDL 更改Varchar的字段长度 一、这里是可以跳过的牢骚 开年上班的第一个星期,周围的同事们都在“表面上努力的工作,朋友圈一打开都在祝福谷爱凌夺冠”,哈哈哈,比较闲啦。 今天研究了一下varchr长度变更会不会把表给…...
2024/4/15 14:01:43 - Git提交代码/创建本地分支/创建远程分支
首次提交代码 第一步:拉取代码 git clone XXX 远程ssh地址 这里已我的为例: git clone gitgithub.com:caozhengbo/cekai8.git查看一下当前代码的分支 git branch第二步:修改代码里面的内容 我这里修改了README.md 文件 第三步 查看本次修…...
2024/4/7 22:21:04 - APP如何接入线上支付渠道,为什么不建议直接对接官方渠道
线上程序,包括app,h5网页等,往往都有支付的需求,很多人都认为接入支付这种事,只需要找到支付宝或者微信就能顺利接入了,话是这么说没错,个人或者公司也是能够直接对接支付宝以及微信等各种线上支…...
2024/4/17 21:48:33 - 解决虚拟机ubuntu20.04不能连外网问题
首先,我用的不是dhcp服务将ip分配给虚拟机的,用的是nat模式 先打开vm虚拟机的虚拟网络编辑器,如图先打开编辑-->虚拟网络编辑器 然后点击更改设置 此时点击VMnet8,注意“使用本地DHCP服务将IP地址分配给虚拟机”这个选项我是没…...
2024/4/13 11:03:08 - CAD软件开发面试记录
判断点是否在椭球内单链表逆向操作,写算法代码通过二叉树的前序遍历结果和中序遍历结果,写算法代码得到后序遍历结果如何做,可以让一个自定义的类当做map的key如何访问其他类的私有成员如何访问dll中的代码unorderedMap的底层原理,…...
2024/4/26 14:01:11 - c++ stat函数获取文件状态(包括修改时间等)
//stat函数不需要打开文件也能获取文件状态信息,对修改时间无影响,比GetFileTime函数好。 //前一篇文章的GetFileTime也可获取修改时间,但需要打开文件,打开文件影响修改时间,不推//荐使用GetFileTime函数。 #include <iostr…...
2024/4/13 11:02:43 - Windows11右键菜单太烦人,简单几步即可恢复旧版完整菜单
Windows 11已经推出一段时间了,相比Windows 10,界面确实美观了不少,同时也有很多新的设计。但是并不是每个人都能很快适应这种新设计。被广泛吐槽的一点就是右键菜单的改变,增加了显示更多选项 ,原来的很多右键选项被隐…...
2024/4/13 11:03:08 - C++程序设计之使用istringstream
...
2024/4/16 15:05:58 - 层次分析法
层次分析法 前言 比赛需要学了一手层次分析法,该方法适合用于评价分析。 虽然比直接主观判断要好一些,但仍属于偏主观的评价方法 吐槽一下,mooc上的数模关于这个的有个讲解视频感觉理解门槛有点高,反正我是听了一两遍都没懂&…...
2024/4/5 2:33:24
最新文章
- C语言--带环链表问题
继续学习 一、判断链表是否带环 141. 环形链表 - 力扣(LeetCode) 思路:用快慢指针,快指针走两步,慢指针走一步,当慢指针走一半快指针进到环里 当慢指针进环,快指针已经在环中转了一会儿了 | |…...
2024/5/6 1:30:52 - 梯度消失和梯度爆炸的一些处理方法
在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言,在此感激不尽。 权重和梯度的更新公式如下: w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...
2024/3/20 10:50:27 - 【项目新功能开发篇】开发编码
作者介绍:本人笔名姑苏老陈,从事JAVA开发工作十多年了,带过大学刚毕业的实习生,也带过技术团队。最近有个朋友的表弟,马上要大学毕业了,想从事JAVA开发工作,但不知道从何处入手。于是࿰…...
2024/5/3 2:06:18 - 【VTKExamples::Meshes】第七期 TableBasedClipDataSetWithPolyData
很高兴在雪易的CSDN遇见你 VTK技术爱好者 QQ:870202403 公众号:VTK忠粉 前言 本文分享VTK样例TableBasedClipDataSetWithPolyData,并解析接口vtkTableBasedClipDataSet,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步! 你…...
2024/5/5 8:45:33 - 【外汇早评】美通胀数据走低,美元调整
原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...
2024/5/4 23:54:56 - 【原油贵金属周评】原油多头拥挤,价格调整
原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...
2024/5/4 23:54:56 - 【外汇周评】靓丽非农不及疲软通胀影响
原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...
2024/5/4 23:54:56 - 【原油贵金属早评】库存继续增加,油价收跌
原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...
2024/5/4 23:55:17 - 【外汇早评】日本央行会议纪要不改日元强势
原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...
2024/5/4 23:54:56 - 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响
原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...
2024/5/4 23:55:05 - 【外汇早评】美欲与伊朗重谈协议
原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...
2024/5/4 23:54:56 - 【原油贵金属早评】波动率飙升,市场情绪动荡
原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...
2024/5/4 23:55:16 - 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试
原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...
2024/5/4 23:54:56 - 【原油贵金属早评】市场情绪继续恶化,黄金上破
原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...
2024/5/4 18:20:48 - 【外汇早评】美伊僵持,风险情绪继续升温
原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...
2024/5/4 23:54:56 - 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势
原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...
2024/5/4 23:55:17 - 氧生福地 玩美北湖(上)——为时光守候两千年
原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...
2024/5/4 23:55:06 - 氧生福地 玩美北湖(中)——永春梯田里的美与鲜
原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...
2024/5/4 23:54:56 - 氧生福地 玩美北湖(下)——奔跑吧骚年!
原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...
2024/5/4 23:55:06 - 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!
原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...
2024/5/5 8:13:33 - 「发现」铁皮石斛仙草之神奇功效用于医用面膜
原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...
2024/5/4 23:55:16 - 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者
原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...
2024/5/4 23:54:58 - 广州械字号面膜生产厂家OEM/ODM4项须知!
原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...
2024/5/4 23:55:01 - 械字号医用眼膜缓解用眼过度到底有无作用?
原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...
2024/5/4 23:54:56 - 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...
解析如下:1、长按电脑电源键直至关机,然后再按一次电源健重启电脑,按F8健进入安全模式2、安全模式下进入Windows系统桌面后,按住“winR”打开运行窗口,输入“services.msc”打开服务设置3、在服务界面,选中…...
2022/11/19 21:17:18 - 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。
%读入6幅图像(每一幅图像的大小是564*564) f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...
2022/11/19 21:17:16 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...
win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面,在等待界面中我们需要等待操作结束才能关机,虽然这比较麻烦,但是对系统进行配置和升级…...
2022/11/19 21:17:15 - 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...
有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows,请勿关闭计算机”的提示,要过很久才能进入系统,有的用户甚至几个小时也无法进入,下面就教大家这个问题的解决方法。第一种方法:我们首先在左下角的“开始…...
2022/11/19 21:17:14 - win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...
置信有很多用户都跟小编一样遇到过这样的问题,电脑时发现开机屏幕显现“正在配置Windows Update,请勿关机”(如下图所示),而且还需求等大约5分钟才干进入系统。这是怎样回事呢?一切都是正常操作的,为什么开时机呈现“正…...
2022/11/19 21:17:13 - 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...
Win7系统开机启动时总是出现“配置Windows请勿关机”的提示,没过几秒后电脑自动重启,每次开机都这样无法进入系统,此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一:开机按下F8,在出现的Windows高级启动选…...
2022/11/19 21:17:12 - 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...
有不少windows10系统用户反映说碰到这样一个情况,就是电脑提示正在准备windows请勿关闭计算机,碰到这样的问题该怎么解决呢,现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法:1、2、依次…...
2022/11/19 21:17:11 - 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...
今天和大家分享一下win7系统重装了Win7旗舰版系统后,每次关机的时候桌面上都会显示一个“配置Windows Update的界面,提示请勿关闭计算机”,每次停留好几分钟才能正常关机,导致什么情况引起的呢?出现配置Windows Update…...
2022/11/19 21:17:10 - 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...
只能是等着,别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚,只能是考虑备份数据后重装系统了。解决来方案一:管理员运行cmd:net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...
2022/11/19 21:17:09 - 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?
原标题:电脑提示“配置Windows Update请勿关闭计算机”怎么办?win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢?一般的方…...
2022/11/19 21:17:08 - 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...
关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!关机提示 windows7 正在配…...
2022/11/19 21:17:05 - 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...
钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...
2022/11/19 21:17:05 - 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...
前几天班里有位学生电脑(windows 7系统)出问题了,具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面,长时间没反应,无法进入系统。这个问题原来帮其他同学也解决过,网上搜了不少资料&#x…...
2022/11/19 21:17:04 - 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...
本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法,并在最后教给你1种保护系统安全的好方法,一起来看看!电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中,添加了1个新功能在“磁…...
2022/11/19 21:17:03 - 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...
许多用户在长期不使用电脑的时候,开启电脑发现电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机。。.这要怎么办呢?下面小编就带着大家一起看看吧!如果能够正常进入系统,建议您暂时移…...
2022/11/19 21:17:02 - 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...
配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!配置windows update失败 还原更改 请勿关闭计算机&#x…...
2022/11/19 21:17:01 - 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...
不知道大家有没有遇到过这样的一个问题,就是我们的win7系统在关机的时候,总是喜欢显示“准备配置windows,请勿关机”这样的一个页面,没有什么大碍,但是如果一直等着的话就要两个小时甚至更久都关不了机,非常…...
2022/11/19 21:17:00 - 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...
当电脑出现正在准备配置windows请勿关闭计算机时,一般是您正对windows进行升级,但是这个要是长时间没有反应,我们不能再傻等下去了。可能是电脑出了别的问题了,来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...
2022/11/19 21:16:59 - 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...
我们使用电脑的过程中有时会遇到这种情况,当我们打开电脑之后,发现一直停留在一个界面:“配置Windows Update失败,还原更改请勿关闭计算机”,等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢࿰…...
2022/11/19 21:16:58 - 如何在iPhone上关闭“请勿打扰”
Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...
2022/11/19 21:16:57