如何实现一个分布锁?

2023-11-19

基本概念

为何需要分布式锁?

  1. 传统环境中的情况:
    在程序开发过程中不得不考虑的就是并发问题。在java中对于同一个jvm而言,jdk已经提供了lock和同步等。但是在分布式情况下,往往存在多个进程对一些资源产生竞争关系,而这些进程往往在不同的机器上,这个时候jdk中提供的已经不能满足。也就是说单纯的Java Api并不能提供分布式锁的能力。所以针对分布式锁的实现目前有多种方案。

  2. 在很多的场景中,为了保证数据的最终一致性,需要很多方案来支持,比如分布式事务、分布式锁等。我们需要保证一个方法在同一时间内只有一个线程被执行。(比如Java中的并发情况lock, synchronized)就是实现了单机环境下的同步,保证共享变量的一致性。

  3. 分布式锁主要用于在分布式环境中保护跨进程、跨主机、跨网络的共享资源实现互斥访问,以达到保证数据的一致性。

目前的解决方案

  1. 基于数据库实现分布式锁
  2. 基于缓存(redis、memcached)等实现分布锁
  3. 基于zookeeper实现分布锁

要达到的目标

在分析上述几种方案之前,理想的分布锁理应达到的效果

  • 可以保证在分布式部署的应用集群中,同一个方法在同一个时间内只能被一台机器上面的一个线程执行。
  • 这把锁事可重入锁避免死锁即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。
  • 有高可用的获取锁和释放锁的功能
  • 释放锁和获取锁的成本要低,性能要好(包括正常情况下的释放锁和非正常情况下的释放锁)
  • 互斥性。在任意时刻,只有一个客户端能持有锁
  • 具有容错性。只要大部分的Redis节点正常运行,客户端就可以加锁和解锁。

# 基于数据库实现分布式锁

基于数据库的锁实现也有两种方式,一是基于数据库表,另一种是基于数据库排他锁。

基于数据库表

要实现分布式锁,最简单的方式就是之间创建一张锁表,然后通过操作表中的数据来实现。当我们要锁住某个资源或方法时,我们就在该表中增加一条记录,想要释放锁的时候就删除这条记录。

基于数据库表增删是最简单的方式,首先创建一张锁的表主要包含下列字段:方法名,时间戳等字段。

创建这样一张数据库表:

