当前位置: 首页 > news >正文

网站建设企业咨询/网站建设全网营销

网站建设企业咨询,网站建设全网营销,公众平台的微信网站开发,斜杠青年seo工作室序 本文主要研究一下AsyncHttpClient的ChannelPool ChannelPool org/asynchttpclient/channel/ChannelPool.java public interface ChannelPool {/*** Add a channel to the pool** param channel an I/O channel* param partitionKey a key used to retrieve the cac…

本文主要研究一下AsyncHttpClient的ChannelPool

ChannelPool

org/asynchttpclient/channel/ChannelPool.java

public interface ChannelPool {/*** Add a channel to the pool** @param channel      an I/O channel* @param partitionKey a key used to retrieve the cached channel* @return true if added.*/boolean offer(Channel channel, Object partitionKey);/*** Remove the channel associated with the uri.** @param partitionKey the partition used when invoking offer* @return the channel associated with the uri*/Channel poll(Object partitionKey);/*** Remove all channels from the cache. A channel might have been associated* with several uri.** @param channel a channel* @return the true if the channel has been removed*/boolean removeAll(Channel channel);/*** Return true if a channel can be cached. A implementation can decide based* on some rules to allow caching Calling this method is equivalent of* checking the returned value of {@link ChannelPool#offer(Channel, Object)}** @return true if a channel can be cached.*/boolean isOpen();/*** Destroy all channels that has been cached by this instance.*/void destroy();/*** Flush partitions based on a predicate** @param predicate the predicate*/void flushPartitions(Predicate<Object> predicate);/*** @return The number of idle channels per host.*/Map<String, Long> getIdleChannelCountPerHost();
}

ChannelPool定义了offer、poll、removeAll、isOpen、destroy、flushPartitions、getIdleChannelCountPerHost方法,它有两个实现类,分别是NoopChannelPool及DefaultChannelPool

NoopChannelPool

org/asynchttpclient/channel/NoopChannelPool.java

public enum NoopChannelPool implements ChannelPool {INSTANCE;@Overridepublic boolean offer(Channel channel, Object partitionKey) {return false;}@Overridepublic Channel poll(Object partitionKey) {return null;}@Overridepublic boolean removeAll(Channel channel) {return false;}@Overridepublic boolean isOpen() {return true;}@Overridepublic void destroy() {}@Overridepublic void flushPartitions(Predicate<Object> predicate) {}@Overridepublic Map<String, Long> getIdleChannelCountPerHost() {return Collections.emptyMap();}
}

NoopChannelPool是个枚举,用枚举实现了单例,其方法默认为空操作

DefaultChannelPool

/*** A simple implementation of {@link ChannelPool} based on a {@link java.util.concurrent.ConcurrentHashMap}*/
public final class DefaultChannelPool implements ChannelPool {private static final Logger LOGGER = LoggerFactory.getLogger(DefaultChannelPool.class);private final ConcurrentHashMap<Object, ConcurrentLinkedDeque<IdleChannel>> partitions = new ConcurrentHashMap<>();private final ConcurrentHashMap<ChannelId, ChannelCreation> channelId2Creation;private final AtomicBoolean isClosed = new AtomicBoolean(false);private final Timer nettyTimer;private final int connectionTtl;private final boolean connectionTtlEnabled;private final int maxIdleTime;private final boolean maxIdleTimeEnabled;private final long cleanerPeriod;private final PoolLeaseStrategy poolLeaseStrategy;public DefaultChannelPool(AsyncHttpClientConfig config, Timer hashedWheelTimer) {this(config.getPooledConnectionIdleTimeout(),config.getConnectionTtl(),hashedWheelTimer,config.getConnectionPoolCleanerPeriod());}public DefaultChannelPool(int maxIdleTime,int connectionTtl,Timer nettyTimer,int cleanerPeriod) {this(maxIdleTime,connectionTtl,PoolLeaseStrategy.LIFO,nettyTimer,cleanerPeriod);}public DefaultChannelPool(int maxIdleTime,int connectionTtl,PoolLeaseStrategy poolLeaseStrategy,Timer nettyTimer,int cleanerPeriod) {this.maxIdleTime = maxIdleTime;this.connectionTtl = connectionTtl;connectionTtlEnabled = connectionTtl > 0;channelId2Creation = connectionTtlEnabled ? new ConcurrentHashMap<>() : null;this.nettyTimer = nettyTimer;maxIdleTimeEnabled = maxIdleTime > 0;this.poolLeaseStrategy = poolLeaseStrategy;this.cleanerPeriod = Math.min(cleanerPeriod, Math.min(connectionTtlEnabled ? connectionTtl : Integer.MAX_VALUE, maxIdleTimeEnabled ? maxIdleTime : Integer.MAX_VALUE));if (connectionTtlEnabled || maxIdleTimeEnabled)scheduleNewIdleChannelDetector(new IdleChannelDetector());}//......
}  

