zk源码—4.会话的实现原理一
大纲
1.创建会话
(1)客户端的会话状态
(2)服务端的会话创建
(3)会话ID的初始化实现
(4)设置的会话超时时间没生效的原因
2.分桶策略和会话管理
(1)分桶策略和过期队列
(2)会话激活
(3)会话超时检查
(4)会话清理
1.创建会话
(1)客户端的会话状态
(2)服务端的会话创建
(3)会话ID的初始化实现
(4)设置的会话超时时间没生效的原因
会话是zk中最核心的概念之一,客户端与服务端的交互都离不开会话的相关操作。其中包括临时节点的生命周期、客户端请求的顺序、Watcher通知机制等。比如会话关闭时,服务端会自动删除该会话所创建的临时节点。当客户端会话退出,通过Watcher机制可向订阅该事件的客户端发送通知。
(1)客户端的会话状态
当zk客户端与服务端成功建立连接后,就会创建一个会话。在zk客户端的运行过程(会话生命周期)中,会话会经历不同的状态变化。
这些不同的会话状态包括:正在连接(CONNECTING)、已经连接(CONNECTED)、会话关闭(CLOSE)、正在重新连接(RECONNECTING)、已经重新连接(RECONNECTED)等。
如果zk客户端需要与服务端建立连接创建一个会话,那么客户端就必须提供一个使用字符串表示的zk服务端地址列表。
当客户端刚开始创建ZooKeeper对象时,其会话状态就是CONNECTING,之后客户端会根据服务端地址列表中的IP地址分别尝试进行网络连接。如果成功连接上zk服务端,那么客户端的会话状态就会变为CONNECTED。
如果因为网络闪断或者其他原因造成客户端与服务端之间的连接断开,那么zk客户端会自动进行重连操作,同时其会话状态变为CONNECTING,直到重新连接上zk服务端后,客户端的会话状态才变回CONNECTED。
通常 总是在CONNECTING或CONNECTED间切换。如果出现会话超时、权限检查失败、客户端主动退出程序等情况,那么客户端的会话状态就会直接变为CLOSE。
public class CreateSessionDemo {private final static String CONNECTSTRING = "192.168.1.5:2181";private static CountDownLatch countDownLatch = new CountDownLatch(1);public static void main(String[] args) throws Exception {//创建zkZooKeeper zooKeeper = new ZooKeeper(CONNECTSTRING, 5000, new Watcher() {public void process(WatchedEvent watchedEvent) {//如果当前的连接状态是连接成功, 则通过计数器去控制, 否则进行阻塞, 因为连接是需要时间的//如果已经获得连接了, 那么状态会是SyncConnectedif (watchedEvent.getState() == Event.KeeperState.SyncConnected){countDownLatch.countDown();System.out.println(watchedEvent.getState());}//如果数据发生了变化if (watchedEvent.getType() == Event.EventType.NodeDataChanged) {System.out.println("节点发生了变化, 路径: " + watchedEvent.getPath());}}});//进行阻塞countDownLatch.await();//确定已经获得连接了再进行zk的操作: 增删改查...}
}public class ZooKeeper implements AutoCloseable {protected final ClientCnxn cnxn;protected final ZKWatchManager watchManager;//ZKWatchManager实现了ClientWatchManager...//1.初始化ZooKeeper对象public ZooKeeper(String connectString, int sessionTimeout, Watcher watcher, boolean canBeReadOnly, HostProvider aHostProvider, ZKClientConfig clientConfig) throws IOException {...//创建客户端的Watcher管理器ZKWatchManagerwatchManager = defaultWatchManager();//2.设置会话默认的Watcher,保存在客户端的Watcher管理器ZKWatchManager中watchManager.defaultWatcher = watcher;ConnectStringParser connectStringParser = new ConnectStringParser(connectString);//3.构造服务器地址列表管理器StaticHostProviderhostProvider = aHostProvider;//4.创建并初始化客户端的网络连接器ClientCnxn + 5.初始化SendThread和EventThreadcnxn = createConnection(connectStringParser.getChrootPath(), hostProvider, sessionTimeout, this, watchManager, getClientCnxnSocket(), canBeReadOnly);//6.启动SendThread和EventThreadcnxn.start();}protected ClientCnxn createConnection(String chrootPath, HostProvider hostProvider, int sessionTimeout, ZooKeeper zooKeeper, ClientWatchManager watcher, ClientCnxnSocket clientCnxnSocket, boolean canBeReadOnly) throws IOException { return new ClientCnxn(chrootPath, hostProvider, sessionTimeout, this, watchManager, clientCnxnSocket, canBeReadOnly);}//从配置中获取客户端使用的网络连接配置:使用NIO还是Netty,然后通过反射进行实例化客户端Socketprivate ClientCnxnSocket getClientCnxnSocket() throws IOException {String clientCnxnSocketName = getClientConfig().getProperty(ZKClientConfig.ZOOKEEPER_CLIENT_CNXN_SOCKET);if (clientCnxnSocketName == null) {clientCnxnSocketName = ClientCnxnSocketNIO.class.getName();}Constructor<?> clientCxnConstructor = Class.forName(clientCnxnSocketName).getDeclaredConstructor(ZKClientConfig.class);ClientCnxnSocket clientCxnSocket = (ClientCnxnSocket) clientCxnConstructor.newInstance(getClientConfig());return clientCxnSocket;}public enum States {//客户端的会话状态包括CONNECTING, ASSOCIATING, CONNECTED, CONNECTEDREADONLY,CLOSED, AUTH_FAILED, NOT_CONNECTED;public boolean isAlive() {return this != CLOSED && this != AUTH_FAILED;}public boolean isConnected() {return this == CONNECTED || this == CONNECTEDREADONLY;}}...static class ZKWatchManager implements ClientWatchManager {private final Map<String, Set<Watcher>> dataWatches = new HashMap<String, Set<Watcher>>();private final Map<String, Set<Watcher>> existWatches = new HashMap<String, Set<Watcher>>();private final Map<String, Set<Watcher>> childWatches = new HashMap<String, Set<Watcher>>();protected volatile Watcher defaultWatcher;...}protected ZKWatchManager defaultWatchManager() {//创建客户端的Watcher管理器ZKWatchManagerreturn new ZKWatchManager(getClientConfig().getBoolean(ZKClientConfig.DISABLE_AUTO_WATCH_RESET));}...
}public class ClientCnxn {...volatile States state = States.NOT_CONNECTED;private final HostProvider hostProvider;public ClientCnxn(String chrootPath, HostProvider hostProvider, int sessionTimeout, ZooKeeper zooKeeper, ClientWatchManager watcher, ClientCnxnSocket clientCnxnSocket, long sessionId, byte[] sessionPasswd, boolean canBeReadOnly) {...this.hostProvider = hostProvider;//5.初始化SendThread和EventThreadsendThread = new SendThread(clientCnxnSocket);eventThread = new EventThread();...}//6.启动SendThread和EventThreadpublic void start() {sendThread.start();eventThread.start();}class SendThread extends ZooKeeperThread {private final ClientCnxnSocket clientCnxnSocket;...SendThread(ClientCnxnSocket clientCnxnSocket) {super(makeThreadName("-SendThread()"));//客户端刚开始创建ZooKeeper对象时,设置其会话状态为CONNECTINGstate = States.CONNECTING;this.clientCnxnSocket = clientCnxnSocket;//设置为守护线程setDaemon(true);}@Overridepublic void run() {...while (state.isAlive()) {...//7.获取其中一个zk服务端的地址serverAddress = hostProvider.next(1000);//向zk服务端发起连接请求startConnect(serverAddress);...}...}private void startConnect(InetSocketAddress addr) throws IOException {...state = States.CONNECTING;//8.创建TCP连接//接下来以ClientCnxnSocketNetty的connect为例clientCnxnSocket.connect(addr);}void onConnected(int _negotiatedSessionTimeout, long _sessionId, byte[] _sessionPasswd, boolean isRO) throws IOException {...//和服务端建立连接后的处理state = (isRO) ? States.CONNECTEDREADONLY : States.CONNECTED;...}...}
}public class ClientCnxnSocketNetty extends ClientCnxnSocket {//向zk服务端发起建立连接的请求@Overridevoid connect(InetSocketAddress addr) throws IOException {...Bootstrap bootstrap = new Bootstrap().group(eventLoopGroup).channel(NettyUtils.nioOrEpollSocketChannel()).option(ChannelOption.SO_LINGER, -1).option(ChannelOption.TCP_NODELAY, true).handler(new ZKClientPipelineFactory(addr.getHostString(), addr.getPort()));bootstrap = configureBootstrapAllocator(bootstrap);bootstrap.validate();connectFuture = bootstrap.connect(addr);...}private class ZKClientHandler extends SimpleChannelInboundHandler<ByteBuf> {...@Overrideprotected void channelRead0(ChannelHandlerContext ctx, ByteBuf buf) throws Exception {...//与zk服务端建立好连接后的处理,调用父类ClientCnxnSocket的readConnectResult()方法readConnectResult();...}...}...
}abstract class ClientCnxnSocket {void readConnectResult() throws IOException {...sendThread.onConnected(conRsp.getTimeOut(), this.sessionId, conRsp.getPasswd(), isRO);}...
}
(2)服务端的会话创建
在zk服务端中,使用SessionImpl表示客户端与服务器端连接的会话实体。SessionImpl由三个部分组成:会话ID(sessionID)、会话超时时间(timeout)、会话关闭状态(isClosing)。
一.会话ID
会话ID是一个会话的标识符,当创建一次会话时,zk服务端会自动为其分配一个唯一的ID。
二.会话超时时间
一个会话的超时时间就是指一次会话从发起后到被服务器关闭的时长。设置会话超时时间后,zk服务端会参考设置的超时时间,最终计算一个服务端自己的超时时间。这个超时时间才是真正被zk服务端用于管理用户会话的超时时间。
三.会话关闭状态
会话关闭状态isClosing表示一个会话是否已经关闭。如果zk服务端检查到一个会话已经因为超时等原因失效时,就会将该会话的isClosing标记为关闭,之后就不再对该会话进行操作。
public class SessionTrackerImpl extends ZooKeeperCriticalThread implements SessionTracker {...public static class SessionImpl implements Session {SessionImpl(long sessionId, int timeout) {this.sessionId = sessionId;this.timeout = timeout;isClosing = false;}final long sessionId;//会话IDfinal int timeout;//会话超时时间boolean isClosing;//会话关闭状态...}...
}
服务端收到客户端的创建会话请求后,进行会话创建的过程大概分四步:处理ConnectRequest请求、创建会话、请求处理链处理和会话响应。
步骤一:处理ConnectRequest请求
首先由NettyServerCnxn负责接收来自客户端的创建会话请求,然后反序列化出ConnectRequest对象,并完成会话超时时间的协商。
步骤二:创建会话
SessionTrackerImpl的createSession()方法会为该会话分配一个sessionID,并将该sessionID注册到sessionsById和sessionsWithTimeout中,同时通过SessionTrackerImpl的updateSessionExpiry()方法进行会话激活。
步骤三:请求处理链处理
接着调用ZooKeeperServer.firstProcessor的processRequest()方法,让该会话请求会在zk服务端的各个请求处理器之间进行顺序流转。
步骤四:会话响应
最后在请求处理器FinalRequestProcessor的processRequest()方法中进行会话响应。
//由网络连接工厂类监听到客户端的创建会话请求
public class NettyServerCnxnFactory extends ServerCnxnFactory {class CnxnChannelHandler extends ChannelDuplexHandler {@Overridepublic void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {...NettyServerCnxn cnxn = ctx.channel().attr(CONNECTION_ATTRIBUTE).get();cnxn.processMessage((ByteBuf) msg);...}...}...
}public class NettyServerCnxn extends ServerCnxn {private volatile ZooKeeperServer zkServer;void processMessage(ByteBuf buf) {...receiveMessage(buf);...}private void receiveMessage(ByteBuf message) {...ZooKeeperServer zks = this.zkServer;//处理会话连接请求zks.processConnectRequest(this, bb);...}...
}public class ZooKeeperServer implements SessionExpirer, ServerStats.Provider {protected SessionTracker sessionTracker;...public synchronized void startup() {startupWithServerState(State.RUNNING);}private void startupWithServerState(State state) {//创建并启动会话管理器if (sessionTracker == null) {createSessionTracker();}startSessionTracker();//初始化请求处理链setupRequestProcessors();...}protected void createSessionTracker() {sessionTracker = new SessionTrackerImpl(this, zkDb.getSessionWithTimeOuts(), tickTime, createSessionTrackerServerId, getZooKeeperServerListener());}public void processConnectRequest(ServerCnxn cnxn, ByteBuffer incomingBuffer) throws IOException {//步骤一:处理ConnectRequest请求BinaryInputArchive bia = BinaryInputArchive.getArchive(new ByteBufferInputStream(incomingBuffer));ConnectRequest connReq = new ConnectRequest();connReq.deserialize(bia, "connect");...//协商会话超时时间int sessionTimeout = connReq.getTimeOut();byte passwd[] = connReq.getPasswd();int minSessionTimeout = getMinSessionTimeout();if (sessionTimeout < minSessionTimeout) {sessionTimeout = minSessionTimeout;}int maxSessionTimeout = getMaxSessionTimeout();if (sessionTimeout > maxSessionTimeout) {sessionTimeout = maxSessionTimeout;}cnxn.setSessionTimeout(sessionTimeout);...long sessionId = connReq.getSessionId();if (sessionId == 0) {//步骤二:创建会话long id = createSession(cnxn, passwd, sessionTimeout);} else {long clientSessionId = connReq.getSessionId();if (serverCnxnFactory != null) {serverCnxnFactory.closeSession(sessionId);}if (secureServerCnxnFactory != null) {secureServerCnxnFactory.closeSession(sessionId);}cnxn.setSessionId(sessionId);reopenSession(cnxn, sessionId, passwd, sessionTimeout);}}long createSession(ServerCnxn cnxn, byte passwd[], int timeout) {if (passwd == null) {passwd = new byte[0];}//通过会话管理器创建会话long sessionId = sessionTracker.createSession(timeout);Random r = new Random(sessionId ^ superSecret);r.nextBytes(passwd);ByteBuffer to = ByteBuffer.allocate(4);to.putInt(timeout);cnxn.setSessionId(sessionId);Request si = new Request(cnxn, sessionId, 0, OpCode.createSession, to, null);setLocalSessionFlag(si);//激活会话 + 提交请求到请求处理链进行处理submitRequest(si);return sessionId;}public void submitRequest(Request si) {...//激活会话touch(si.cnxn);//步骤三:交给请求处理链进行处理,在FinalRequestProcessor中会进行会话响应firstProcessor.processRequest(si);...}...
}public class SessionTrackerImpl extends ZooKeeperCriticalThread implements SessionTracker {...private final AtomicLong nextSessionId = new AtomicLong();private final ExpiryQueue<SessionImpl> sessionExpiryQueue;public SessionTrackerImpl(SessionExpirer expirer, ConcurrentMap<Long, Integer> sessionsWithTimeout, int tickTime, long serverId, ZooKeeperServerListener listener) {super("SessionTracker", listener);this.expirer = expirer;this.sessionExpiryQueue = new ExpiryQueue<SessionImpl>(tickTime);this.sessionsWithTimeout = sessionsWithTimeout;//初始化SessionIdthis.nextSessionId.set(initializeNextSession(serverId));for (Entry<Long, Integer> e : sessionsWithTimeout.entrySet()) {addSession(e.getKey(), e.getValue());}EphemeralType.validateServerId(serverId);}...public long createSession(int sessionTimeout) {//为会话分配一个sessionIDlong sessionId = nextSessionId.getAndIncrement();//将sessionID注册到sessionsById和sessionsWithTimeout中addSession(sessionId, sessionTimeout);return sessionId;}public synchronized boolean addSession(long id, int sessionTimeout) {sessionsWithTimeout.put(id, sessionTimeout);boolean added = false;SessionImpl session = sessionsById.get(id);if (session == null) {session = new SessionImpl(id, sessionTimeout);}SessionImpl existedSession = sessionsById.putIfAbsent(id, session);if (existedSession != null) {session = existedSession;} else {added = true;LOG.debug("Adding session 0x" + Long.toHexString(id));}...updateSessionExpiry(session, sessionTimeout);return added;}private void updateSessionExpiry(SessionImpl s, int timeout) {...sessionExpiryQueue.update(s, timeout);}...
}public class FinalRequestProcessor implements RequestProcessor {...public void processRequest(Request request) {...ServerCnxn cnxn = request.cnxn;//步骤四:会话响应cnxn.sendResponse(hdr, rsp, "response");...}...
}public abstract class ServerCnxn implements Stats, Watcher {...public void sendResponse(ReplyHeader h, Record r, String tag) throws IOException {ByteArrayOutputStream baos = new ByteArrayOutputStream();BinaryOutputArchive bos = BinaryOutputArchive.getArchive(baos);try {baos.write(fourBytes);bos.writeRecord(h, "header");if (r != null) {bos.writeRecord(r, tag);}baos.close();} catch (IOException e) {LOG.error("Error serializing response");}byte b[] = baos.toByteArray();serverStats().updateClientResponseSize(b.length - 4);ByteBuffer bb = ByteBuffer.wrap(b);bb.putInt(b.length - 4).rewind();sendBuffer(bb);}...
}public class NettyServerCnxn extends ServerCnxn {...@Overridepublic void sendBuffer(ByteBuffer sendBuffer) {if (sendBuffer == ServerCnxnFactory.closeConn) {close();return;}channel.writeAndFlush(Unpooled.wrappedBuffer(sendBuffer)).addListener(onSendBufferDoneListener);}...
}
(3)会话ID的初始化实现
SessionTracker是zk服务端的会话管理器,zk会话的整个生命周期都离不开SessionTracker的参与。SessionTracker是一个接口类型,规定了会话管理的相关操作行为,具体的会话管理逻辑则由SessionTrackerImpl来完成。
SessionTrackerImpl类实现了SessionTracker接口,其中有四个关键字段:sessionExpiryQueue字段表示的是会话过期队列,用于管理会话自动过期。nextSessionId字段记录了当前生成的会话ID。sessionsById字段用于根据会话ID来管理具体的会话实体。sessionsWithTimeout字段用于根据会话ID管理会话的超时时间。
在SessionTrackerImpl类初始化时,会调用initializeNextSession()方法来生成一个初始化的会话ID。之后在zk的运行过程中,会在该会话ID的基础上为每个会话分配ID。
public class SessionTrackerImpl extends ZooKeeperCriticalThread implements SessionTracker {...private final ExpiryQueue<SessionImpl> sessionExpiryQueue;//过期队列private final AtomicLong nextSessionId = new AtomicLong();//当前生成的会话IDConcurrentHashMap<Long, SessionImpl> sessionsById;//根据会话ID来管理具体的会话实体ConcurrentMap<Long, Integer> sessionsWithTimeout;//根据不同的会话ID管理每个会话的超时时间public SessionTrackerImpl(SessionExpirer expirer, ConcurrentMap<Long, Integer> sessionsWithTimeout, int tickTime, long serverId, ZooKeeperServerListener listener) {super("SessionTracker", listener);this.expirer = expirer;this.sessionExpiryQueue = new ExpiryQueue<SessionImpl>(tickTime);this.sessionsWithTimeout = sessionsWithTimeout;//初始化SessionIdthis.nextSessionId.set(initializeNextSession(serverId));for (Entry<Long, Integer> e : sessionsWithTimeout.entrySet()) {addSession(e.getKey(), e.getValue());}EphemeralType.validateServerId(serverId);}public static long initializeNextSession(long id) {long nextSid;nextSid = (Time.currentElapsedTime() << 24) >>> 8;nextSid = nextSid | (id <<56);return nextSid;}...
}
在SessionTrackerImpl的initializeNextSession()方法中,生成初始化的会话ID的过程如下:
步骤一:获取当前时间的毫秒表示
步骤二:将得到的毫秒表示的时间先左移24位
步骤三:将左移24位后的结果再右移8位
步骤四:服务器SID左移56位
步骤五:将右移8位的结果和左移56位的结果进行位与运算
算法概述:高8位确定所在机器,低56位使用当前时间的毫秒表示来进行随机。
其中左移24位的目的是:将毫秒表示的时间的最高位的1移出,可以防止出现负数。
//时间的二进制表示,41位
10100000110000011110001000100110111110111
//左移24位变成,64位
0100000110000011110001000100110111110111000000000000000000000000
//右移8位变成,64位
0000000001000001100000111100010001001101111101110000000000000000
//假设服务器SID为2,那么左移56位变成
0000001000000000000000000000000000000000000000000000000000000000
//位与运算
0000001001000001100000111100010001001101111101110000000000000000
(4)设置的会话超时时间没生效的原因
在平时的开发工作中,最常遇到的场景就是会话超时异常。zk的会话超时异常包括:客户端readTimeout异常和服务端sessionTimeout异常。
需要注意的是:可能虽然设置了超时时间,但实际服务运行时zk并没有按设置的超时时间来管理会话。
这是因为实际起作用的超时时间是由客户端和服务端协商决定的。zk客户端在和服务端建立连接时,会提交一个客户端设置的会话超时时间,而该超时时间会和服务端设置的最大超时时间和最小超时时间进行比较。如果正好在服务端设置允许的范围内,则采用客户端的超时时间管理会话。如果大于或小于服务端设置的超时时间,则采用服务端的超时时间管理会话。
相关文章:
zk源码—4.会话的实现原理一
大纲 1.创建会话 (1)客户端的会话状态 (2)服务端的会话创建 (3)会话ID的初始化实现 (4)设置的会话超时时间没生效的原因 2.分桶策略和会话管理 (1)分桶策略和过期队列 (2)会话激活 (3)会话超时检查 (4)会话清理 1.创建会话 (1)客户端的会话状态 (2)服务端的会话创建…...
快排算法 (分治实现)
本算法采用将整个数组划分成三个部分 <key key >key 在数组全是同一个数字时,也能达到NlogN的时间复杂度 下面的板书中i为遍历数组的下标 left为<key的最右边的下标 right为>key的最左边的下标 例题1:912. 排序数组 - 力扣࿰…...
P9242 [蓝桥杯 2023 省 B] 接龙数列
这道题说要求最少删多少个使剩下的序列是接龙序列,这个问题可以转换为序列中最长的接龙序列是多少,然后用总长度减去最长接龙序列的长度就可以了,在第一个暴力版本的代码中我用了两个for循环求出了所有的接龙序列的长度,但是会超时…...
未来 AI 发展趋势与挑战(AGI、数据安全、监管政策)
从 ChatGPT 的火爆到国内 DeepSeek、通义千问、百川智能等模型的兴起,AI 正以前所未有的速度走入各行各业。而下一阶段,AI 是否会发展出真正的“通用智能”(AGI)?数据隐私、技术伦理又该如何应对?本文将带你全面洞察未来 AI 的技术趋势与落地挑战。 一、AGI 的曙光:通用…...
驱动开发硬核特训 · Day 6 : 深入解析设备模型的数据流与匹配机制 —— 以 i.MX8M 与树莓派为例的实战对比
🔍 B站相应的视屏教程: 📌 内核:博文视频 - 从静态绑定驱动模型到现代设备模型 主题:深入解析设备模型的数据流与匹配机制 —— 以 i.MX8M 与树莓派为例的实战对比 在上一节中,我们从驱动框架的历史演进出…...
MyBatis 动态 SQL 使用详解
🌟 一、什么是动态 SQL? 动态 SQL 是指根据传入参数,动态拼接生成 SQL 语句,不需要写多个 SQL 方法。MyBatis 提供了 <if>、<choose>、<foreach>、<where> 等标签来实现这类操作 ✅ 二、动态 SQL 的优点…...
数据结构实验4.1:链队列的基本操作
文章目录 一,问题描述二,基本要求三,算法分析链队列的存储结构设计基本操作的算法分析 四,示例代码五,实验操作六,运行效果 一,问题描述 编程实现有关链队列的下列基本操作。 (1&am…...
独立部署及使用Ceph RBD块存储
Ceph RBD(RADOS Block Device) 是 Ceph 分布式存储系统中的块存储组件,类似于 AWS EBS、iSCSI 等。它独立于 OpenShift 或 IBM CP4BA,是一个分布式存储系统,提供高性能、可扩展性和容错能力,适用于数据库、…...
C++初阶-C++入门基础
目录 编辑 1.C的简介 1.1C的产生和发展 1.2C的参考文档 1.3C优势和难度 1.4C学习的建议 2.C的第一个程序 2.1打印Hello world 2.2头文件 2.3namespace命名空间 2.4::作用域限定符 2.5namespace的延伸 2.6C的输入输出 3.总结 1.C的简介 …...
部署大模型不再难:DeepSeek + 腾讯云 HAI 实战教程
网罗开发 (小红书、快手、视频号同名) 大家好,我是 展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等…...
算法训练之位运算
♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥ ♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥ ♥♥♥我们一起努力成为更好的自己~♥♥♥ ♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥ ♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥ ✨✨✨✨✨✨ 个…...
初识Linux:常见指令与权限的理解,以及相关衍生知识
目录 前言 关于linux的简介 代码开源 网络功能强大 系统工具链完整 一、Linux下的基本指令 1.ls指令 2.pwd指令 3.cd指令 4.whoami指令 5.touch指令 6.mkdir指令 7.rm指令 8.man指令 9.cp指令 10.mv指令 11.nano指令 12.cat指令 13.tac指令 14.more指令 15.less指令 16.head指令…...
PostgreSQL-数据库的索引 pg_operator_oid_index 损坏
报错信息: 连接测试失败 Error connecting to database: Connection failed: ERROR: index "pg_operator_oid_index" contains unexpected zero page at block 3 Hint: Please REINDEX it. 这个错误表明 PostgreSQL 数据库的索引 pg_operator_oid_index …...
数字图像处理作业4
数字图像处理 作业4 Project 4:Image Restoration The scoring method for this project is as follows: 1.Implement a blurring filter using the equation(5.6-11,数字图像处理(…...
Simulink中Signal Builder在新版中找不到怎么办
在较新的MATLAB版本中,新版Simulink中的Signal Builder用Signal Editor作为替代工具。 signal builder not shown in matlab - MATLAB Answers - MATLAB Central signalBuilderToSignalEditor 1.打开上面第二个链接 2.点击拷贝 3.然后在命令行中粘贴 4.然后就会…...
STM32——RTC实时时钟
RTC简介 RTC(Real Time Clock, RTC)实时时钟,其本质是一个计数器,计数频率常为秒,专门用来记录时间。 其具有能提供时间(秒钟数),能在MCU掉电后运行,低功耗的特性 内部框图 1. RTC预分频器 2. …...
sqli-labs靶场 less4
文章目录 sqli-labs靶场less 4 联合注入 sqli-labs靶场 每道题都从以下模板讲解,并且每个步骤都有图片,清晰明了,便于复盘。 sql注入的基本步骤 注入点注入类型 字符型:判断闭合方式 (‘、"、’、“”…...
指针数组 vs 数组指针
一、指针数组:「数组装指针」—— 每个元素都是指针 🔍 核心定义 语法:类型* 数组名[长度]; ([]优先级高于*,先形成数组,元素是指针)本质:一个 数组,数组的每个元素是 …...
GitHub优秀项目:数据湖的管理系统LakeFS
lakeFS 是一个开源工具,它将用户的对象存储转换为类似Git的存储库。使用户可以像管理代码一样管理数据湖。借助 lakeFS,可以构建可重复、原子化和版本化的数据湖操作--从复杂的ETL作业到数据科学和分析。 Stars 数11090Forks 数3157 主要特点 强大的数据…...
数据库视图讲解(view)
一、为什么需要视图 二、视图的讲解 三、总结 一、为什么需要视图 视图一方面可以帮我们使用表的一部分而不是所有的表,另一方面也可以针对不同的用户制定不同的查询视图。 比如,针对一个公司的销售人员,我们只想给他看部分数据,…...
pip install pytrec_eval失败的解决方案
1、问题描述 在使用华为云 notebook 的时候,想要: !pip install transformer结果失败,阅读报错后,疑似是 pytrec_eval 库的下载问题。 于是,单独尝试: !pip install pytrec_eval发现确实是这个库安装失…...
使用stream的Collectors.toMap()方法常见问题
文章目录 一、常见问题二、key重复问题2.1、报错示例2.2、解决方法 三、value为空问题3.1、报错示例3.2、解决方法3.1、方案一3.2、方案二 一、常见问题 stream的Collectors.toMap()方法常见问题: 1、 key不能有重复,否则会报错。java.lang.IllegalStat…...
[C++面试] 初始化相关面试点深究
一、入门 1、C中基础类型的初始化方式有哪些?请举例说明 默认初始化 对于全局变量和静态变量,基础类型(如int、float、double等)会被初始化为 0;而对于局部变量,其值是未定义的,包含随机…...
ChatDBA:一个基于AI的智能数据库助手
今天给大家介绍一个基于 AI 大语言模型实现数据库故障诊断的智能助手:ChatDBA。 ChatDBA 是由上海爱可生信息技术股份有限公司开发,通过对话交互,提供数据库故障诊断、专业知识学习、SQL 生成和优化等功能,旨在提升 DBA 工作效率。…...
Java延迟队列
📌 1. 场景背景 最近做项目,使用到了延迟队列。场景是这样的:在在线视频学习中,学生每隔几秒上报当前学习进度,为避免频繁写数据库、提升性能,采用以下方案: 先写入 Redis,再延迟一…...
神舟平板电脑怎么样?平板电脑能当电脑用吗?
在如今的数码产品市场上,神舟平板电脑会拥有独特的优势,其中比较受到大家关注的就是神舟PCpad为例,无论是设计还是规格也会有很多的亮点,那么是不是可以直接当成电脑一起来使用呢? 这款平板电脑就会配备10.1英寸显示屏…...
Ansible的使用3
#### 一、Ansible补充模块 try () { } catch () { } finally 等同于 block () { } rescue () { } always ##### 任务块 - block任务块 - 通过block关键字,将多个任务组合到一起 - 将整个block任务组,一…...
PS教学记录
PS制作手机壁纸和电脑壁纸 1. 思绪来源 找到了一位B站UP,分享了有关于灰原哀的动态壁纸。自身( •̀ ω •́ )也是名侦探柯南的爱好者,在此基础上,萌生了制作壁纸的想法。便在B站上搜寻有关于壁纸制作的教学。找到了一位壁纸分享者的教程镜…...
分析一下HashMap内部是怎么实现的
当然可以!我们来深入分析一下 Java 中 HashMap 的内部实现机制(以 JDK 8 为主),包括数据结构、核心算法、源码设计、以及适用场景。 🧠 一、HashMap 的核心结构 HashMap 是基于哈希表实现的 Map,底层结构是…...
面向对象的要素
理解面向对象 程序的三种基本结构 (1)顺序结构 (2)选择结构 (3)循环结构 面向对象程序设计简介 面向对象是一种更优秀的程序设计方法,它的基本思想是使用类、对象、继承、封装、消息等基本…...
Java基础 4.9
1.方法递归调用练习 //请使用递归的方式求出斐波那契数1, 1, 2, 3, 5, 8, 13 //给你一个整数n, 求出它的值是多少 /* 思路 n 1 1 n 2 1 n > 3 前两个数的和 递归的思路 */ public class RecursionExercise01 {public static void main(String[] args) {Mathod mathod ne…...
什么是堆?深入理解堆数据结构及其应用
粉丝提问 ⭐算法OJ⭐数据流的中位数【最小堆】Find Median from Data Stream 发表后收到一位粉丝的私信询问: “经常听说堆、堆排序、优先队列这些概念,但一直不太明白堆到底是什么,能简单解释一下吗?它和内存分配中的堆是一回事…...
程序化广告行业(73/89):买卖双方需求痛点及应对策略深度剖析
程序化广告行业(73/89):买卖双方需求痛点及应对策略深度剖析 大家好!一直以来,我都热衷于在技术领域探索学习,也深知知识的分享能让我们共同进步。写这篇博客的目的,就是希望能和大家一起深入了…...
C++ RAII 的用途及业务代码实现案例
C RAII 的用途及业务代码实现案例 RAII 的核心概念 RAII (Resource Acquisition Is Initialization,资源获取即初始化) 是 C 的核心编程范式,其核心思想是: 资源获取与对象构造绑定资源释放与对象析构绑定利用 C 对象生命周期自动管理资源…...
神经网络入门—自定义神经网络续集
修改网络 神经网络入门—自定义网络-CSDN博客 修改数据集,yx^2 # 生成一些示例数据 x_train torch.tensor([[1.0], [2.0], [3.0], [4.0]], dtypetorch.float32) y_train torch.tensor([[1.0], [4.0], [9.0], [16.0]], dtypetorch.float32) 将预测代码改为&…...
【C语言】浮点数在内存的储存
前言: 在上章,了解了整数在内存中的储存,在本章节为大家继续讲解浮点数的储存,也是数据储存的最后一部分。 浮点数是计算机科学中一种重要的数据类型,用于表示实数。它能够表示非常大或非常小的数值,并且…...
安装 Calico 的两种主流方式对比
本文对比了 Calico 的两种主流安装方式: 使用 calico.yaml 的 Manifest 安装方式使用 Tigera Operator(tigera-operator.yaml custom-resources.yaml)安装方式 ✅ 1. 使用 Manifest 方式安装(直接部署 calico.yaml) …...
信用卡欺诈检测实战教程:从数据预处理到模型优化全解析
引言:为什么需要信用卡欺诈检测? 根据尼尔森报告,全球每年因信用卡欺诈造成的损失超过250亿美元,金融机构需要在0.1秒内完成交易风险评估。本文将带您从零构建基于机器学习的信用卡欺诈检测系统,完整代码可视化分析&a…...
android studio编译报错 Gradle
android studio 提示 Could not install Gradle distribution from https://services.gradle.org/distributions/gradle-8.0.2-bin.zip. Reason: java.net.SocketTimeoutException: Read timed out 一,手动下载 https://services.gradle.org/distributions/gradle…...
【Nodebb系列】Nodebb笔记写入方案
NodeBB写入方案 前言 最近在整理以前记录的碎片笔记,想把它们汇总到NodeBB中,方便管理和浏览。但是笔记内容有点多,并且用发帖的形式写到NodeBB中会丢失时间信息,因此整理了一套NodeBB写入方案,大致流程如下: 建立标准笔记格式导出原始笔记,并编写脚本将笔记内容转换为…...
Spring Boot 集成 POI
Spring Boot 集合 POI Apache POI 官站:https://poi.apache.org/ 基础概念 Apache POI 是一个开源项目,提供 Java API 用于操作 Microsoft Office 文件格式。Apache POI 对 Excel 文件的处理分为两个主要类库: HSSF (Horrible Spreadsheet …...
8个方向使用DeepSeek打磨完美课题申报书!
一份出色的课题申报书,往往就是项目获批的关键。撰写高质量课题申报书绝非易事,它需要您在选题切入点、研究价值论证、技术路线设计、团队优势呈现、经费规划和预期成果等多维度进行精心布局,确保论证有力、重点突出、结构清晰。 本文为您提供…...
Leetcode 34.在排序数组中查找元素的第一个和最后一个位置
题目描述 给你一个按照非递减顺序排列的整数数组 nums,和一个目标值 target。请你找出给定目标值在数组中的开始位置和结束位置。 如果数组中不存在目标值 target,返回 [-1, -1]。 你必须设计并实现时间复杂度为 O(log n) 的算法解决此问题。 考察二…...
ctfshow VIP题目限免 密码逻辑脆弱
根据题目提示:公开的信息比如邮箱,可能造成信息泄露,产生严重后果 在页面上找一个邮箱号 从 QQ 上面搜索这个 QQ号,发现是一个叫大牛的人,地区是陕西西安 然后我们拼接访问 /admin 发现了一个后台登录系统的页面&…...
C++初级入门学习
数据结构初级部分的学习我们已经学完了,接下来就进入C初阶部分的学习,因为数据结构的高阶部分要用到C才能够更好的理解并书写,所以我们要先学习C,初阶部分学完就能继续学习我们对数据结构了。好了,直接进入今天的主题吧…...
2025年汽车加气站操作工证考试内容
汽车加气站操作工证是从事汽车加气站相关操作工作的人员需要考取的资格证书 考试内容 理论知识:包括加气站的工艺流程、设备原理、安全操作规程、气体性质、消防知识、环境保护等方面的知识。例如,需要了解压缩天然气或液化天然气的储存、运输和加注流…...
python爬虫:喜马拉雅案例(破解sign值)
声明: 本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关ÿ…...
嵌入式AI前沿:精选工具与应用网站解析
1. Edge Impulse 网址:https://www.edgeimpulse.com/核心内容: 提供端到端的嵌入式AI开发平台,简化从数据收集到模型训练再到部署的全流程。支持多模态数据处理(音频、视觉、运动等),并优化模型以在资源受…...
【论文精读】Multi-scale Neighbourhood Feature Interaction Network
摘要(ABSTRACT) 光伏发电是工业领域的关键组成部分,其能量转换效率受光伏电池表面缺陷的显著影响。近年来,深度学习模型的广泛应用推动了缺陷检测技术的进步。然而,由于光伏电池缺陷尺寸差异较大(尤其是微…...
C++ 蓝桥云课代码练习
代码一 ,小明的背包1,代码见下 #include <iostream> #include <cstring> using namespace std;#define maxn 110 #define maxm 1001 #define inf -1int w[maxn], v[maxn]; int dp[maxn][maxm];int main() {memset(dp, inf, sizeof(dp));dp[…...