CREATE TABLE `methodLock` ( 
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',  
`method_name` varchar(64) NOT NULL DEFAULT '' COMMENT '锁定的方法名',  
`desc` varchar(1024) NOT NULL DEFAULT '备注信息',  
 `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE  CURRENT_TIMESTAMPCOMMENT '保存数据时间,自动生成',  
 PRIMARY KEY (`id`),  UNIQUE KEY `uidx_method_name` (`method_name `) USING BTREE) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='锁定中的方法';


当我们想要锁住某个方法,执行一下SQL

insert into methodLock(method_name,desc) values (‘method_name’,desc)

当我们对method_name做了唯一性约束,这里如果有多个请求同时提交到数据的话,数据库会保证只有一个操作可以成功,那么我们就可以认为操作成功的那个线程获得了该方法的锁,可以执行方法体内容。

当方法执行完毕之后,想要释放锁的话,需要执行以下Sql:

delete from methodLock where method_name ='method_name'

基于数据库排他锁

除了可以通过增删操作数据表中的记录以外,其实还可以借助数据中自带的锁来实现分布式的锁。

我们还可以通过数据库的排他锁来实现分布式锁。基于MySql的InnoDB引擎,用刚刚创建的那张数据库表,可以使用以下方法来实现加锁操作:

####### 1. 获得锁

public boolean lock(){   
    connection.setAutoCommit(false)    
        while(true){       
            try{           
                result = select * from methodLock where method_name=xxx for update;               
                if(result!=null){    
                    //代表获取到锁
                    return true;           
                }       
            }catch(Exception e)
            {        e.printStack();
            }    
             //为空或者抛异常的话都表示没有获取到锁
            sleep(1000);   
        }    return false;
}

在查询语句后面增加for update,数据库会在查询过程中给数据库表增加排他锁(这里再多提一句,InnoDB引擎在加锁的时候,只有通过索引进行检索的时候才会使用行级锁,否则会使用表级锁。这里我们希望使用行级锁,就要给method_name添加索引,值得注意的是,这个索引一定要创建成唯一索引,否则会出现多个重载方法之间无法同时被访问的问题。重载方法的话建议把参数类型也加上。)。当某条记录被加上排他锁之后,其他线程无法再在该行记录上增加排他锁。

2. 释放锁

我们可以认为获得排它锁的线程即可获得分布式锁,当获取到锁之后,可以执行方法的业务逻辑,执行完方法之后,再通过以下方法解锁:


public void unlock(){
    connection.commit();

}

通过==connection.commit()==操作来释放锁。

存在的问题

  1. 这把锁强依赖数据库的可用性,数据库是一个单点,一旦数据库挂掉,会导致业务系统不可用。
  2. 这把锁没有失效时间,一旦解锁操作失败,就会导致锁记录一直在数据库中,其他线程无法再获得到锁。(释放锁的性能不高)
  3. 这把锁只能是非阻塞的,因为数据的insert操作,一旦插入失败就会直接报错。没有获得锁的线程并不会进入排队队列,要想再次获得锁就要再次触发获得锁操作。
  4. 这把锁是非重入的,同一个线程在没有释放锁之前无法再次获得该锁。因为数据中数据已经存在了。

在查询语句后面增加for update,数据库会在查询过程中给数据库表增加排他锁(这里再多提一句,InnoDB引擎在加锁的时候,只有通过索引进行检索的时候才会使用行级锁,否则会使用表级锁。这里我们希望使用行级锁,就要给method_name添加索引,值得注意的是,这个索引一定要创建成唯一索引,否则会出现多个重载方法之间无法同时被访问的问题。重载方法的话建议把参数类型也加上。)。当某条记录被加上排他锁之后,其他线程无法再在该行记录上增加排他锁。

当然也有方式解决上面的问题

  1. 数据库是单点?搞两个数据库,数据之前双向同步。一旦挂掉快速切换到备库上。
  2. 没有失效时间?只要做一个定时任务,每隔一定时间把数据库中的超时数据清理一遍。
  3. 非阻塞的?搞一个while循环,直到insert成功再返回成功。
  4. 非重入的?在数据库表中加个字段,记录当前获得锁的机器的主机信息和线程信息,那么下次再获取锁的时候先查询数据库,如果当前机器的主机信息和线程信息在数据库可以查到的话,直接把锁分配给他就可以了。

总结

总结一下使用数据库来实现分布式锁的方式,这两种方式都是依赖数据库的一张表,一种是通过表中的记录的存在情况确定当前是否有锁存在,另外一种是通过数据库的排他锁来实现分布式锁。

优点

直接借助数据库,容易理解

缺点

操作数据库需要一定的开销,性能问题需要考虑。

使用数据库的行级锁并不一定靠谱,尤其是当我们的锁表并不大的时候。

使用zookeeper实现分布式锁

讲得很好,看这篇就够了

基于zookeeper临时有序节点可以实现的分布式锁。

背景知识(节点知识)

节点代表一个客户端在服务器下面创建的一个标志的东西
在描述算法流程之前,先看下zookeeper中几个关于节点的有趣的性质:

  1. 有序节点:假如当前有一个父节点为/lock,我们可以在这个父节点下面创建子节点;zookeeper提供了一个可选的有序特性,例如我们可以创建子节点“/lock/node-”并且指明有序,那么zookeeper在生成子节点时会根据当前的子节点数量自动添加整数序号,也就是说如果是第一个创建的子节点,那么生成的子节点为/lock/node-0000000000,下一个节点则为/lock/node-0000000001,依次类推。
  2. 临时节点:客户端可以建立一个临时节点,在会话结束或者会话超时后,zookeeper会自动删除该节点
  3. 事件监听:在读取数据时,我们可以同时对节点设置事件监听,当节点数据或结构变化时,zookeeper会通知客户端。当前zookeeper有如下四种事件:1)节点创建;2)节点删除;3)节点数据修改;4)子节点变更。

总体结构

在介绍使用Zookeeper实现分布式锁之前,首先看当前的系统架构图

结构图

算法总体流程

下面描述使用zookeeper实现分布式锁的算法流程,假设锁空间的根节点为/lock:

  1. 客户端连接zookeeper,并在/locker下创建临时的且有序的子节点,第一个客户端对应的子节点为/lock/lock-0000000000,第二个为/lock/lock-0000000001,以此类推。
  2. 客户端获取/lock下的子节点列表,判断自己创建的子节点是否为当前子节点列表中序号最小的子节点,如果是则认为获得锁,否则监听/lock的子节点变更消息,获得子节点变更通知后重复此步骤直至获得锁;
  3. 执行业务代码;
  4. 完成业务流程后,删除对应的子节点释放锁。(定义了释放锁的操作In ZooKeeper, the lock releasing in normal circumstances means to delete the temporary nodes)

步骤1中创建的临时节点能够保证在故障的情况下锁也能被释放,考虑这么个场景:假如客户端a当前创建的子节点为序号最小的节点,获得锁之后客户端所在机器宕机了,客户端没有主动删除子节点;如果创建的是永久的节点,那么这个锁永远不会释放,导致死锁;由于创建的是临时节点,客户端宕机后,过了一定时间zookeeper没有收到客户端的心跳包判断会话失效,将临时节点删除从而释放锁。
另外细心的朋友可能会想到,在步骤2中获取子节点列表与设置监听这两步操作的原子性问题,考虑这么个场景:客户端a对应子节点为/lock/lock-0000000000,客户端b对应子节点为/lock/lock-0000000001,客户端b获取子节点列表时发现自己不是序号最小的,但是在设置监听器前客户端a完成业务流程删除了子节点/lock/lock-0000000000,客户端b设置的监听器岂不是丢失了这个事件从而导致永远等待了?这个问题不存在的。因为zookeeper提供的API中设置监听器的操作与读操作是原子执行的,也就是说在读子节点列表时同时设置监听器,保证不会丢失事件。

最后,对于这个算法有个极大的优化点:假如当前有1000个节点在等待锁,如果获得锁的客户端释放锁时,这1000个客户端都会被唤醒,这种情况称为“羊群效应”;在这种羊群效应中,zookeeper需要通知1000个客户端,这会阻塞其他的操作,最好的情况应该只唤醒新的最小节点对应的客户端。应该怎么做呢?在设置事件监听时,每个客户端应该对刚好在它之前的子节点设置事件监听,例如子节点列表为/lock/lock-0000000000、/lock/lock-0000000001、/lock/lock-0000000002,序号为1的客户端监听序号为0的子节点删除消息,序号为2的监听序号为1的子节点删除消息。

所以调整后的分布式锁算法流程如下:

  1. 客户端连接zookeeper,并在/lock下创建临时的且有序的子节点,第一个客户端对应的子节点为/lock/lock-0000000000,第二个为/lock/lock-0000000001,以此类推。(唯一的临时有序节点)

  2. 客户端获取/lock下的子节点列表,判断自己创建的子节点是否为当前子节点列表中序号最小的子节点,如果是则认为获得锁,否则监听刚好在自己之前一位的子节点删除消息,获得子节点变更通知后重复此步骤直至获得锁;(getChildren(/mylock)

  3. 执行业务代码;

  4. 完成业务流程后,删除对应的子节点释放锁。

    可以总结如下

    每个客户端对某个方法加锁时,在zookeeper上的与该方法对应的指定节点的目录下,生成一个唯一的瞬时有序节点。 判断是否获取锁的方式很简单,只需要判断有序节点中序号最小的一个。 当释放锁的时候,只需将这个瞬时节点删除即可。同时,其可以避免服务宕机导致的锁无法释放,而产生的死锁问题。

算法总体流程

总体流程图

伪代码

1. 获取锁

public void lock(){ 
    path = Create temporary sequence nodes under the parent node 
    while(true){ 
        children = Obtain all the nodes under the parent node 
        If (path is the smallest unit in children){ 
            indicates the node is obtained 
            return; 
        }else{ 
            Add a watcher to monitor whether the previous node exists 
            wait(); 
        } 
    } 
} 
​```
//先创建临时节点,然后判断是否是最小的节点,如果是获得锁,否则在前一个节点处watch监听
Content in watcher{
    notifyAll();
}

2.释放锁

public void release{
    Delete the node create above
}

All unlock() does is explictly delete this process’s node which notifies all the other waiting processes and allows the next one in line to go. Because the nodes are EPHEMERAL, the process can exit without unlocking and ZooKeeper will eventually reap its node allowing the next process to execute. This is a good thing because it means if your process ends prematurely without you having a chance to call unlock() it will not block the remaining processes. Note that it is best to explicitly call unlock() if you can, because it is much faster than waiting for ZooKeeper to reap your node

zookeeper 如何解决数据库方式存在的问题

  1. 锁无法释放?

    使用zookeeper可以有效解决锁无法释放的问题。在获取锁之前,客户端会在ZK服务端zookeeper/locker/node_序号(临时), 一旦客户端获得锁之后挂掉(Session连接断开),那么这个临时节点就会自动删除掉,释放锁。其他客户端就可以再次获得锁

  2. 非阻塞锁?

    使用Zookeeper可以实现阻塞的锁,客户端可以通过在ZK中创建顺序节点,如果获取锁不成功,就在前面一个节点注册watch监听器;一旦节点有变化,Zookeeper会通知客户端,客户端可以检查自己创建的节点是不是当前所有节点中序号最小的,如果是,那么自己就获取到锁,便可以执行业务逻辑了。

  3. 不可重入?

    使用Zookeeper也可以有效的解决不可重入的问题,客户端在创建节点的时候,把当前客户端的主机信息和线程信息直接写入到节点中,下次想要获取锁的时候和当前最小的节点中的数据比对一下就可以了。如果和自己的信息一样,那么自己直接获取到锁,如果不一样就再创建一个临时的顺序节点,参与排队。

  4. 单点问题?

    单点问题?使用Zookeeper可以有效的解决单点问题,ZK是集群部署的,只要集群中有半数以上的机器存活,就可以对外提供服务。(保证高可用)

zookeeper开源客户端

Curator 和zkclient等客户端情况

虽然zookeeper原生客户端暴露的API已经非常简洁了,但是实现一个分布式锁还是比较麻烦的…
我们可以直接使用curator这个开源项目提供的zookeeper分布式锁实现。

缺点

  1. zookeeper实现的分布式锁其实存在一个缺点,那就是性能上可能并没有缓存服务那么高。因为每次在创建锁和释放锁的过程中,都要动态创建、销毁瞬时节点来实现锁功能。
  2. ZK中创建和删除节点只能通过Leader服务器来执行,然后将数据同不到所有的Follower机器上。并发问题,可能存在网络抖动,客户端和ZK集群的session连接断了,zk集群以为客户端挂了,就会删除临时节点,这时候其他客户端就可以获取到分布式锁了

redis实现分布锁

In Redis, you usually can use the SETNX command to implement distributed locks.

相比较于基于数据库实现分布式锁的方案来说,基于缓存来实现在性能方面会表现的更好一点。而且很多缓存是可以集群部署的,可以解决单点问题。(同样zookeeper 形式)

代码

1.获得锁

public void lock(){ 
    for(){ 
        ret = setnx lock_ley (current_time + lock_timeout) 
        if(ret){ 
            //The lock is obtained 
            break; 
        } 
        //The lock is not obtained 
        sleep(100); 
    } 
} 

释放锁

  1. 释放锁

    public void release(){
        del lock_key
    }
    

优点

相对于基于数据库实现分布式锁的方案来说,基于缓存来实现在性能方面会表现的更好一点,存取速度快很多。而且很多缓存是可以集群部署的,可以解决单点问题。基于缓存的锁有好几。

缺点

实现复杂

Java 客户端

Redisson 链接

redis实现分布式锁和zookeeper实现分布式锁的区别?

redis和zookeeper锁的区别

Redis为单进程单线程模式,采用队列模式将并发访问变成串行访问,且多客户端对Redis的连接并不存在竞争关系。其次Redis提供一些命令SETNX,GETSET,可以方便实现分布式锁机制

Redis分布式锁,必须使用者自己间隔时间轮询去尝试加锁,当锁被释放后,存在多线程去争抢锁,并且可能每次间隔时间去尝试锁的时候,都不成功,对性能浪费很大。
Zookeeper分布锁,首先创建加锁标志文件,如果需要等待其他锁,则添加监听后等待通知或者超时,当有锁释放,无须争抢,按照节点顺序,依次通知使用者。

从上面可以知道,基于zookeeper的锁,client的都有节点序号(有序节点的特性),按照序号来, 都是注册在locker 下面下的node_n, 不存在多个竞争的方式

Redis实现分布式锁服务时,有可能存在master崩溃导致多个节点获取锁的问题

总结

Zookeeper实现简单,但效率较低;Redis实现复杂,但效率较高。

相对于基于数据库实现分布式锁的方案来说,基于缓存来实现在性能方面会表现的更好一点,存取速度快很多。而且很多缓存是可以集群部署的,可以解决单点问题。基于缓存的锁有好几。
三种方案的比较

上面几种方式,哪种方式都无法做到完美。就像CAP一样,在复杂性、可靠性、性能等方面无法同时满足,所以,根据不同的应用场景选择最适合自己的才是王道。
从理解的难易程度角度(从低到高)

数据库 > 缓存 > Zookeeper
从实现的复杂性角度(从低到高)

Zookeeper >= 缓存 > 数据库
从性能角度(从高到低)

缓存 > Zookeeper >= 数据库
从可靠性角度(从高到低)

Zookeeper > 缓存 > 数据库

实现分布锁的原则

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何实现一个分布锁? 的相关文章

  • StackExchange.Redis 简单 C# 示例

    我正在寻找一个非常简单的 C 入门应用程序来使用 StackExchange Redis 我在网上搜索并发现StackExchange Redis https github com StackExchange StackExchange R
  • scrapy-redis程序不会自动关闭

    scrapy redis框架 redis存储的xxx requests已经爬取完毕 但是程序还在运行 如何自动停止程序 而不是一直在运行 运行代码 2017 08 07 09 17 06 scrapy extensions logstats
  • Express 和 Redis 会话的过期时间

    我正在使用express和redis来使会话在我的系统上保持活动状态 我在设置 sessionCookie 上的 maxAge 时遇到一些问题 默认情况下 我读到的时间是 24 小时 但这对于保持其存活来说是很长的时间 我想设置大约 30
  • 为什么我不能让单个 Redis 客户端在同一连接中充当 PUB 和 Sub ?

    我的思维模型是 聊天 我订阅了某个频道 并且可以向该频道发布消息 由于 pub sub 是异步的 因此发布的消息可能随时出现 包括当您期望命令响应时 尽管 Redis 是单线程的 通常会阻止此类事情 但网络延迟可能会导致一些有趣的影响 根据
  • ServiceStack:手动调用服务时恢复管道?

    作为后续这个问题 https stackoverflow com questions 64560997 servicestack messaging api can it make a broadcast 我想了解如何改进我对服务的手动调用
  • Redis部署配置-主从复制

    目前我有两台服务器 我已经部署了基于node js Express JS的Web服务API 我正在使用 Redis 来缓存 JSON 字符串 将此设置部署到生产中的最佳选择是什么 我懂了here https stackoverflow co
  • 使用 EVAL、SCAN 和 DEL 的 Redis 通配符删除脚本返回“非确定性命令后不允许写入命令”

    因此 我正在寻求构建一个 lua 脚本 该脚本使用 SCAN 根据模式查找键并删除它们 原子地 我首先准备了以下脚本 local keys local done false local cursor 0 repeat local resul
  • 如何在redis中创建自己的数据库?

    There are 0 to 15 databases in redis 我想使用 redis cli 创建自己的数据库 有什么命令可以实现吗 Redis 数据库并不等同于 MySQL 等 DBMS 中的数据库名称 这是一种为键创建隔离和命
  • 使用brew在MacOSx上安装Redis JSON

    如何使用brew 在 macOSx 上安装 RedisJSON 如何在不编译redis的情况下启用redis上的模块 我不想使用 docker 客户端 Redis Stack 可能是最简单的方法 它不仅仅是 RedisJSON 还包括 Re
  • 保护节点 Redis

    我正在尝试保护 Node Redis IPC 服务器以使用私钥 公钥 我已经关注了本教程 http bencane com 2014 02 18 sending redis traffic through an ssl tunnel wit
  • Stackexchange.redis 缺乏“WAIT”支持

    我在客户端应用程序正在使用的负载均衡器后面有 3 个 Web API 服务器 我正在使用这个库来访问具有一个主服务器和几个从服务器的 Redis 集群 目前不支持 WAIT 操作 我需要此功能来存储新创建的用户会话并等待它复制到所有从属服务
  • 如何设置 Celery 以通过 ssl 与 Azure Redis 实例对话

    使用 的伟大答案 如何在microsoft azure上的django项目中配置celery redis https stackoverflow com questions 39616701 how to configure celery
  • 库存管理系统的 SQL 与 NoSQL

    我正在开发一个基于 JAVA 的网络应用程序 主要目的是拥有在多个称为渠道的网站上销售的产品的库存 我们将担任所有这些渠道的管理者 我们需要的是 用于管理每个渠道的库存更新的队列 库存表 其中包含每个通道上分配的正确快照 将会话 ID 和其
  • 如果另一个键中的计数器低于零,则从集合中原子删除一个项目?

    雷迪斯2 0 3 在我的 Redis DB 中 我有一组项目 每个项目都有一个与其关联的计数器 MULTI SADD items set foo INCRBY items foo 10000 EXEC 新项目会以随机间隔添加到集合中 当用户
  • Redis 排序集和解决关系

    我正在使用 Redis 排序集来存储我正在处理的项目的排名 我们没有预料到 我们想要如何处理关系 Redis 按字典顺序对具有相同分数的条目进行排序 但我们想要做的是对具有相同分数的所有条目给予相同的排名 例如在以下情况 redis 127
  • Spring Data Redis JedisConnectionException:流意外结束

    雷迪斯3 0 5Spring数据Redis 1 3 6绝地武士2 6 3 我们的 Web 应用程序通过 pub sub 从 Redis 接收数据 还以键 值对的形式在 Redis 上执行数据读 写 读 写发生在监听线程 独立监控线程和htt
  • 如何测试我的 Redis 缓存是否正常工作?

    我已经安装了 django redis cache 和 redis py 我遵循了 Django 的缓存文档 据我所知 以下设置就是我所需要的 但我如何判断它是否正常工作 设置 py CACHES default BACKEND redis
  • 使用 Redis 命令 incr 和 expire 时的竞争条件

    根据redis文档 http redis io commands incr http redis io commands incr 在段落模式 速率限制器 2 较短的版本代码 value INCR ip IF value 1 THEN EX
  • socket.io 广播功能 & Redis pub/sub 架构

    如果有人能帮助我解决一个小疑问 我将不胜感激 使用socket io广播功能和在Redis上使用pub sub设计架构有什么区别 例如 在另一个示例中 node js 服务器正在侦听 socket io 针对 键 模型 todo 和值 数据
  • Redis Docker compose无法处理RDB格式版本10

    我无法在 docker compose 文件中启动 redis 容器 我知道docker compose文件没问题 因为我的同事可以成功启动项目 我读到有一个删除 dump rdb 文件的解决方案 但我找不到它 我使用Windows机器 任

随机推荐

  • 关于the selection cannot be run on any server错误的问题,如何快速的解决。

    最近在导入外来项目时 遇到了一个难题 就是出现了图中的错误 the selection cannot be run on any server 无法在任何服务器上运行所选内容 这个错误的原因在于Dynamic Web Module 的版本与
  • 基于CNN-GRU的多维数据预测算法——附带Matlab代码

    基于CNN GRU的多维数据预测算法 附带Matlab代码 近年来 卷积神经网络 CNN 和门控循环单元 GRU 在时序数据处理中的应用十分广泛 本文提出了一种基于CNN GRU结构的多维数据预测算法 并提供了相应的Matlab代码 首先
  • FPGA Xilinx 7系列高速收发器GTX通信

    Xilinx 7系列高速收发器GTX 说明 FPGA TX端 zynq 7z035 RX端 zynq 7z100 两个FPGA通过SFP 光纤 接口相连进行GTX的通信 环境 Vivado2018 2 IP核 7 Series FPGAs
  • radius认证服务器无响应,squid radius认证“RADIUS服务器没有响应”

    我已经用mysql成功配置freeradius 我可以radtest使用命令 squid radius认证 RADIUS服务器没有响应 sudo radtest alice password 192 168 2 3 1812 testing
  • java面向对象 final && static 关键字

    目录 关键字 static 类属性 类方法的设计思想 类变量 class Variable 静态变量的内存解析 类方法 class method 单例 Singleton 设计模式 理解main方法的语法 代码块 关键字 final 总结
  • LTE MIB&SIB1

    LTE MIB SIB1 LTE MIB SIB 消息可以参考 http blog csdn net wowricky article details 51348613 UE 接受完MIB SIB1后就可以判断这个CELL是否可以驻留 这里
  • Unix and perl primer for Biologists - Part2 :Advanced Unix- Reading Notes(U37-U45)

    U37 Counting with grep Running grep c simply counts how many lines match the specified pattern root kali Downloads Unix
  • Linux内核调度算法 -- CPU时间片如何分配

    内核在微观上 把CPU的运行时间分成许多分 然后安排给各个进程轮流运行 造成宏观上所有的进程仿佛同时在执行 双核CPU 实际上最多只能有两个进程在同时运行 大家在top vmstat命令里看到的正在运行的进程 并不是真的在占有着CPU哈 所
  • FPGA_时钟显示(时钟可调)

    1 实验说明 在数码管显示数据的基础上 让六位数码管显示数字时钟 并且通过按键可以对时间进行修改 实验目标 六位数码管分别显示时间的时分秒 且通过按键可实现加减调整时间及清零功能 key1 切换键 选择待调整的时间单位 时 分 秒 key2
  • 2021-09-18

    Idea控制台中文乱码解决 Dfile encoding gb2312
  • HBase跨版本数据迁移总结

    本文首发腾云阁 HBase跨版本数据迁移总结 某客户大数据测试场景为 Solr类似画像的数据查出用户标签 通过这些标签在HBase查询详细信息 以上测试功能以及性能 其中HBase的数据量为500G Solr约5T 数据均需要从对方的集群人
  • 剑指 Offer 56 - II. 数组中数字出现的次数 II(java+python)

    在一个数组 nums 中除一个数字只出现一次之外 其他数字都出现了三次 请找出那个只出现一次的数字 示例 1 输入 nums 3 4 3 3 输出 4 示例 2 输入 nums 9 1 7 9 7 9 7 输出 1 限制 1 lt nums
  • 宝塔面板 创建 二级域名 Unable to round-trip http request to upstream

    1 我的服务器是阿里云 安装了宝塔面板 直接使用宝塔面板创建二级域名bike caowei wang 2 然后就想访问了 对不起 直接给你报错Unable to round trip http request to upstream dia
  • 第二届网刃杯--部分Re

    1 freestyle ida中分析有个两个fun atoi 将字符转换为整数 得到答案为3327105 MD5加密提交 2 Re function 没有提供密码 但是在右边看到熟悉的89 50 利用winhex保存出来 得到解压密码 解压
  • 宝塔登录面板

    请使用正确的入口登录面板 错误原因 当前新安装的已经开启了安全入口登录 新装机器都会随机一个8位字符的安全入口名称 亦可以在面板设置处修改 如您没记录或不记得了 可以使用以下方式解决 解决方法 在SSH终端输入以下一种命令来解决 1 查看面
  • flutter 秒转时分秒

    参考 倒计时工具 class CountdownUtils 补零 static String zeroFill int i return i gt 10 i 0 i 秒转时分秒 static String second2HMS int se
  • 关系数据关联性分析实验

    1 散点图 基于ggplot内置数据mtcars 以mpg列为横坐标 以wt列为纵坐标 以cyl列分组控制颜色 绘制散点图 点的形状为三角形 大小为150 图的标题为 MPG VS WT from ggplot import data gg
  • 【RPA机器人】PDF批量转换成图片机器人

    运行前须知 1 仅支持win10系统 2 请确保安装金山PDF独立版 3 请把屏幕分辨率设置为1920x1080 缩放布局100 4 生成的图片将保存在所选文件夹目录下 运行流程 1 获取需批量转换PDF的文件夹 2 等待文件自动转换 运用
  • Python3中__call__方法介绍

    如果Python3类中有 call 方法 那么此类实例的行为类似于函数并且可以像函数一样被调用 当实例作为函数被调用时 如果定义了此方法 则x arg1 arg2 是x call arg1 arg2 的简写 为了将一个类实例当作函数调用 我
  • 如何实现一个分布锁?

    基本概念 为何需要分布式锁 传统环境中的情况 在程序开发过程中不得不考虑的就是并发问题 在java中对于同一个jvm而言 jdk已经提供了lock和同步等 但是在分布式情况下 往往存在多个进程对一些资源产生竞争关系 而这些进程往往在不同的机