DefaultChannelPool基于ConcurrentHashMap实现了ChannelPool接口,主要的参数为connectionTtl、maxIdleTime、cleanerPeriod、poolLeaseStrategy;cleanerPeriod会取connectionTtl、maxIdleTime、传入的cleanerPeriod的最小值;开启connectionTtl或者maxIdleTime的话,会往nettyTimer添加IdleChannelDetector,延后cleanerPeriod时间执行

offer

  public boolean offer(Channel channel, Object partitionKey) {if (isClosed.get())return false;long now = unpreciseMillisTime();if (isTtlExpired(channel, now))return false;boolean offered = offer0(channel, partitionKey, now);if (connectionTtlEnabled && offered) {registerChannelCreation(channel, partitionKey, now);}return offered;}private boolean isTtlExpired(Channel channel, long now) {if (!connectionTtlEnabled)return false;ChannelCreation creation = channelId2Creation.get(channel.id());return creation != null && now - creation.creationTime >= connectionTtl;}  private boolean offer0(Channel channel, Object partitionKey, long now) {ConcurrentLinkedDeque<IdleChannel> partition = partitions.get(partitionKey);if (partition == null) {partition = partitions.computeIfAbsent(partitionKey, pk -> new ConcurrentLinkedDeque<>());}return partition.offerFirst(new IdleChannel(channel, now));}  private void registerChannelCreation(Channel channel, Object partitionKey, long now) {ChannelId id = channel.id();if (!channelId2Creation.containsKey(id)) {channelId2Creation.putIfAbsent(id, new ChannelCreation(now, partitionKey));}}  

offer接口先判断isTtlExpired,如果channel的存活时间超过connectionTtl则返回false,否则执行offer0,往ConcurrentLinkedDeque添加,若添加成功且connectionTtlEnabled则执行registerChannelCreation,维护创建时间

poll

  /*** {@inheritDoc}*/public Channel poll(Object partitionKey) {IdleChannel idleChannel = null;ConcurrentLinkedDeque<IdleChannel> partition = partitions.get(partitionKey);if (partition != null) {while (idleChannel == null) {idleChannel = poolLeaseStrategy.lease(partition);if (idleChannel == null)// pool is emptybreak;else if (!Channels.isChannelActive(idleChannel.channel)) {idleChannel = null;LOGGER.trace("Channel is inactive, probably remotely closed!");} else if (!idleChannel.takeOwnership()) {idleChannel = null;LOGGER.trace("Couldn't take ownership of channel, probably in the process of being expired!");}}}return idleChannel != null ? idleChannel.channel : null;}

poll方法是根据partitionKey找到对应的ConcurrentLinkedDeque,然后循环执行poolLeaseStrategy.lease(partition),若idleChannel为null直接break,若isChannelActive为false则重置为null继续循环,若idleChannel.takeOwnership()为false也重置为null继续循环

removeAll

  /*** {@inheritDoc}*/public boolean removeAll(Channel channel) {ChannelCreation creation = connectionTtlEnabled ? channelId2Creation.remove(channel.id()) : null;return !isClosed.get() && creation != null && partitions.get(creation.partitionKey).remove(new IdleChannel(channel, Long.MIN_VALUE));}

removeAll方法会将指定的channel从channelId2Creation及ConcurrentLinkedDeque中移除

isOpen

  /*** {@inheritDoc}*/public boolean isOpen() {return !isClosed.get();}

isOpen则取的isClosed变量

destroy

  /*** {@inheritDoc}*/public void destroy() {if (isClosed.getAndSet(true))return;partitions.clear();if (connectionTtlEnabled) {channelId2Creation.clear();}}

destroy会设置isClosed为true,然后清空partitions及channelId2Creation

flushPartitions

  public void flushPartitions(Predicate<Object> predicate) {for (Map.Entry<Object, ConcurrentLinkedDeque<IdleChannel>> partitionsEntry : partitions.entrySet()) {Object partitionKey = partitionsEntry.getKey();if (predicate.test(partitionKey))flushPartition(partitionKey, partitionsEntry.getValue());}}private void flushPartition(Object partitionKey, ConcurrentLinkedDeque<IdleChannel> partition) {if (partition != null) {partitions.remove(partitionKey);for (IdleChannel idleChannel : partition)close(idleChannel.channel);}}private void close(Channel channel) {// FIXME pity to have to do this hereChannels.setDiscard(channel);if (connectionTtlEnabled) {channelId2Creation.remove(channel.id());}Channels.silentlyCloseChannel(channel);}    

flushPartitions会遍历partitions,然后执行predicate.test,为true则执行flushPartition,它将从partitions移除指定的partitionKey,然后遍历idleChannels挨个执行close

getIdleChannelCountPerHost

  public Map<String, Long> getIdleChannelCountPerHost() {return partitions.values().stream().flatMap(ConcurrentLinkedDeque::stream).map(idle -> idle.getChannel().remoteAddress()).filter(a -> a.getClass() == InetSocketAddress.class).map(a -> (InetSocketAddress) a).map(InetSocketAddress::getHostName).collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));}

getIdleChannelCountPerHost则遍历partitions,然后map出remoteAddress获取hostName,然后进行groupBy

PoolLeaseStrategy

  public enum PoolLeaseStrategy {LIFO {public <E> E lease(Deque<E> d) {return d.pollFirst();}},FIFO {public <E> E lease(Deque<E> d) {return d.pollLast();}};abstract <E> E lease(Deque<E> d);}

PoolLeaseStrategy是个枚举,定义了LIFO及FIFO两个枚举,LIFO则是对Deque执行pollFirst,FIFO则是对Deque执行pollLast

IdleChannelDetector

  private final class IdleChannelDetector implements TimerTask {private boolean isIdleTimeoutExpired(IdleChannel idleChannel, long now) {return maxIdleTimeEnabled && now - idleChannel.start >= maxIdleTime;}private List<IdleChannel> expiredChannels(ConcurrentLinkedDeque<IdleChannel> partition, long now) {// lazy createList<IdleChannel> idleTimeoutChannels = null;for (IdleChannel idleChannel : partition) {boolean isIdleTimeoutExpired = isIdleTimeoutExpired(idleChannel, now);boolean isRemotelyClosed = !Channels.isChannelActive(idleChannel.channel);boolean isTtlExpired = isTtlExpired(idleChannel.channel, now);if (isIdleTimeoutExpired || isRemotelyClosed || isTtlExpired) {LOGGER.debug("Adding Candidate expired Channel {} isIdleTimeoutExpired={} isRemotelyClosed={} isTtlExpired={}", idleChannel.channel, isIdleTimeoutExpired, isRemotelyClosed, isTtlExpired);if (idleTimeoutChannels == null)idleTimeoutChannels = new ArrayList<>(1);idleTimeoutChannels.add(idleChannel);}}return idleTimeoutChannels != null ? idleTimeoutChannels : Collections.emptyList();}private List<IdleChannel> closeChannels(List<IdleChannel> candidates) {// lazy create, only if we hit a non-closeable channelList<IdleChannel> closedChannels = null;for (int i = 0; i < candidates.size(); i++) {// We call takeOwnership here to avoid closing a channel that has just been taken out// of the pool, otherwise we risk closing an active connection.IdleChannel idleChannel = candidates.get(i);if (idleChannel.takeOwnership()) {LOGGER.debug("Closing Idle Channel {}", idleChannel.channel);close(idleChannel.channel);if (closedChannels != null) {closedChannels.add(idleChannel);}} else if (closedChannels == null) {// first non closeable to be skipped, copy all// previously skipped closeable channelsclosedChannels = new ArrayList<>(candidates.size());for (int j = 0; j < i; j++)closedChannels.add(candidates.get(j));}}return closedChannels != null ? closedChannels : candidates;}public void run(Timeout timeout) {if (isClosed.get())return;if (LOGGER.isDebugEnabled())for (Object key : partitions.keySet()) {int size = partitions.get(key).size();if (size > 0) {LOGGER.debug("Entry count for : {} : {}", key, size);}}long start = unpreciseMillisTime();int closedCount = 0;int totalCount = 0;for (ConcurrentLinkedDeque<IdleChannel> partition : partitions.values()) {// store in intermediate unsynchronized lists to minimize// the impact on the ConcurrentLinkedDequeif (LOGGER.isDebugEnabled())totalCount += partition.size();List<IdleChannel> closedChannels = closeChannels(expiredChannels(partition, start));if (!closedChannels.isEmpty()) {if (connectionTtlEnabled) {for (IdleChannel closedChannel : closedChannels)channelId2Creation.remove(closedChannel.channel.id());}partition.removeAll(closedChannels);closedCount += closedChannels.size();}}if (LOGGER.isDebugEnabled()) {long duration = unpreciseMillisTime() - start;if (closedCount > 0) {LOGGER.debug("Closed {} connections out of {} in {} ms", closedCount, totalCount, duration);}}scheduleNewIdleChannelDetector(timeout.task());}}

IdleChannelDetector实现了netty的TimerTask接口,其run方法主要是遍历partitions,通过expiredChannels取出过期的IdleChannel,这里isIdleTimeoutExpired、isRemotelyClosed、isTtlExpired都算在内,然后挨个执行takeOwnership及close,再从channelId2Creation及partition中移除,最后再次调度一下IdleChannelDetector

小结

AsyncHttpClient的ChannelPool定义了offer、poll、removeAll、isOpen、destroy、flushPartitions、getIdleChannelCountPerHost方法,它有两个实现类,分别是NoopChannelPool及DefaultChannelPool;DefaultChannelPool基于ConcurrentHashMap实现了ChannelPool接口,主要的参数为connectionTtl、maxIdleTime、cleanerPeriod、poolLeaseStrategy;cleanerPeriod会取connectionTtl、maxIdleTime、传入的cleanerPeriod的最小值;开启connectionTtl或者maxIdleTime的话,会往nettyTimer添加IdleChannelDetector,延后cleanerPeriod时间执行。

poll方法会判断是active,不是的话继续循环lease,而IdleChannelDetector则会定期检查,isIdleTimeoutExpired、isRemotelyClosed、isTtlExpired都会被close,offer的时候还会判断isTtlExpired,这样子来保证连接的活性。

相关文章:

聊聊AsyncHttpClient的ChannelPool

序 本文主要研究一下AsyncHttpClient的ChannelPool ChannelPool org/asynchttpclient/channel/ChannelPool.java public interface ChannelPool {/*** Add a channel to the pool** param channel an I/O channel* param partitionKey a key used to retrieve the cac…...

[MySQL] MySQL复合查询(多表查询、子查询)

前面我们学习了MySQL简单的单表查询。但是我们发现&#xff0c;在很多情况下单表查询并不能很好的满足我们的查询需求。本篇文章会重点讲解MySQL中的多表查询、子查询和一些复杂查询。希望本篇文章会对你有所帮助。 文章目录 一、基本查询回顾 二、多表查询 2、1 笛卡尔积 2、2…...

[架构之路-256]:目标系统 - 设计方法 - 软件工程 - 软件设计 - 架构设计 - 软件系统不同层次的复用与软件系统向越来越复杂的方向聚合

目录 前言&#xff1a; 一、CPU寄存器级的复用&#xff1a;CPU寄存器 二、指令级复用&#xff1a;二进制指令 三、过程级复用&#xff1a;汇编语言 四、函数级复用&#xff1a;C语言 五、对象级复用&#xff1a;C, Java, Python 六、组件级复用 七、服务级复用 八、微…...

C++初学教程三

目录 一、运算符 一、自增自减运算符 二、位运算符 三、关系运算符...

雷达点云数据.pcd格式转.bin格式

雷达点云数据.pcd格式转.bin格式 注意&#xff0c;方法1原则上可行&#xff0c;但是本人没整好pypcd的环境 方法2是绝对可以的。 方法1 1 源码如下&#xff1a; def pcb2bin1(): # save as bin formatimport os# import pypcdfrom pypcd import pypcdimport numpy as np…...

Fiddler抓包测试

模拟弱网测试 操作&#xff1a;一、Rules - Customize Rules &#xff08;快捷键CtrlR&#xff09;弹出编辑器 二、接着CtrlF查找m_SimulateModem标志位 三、默认上传300ms&#xff0c;下载150ms 四、更改后&#xff0c;继续Rules - Performances - Simulate Modem Speeds勾上 …...

视频处理关键知识

1 引言 视频技术发展到现在已经有100多年的历史&#xff0c;虽然比照相技术历史时间短&#xff0c;但在过去很长一段时间之内都是最重要的媒体。由于互联网在新世纪的崛起&#xff0c;使得传统的媒体技术有了更好的发展平台&#xff0c;应运而生了新的多媒体技术。而多媒体技术…...

LeetCode435. Non-overlapping Intervals

文章目录 一、题目二、题解 一、题目 Given an array of intervals intervals where intervals[i] [starti, endi], return the minimum number of intervals you need to remove to make the rest of the intervals non-overlapping. Example 1: Input: intervals [[1,2]…...

ffmpeg 实现多视频轨录制到同一个文件

引言 在视频录制中&#xff0c;有时会碰到这样一个需求&#xff0c;将不同摄像头的画面写入到一个视频文件&#xff0c;这个叫法很多&#xff0c;有的厂家叫合流模式&#xff0c;有的叫多画面多流模式。无论如何&#xff0c;它们的实质都是在一个视频文件上实现多路不同分辨率视…...

vue3中子组件调用父组件的方法

<script lang"ts" setup>前提 父组件&#xff1a; 子组件&#xff1a; const emit defineEmits([closeson]) 在子组件的方法中使用&#xff1a; emit(closeson)...

使用OkHttp上传本地图片及参数

下面以一个例子来讲解在项目中如何使用OKHttp来对本地图片做个最简单的上传功能&#xff0c;基本上无封装&#xff0c;只需要简单调用便可&#xff08;对于OKHttp的引入不再单独做介绍&#xff09;。 1&#xff1a;构建上传图片附带的参数&#xff08;params&#xff09; Map…...

无公网IP环境如何SSH远程连接Deepin操作系统

文章目录 前言1. 开启SSH服务2. Deppin安装Cpolar3. 配置ssh公网地址4. 公网远程SSH连接5. 固定连接SSH公网地址6. SSH固定地址连接测试 前言 Deepin操作系统是一个基于Debian的Linux操作系统&#xff0c;专注于使用者对日常办公、学习、生活和娱乐的操作体验的极致&#xff0…...

不会代码(零基础)学语音开发(语音控制板载双继电器)

继电器的用途可广了&#xff0c;这个语音控制用处也特别广。继电器&#xff0c;它实际上是一种“自动开关”&#xff0c;用小电流去控制大电流运作&#xff0c;在电路中起着自动调节、安全保护、转换电路等作用。 在日常生活中&#xff0c;你插入汽车钥匙&#xff0c;车辆可以…...

在imx6ull中加入ov5640模块

本来觉得是一件很简单的事情但是走了很多的弯路&#xff0c;记录一下调试过程。 先使用正点原子提供的出厂内核把摄像头影像调试出来&#xff0c;然后cat /dev/video1&#xff0c;看一下video1牵扯到哪些模块&#xff0c;可以看到需要ov5640_camera.ko和 mx6s_capture.ko这两个…...

Kafka中的auto-offset-reset配置

Kafka这个服务在启动时会依赖于Zookeeper&#xff0c;Kafka相关的部分数据也会存储在Zookeeper中。如果kafka或者Zookeeper中存在脏数据的话&#xff08;即错误数据&#xff09;&#xff0c;这个时候虽然生产者可以正常生产消息&#xff0c;但是消费者会出现无法正常消费消息的…...

TCP/IP_整理起因

先分享一个初级的问题&#xff1b;有个客户现场&#xff0c;终端设备使用客户网络更新很慢&#xff0c;使用手机热点更新速度符合预期&#xff1b;网络部署情况如下&#xff1a; 前期花费了很大的精力进行问题排查对比&#xff0c;怀疑是客户网络问题&#xff08;其他的客户现…...

CG-0A 电子水尺水导电测量原理应用于道路积水监测

CG-0A 电子水尺水导电测量原理应用于道路积水监测产品概述 本产品是一种采用微处理器芯片为控制器&#xff0c;内置通讯电路的数字式水位传感器&#xff0c;具备高的可靠性及抗干扰性能。适用于江、河、湖、水库及蓄水池、水渠等处的水位测量使用。 本产品采用了生产工艺技术…...

openEuler JDK21 部署 Zookeeper 集群

zookeeper-jdk21 操作系统&#xff1a;openEuler JDK&#xff1a;21 主机名IP地址spark01192.168.171.101spark02192.168.171.102spark03192.168.171.103 安装 1. 升级内核和软件 yum -y update2. 安装常用软件 yum -y install gcc gcc-c autoconf automake cmake make \zl…...

前端——html拖拽原理

文章目录 ⭐前言⭐draggable属性&#x1f496; api&#x1f496; 单向拖动示例&#x1f496; 双向拖动示例 ⭐总结⭐结束 ⭐前言 大家好&#xff0c;我是yma16&#xff0c;本文分享关于 前端——html拖拽原理。 vue3系列相关文章&#xff1a; vue3 fastapi 实现选择目录所有文…...

JVM 执行引擎篇

机器码、指令、汇编语言 机器码 各种用二进制编码方式表示的指令&#xff0c;叫做机器指令码。开始&#xff0c;人们就用它采编写程序&#xff0c;这就是机器语言。机器语言虽然能够被计算机理解和接受&#xff0c;但和人们的语言差别太大&#xff0c;不易被人们理解和记忆&a…...

js中数组对象去重的方法

前端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 最近工作中需要用到数组对象去重的方法&#xff0c;我是怎么想也没想出来&#xff0c;今天稍微研究了一下&#xff0c;总算找到了2种方法。分享一下&…...

【送书活动四期】被GitHub 要求强制开启 2FA 双重身份验证,我该怎么办?

记得是因为fork了OpenZeppelin/openzeppelin-contracts的项目&#xff0c;之后就被GitHub 要求强制开启 2FA 双重身份验证了&#xff0c;一拖再拖&#xff0c;再过几天帐户操作将受到限制了&#xff0c;只能去搞一下了 目录 2FA是什么为什么要开启 2FA 验证GitHub 欲在整个平台…...

GO设计模式——13、享元模式(结构型)

目录 享元模式&#xff08;Flyweight Pattern&#xff09; 享元模式的核心角色&#xff1a; 优缺点 使用场景 注意事项 代码实现 享元模式&#xff08;Flyweight Pattern&#xff09; 享元模式&#xff08;Flyweight Pattern&#xff09;它通过共享对象来减少内存使用和提…...

Linux 网络协议

1 网络基础 1.1 网络概念 网络是一组计算机或者网络设备通过有形的线缆或者无形的媒介如无线&#xff0c;连接起来&#xff0c;按照一定的规则&#xff0c;进行通讯的集合( 缺一不可 )。 5G的来临以及IPv6的不断普及&#xff0c;能够进行联网的设备将会是越来越多&#xff08…...

【C语言】7-32 刮刮彩票 分数 20

7-32 刮刮彩票 分数 20 全屏浏览题目 切换布局 作者 DAI, Longao 单位 杭州百腾教育科技有限公司 “刮刮彩票”是一款网络游戏里面的一个小游戏。如图所示&#xff1a; 每次游戏玩家会拿到一张彩票&#xff0c;上面会有 9 个数字&#xff0c;分别为数字 1 到数字 9&#xf…...

交叉验证以及scikit-learn实现

交叉验证 交叉验证既可以解决数据集的数据量不够大问题&#xff0c;也可以解决参数调优的问题。 主要有三种方式&#xff1a; 简单交叉验证&#xff08;HoldOut检验&#xff09;、k折交叉验证&#xff08;k-fold交叉验证&#xff09;、自助法。 本文仅针对k折交叉验证做详细解…...

css实现头部占一定高度,内容区占剩余高度可滚动

上下布局&#xff1a; <div class"container"><header class"header">头部内容</header><div class"content">内容区域</div> </div>.container {display: flex;flex-direction: column;height: 100vh; /*…...

redis主从复制模式和哨兵机制

目录 第一章、主从复制模式1.1&#xff09;Redis 主从复制模式介绍1.2&#xff09;Redis 主从复制实现、 第二章、哨兵机制2.1&#xff09;容灾处理之哨兵2.2&#xff09;Sentinel 配置 第一章、主从复制模式 1.1&#xff09;Redis 主从复制模式介绍 ①单点故障&#xff1a;数…...

WebStorm:Mac/Win上强大的JavaScript开发工具

WebStorm是JetBrains公司开发的针对Mac和Windows系统的JavaScript开发工具。它为开发者提供了一站式的代码编辑、调试、测试和版本控制等功能&#xff0c;帮助你更高效地进行Web开发。新版本的WebStorm 2023在性能和用户体验方面都做出了重大改进&#xff0c;让你的JavaScript开…...

传世SUN引擎如何安装

大家在搭建的时候一定要理清思路一步一步来&#xff0c;否则一步错步步错。下面跟大家说一下搭建的顺序以及细节。 第一步&#xff1a;首先下载DBC2000进行安装&#xff0c;并按照里面的说明设置好。1、请把压缩包释放到D:\QMirServer目录下。2、在控制面板里找到BDC Administ…...