1.数据库连接池之Hikari
2.linux下TCP在FIN_WAIT1状态能持续多久及TCP假连接问题
3.keepalive部署虚拟IP项目
4.go语言中的码缓channel实现原理是什么?
5.keep-alive的vue2和vue3的源码以及LRU算法
数据库连接池之Hikari
作为数据库连接池的佼佼者,HikariCP因其卓越的码缓性能而备受推崇,尤其在SpringBoot2.0以后成为了默认选用的码缓连接池。它的码缓配置参数如autoCommit、connectionTimeout等,码缓如autoCommit默认为true,码缓maven 源码下载命令用于自动提交从池中获取的码缓连接。connectionTimeout设定了最大等待时间,码缓idleTimeout则控制连接在池中的码缓最长闲置时间,两者共同确保了连接的码缓有效管理。keepaliveTime确保连接的码缓存活,而maxLifetime则设定连接的码缓最长生命周期,建议用户设置以优化性能。码缓minimumIdle用于维护连接池的码缓最小空闲连接数,而maximumPoolSize则控制最大连接数,码缓poolName则是用于标识池的唯一名称。
HikariCP的高性能主要源于其技术优化。首先,它采用FastList替代ArrayList,提高get和remove操作的效率。其次,通过预先初始化避免了同步处理,提升初始化速度。动态字节码生成技术使得连接创建更为迅速。连接获取时,应用中心php源码HikariCP在threadLocal中进行缓存,降低了线程间的并发冲突。同时,HikariCP设计目标在于减少锁竞争,确保在高并发环境中的稳定表现。关于更深入的解析,可以参考《非正经程序员:Spring Boot中使用Hikari,给我整不会了》和《数据库连接池之Hikari源码解析 - Lucky帅小武 - 博客园》等文章,以及《Springboot 2.0默认连接池HikariCP详解(效率最高)》。
linux下TCP在FIN_WAIT1状态能持续多久及TCP假连接问题
本文探讨了TCP在FIN_WAIT1状态的持续时间以及TCP所谓的“假连接”或“死连接”问题。首先,我们从状态机的角度来分析。
我们关注的是从ESTABLISHED状态转换到FIN_WAIT1状态的过程。这个过程简洁明了,涉及到状态转换的基本逻辑。通过观察状态机转换图以及相应的时序图,我们可以明确得出在正常情况下,FIN_WAIT1状态的持续时间大约为一个RTT(往返时间)左右。这个时间非常短暂,几乎在眨眼间即逝。
然而,这个结论基于两个假设。接下来,本文通过设计实验来探讨在异常情况下的作图素材源码下载实际表现。实验构建了一个拓扑,模拟了在接收端TCP针对FIN发送的ACK丢失的场景。按照理论预期,FIN_WAIT1状态应永久持续。但实验结果显示,即使在接收端进程退出销毁的条件下,FIN_WAIT1状态最终消失。
这一现象的解释涉及到Linux内核协议栈中的一个关键参数:`tcp_orphan_retries`。这个参数规定了在收不到针对FIN的ACK时,TCP应等待的超时轮数。超过这个轮数后,连接将被销毁。因此,即使接收端进程已退出,TCP连接状态仍能得到清理。
实验表明,虽然TCP理论上不应因对端的异常行为而永久维持连接,但实际上,为防止资源泄漏,TCP实现必须处理异常情况。`tcp_orphan_retries`参数确保了即使在接收端不可用的情况下,连接也能在合理时间内得到释放。
通过上述实验,我们得出了关于FIN_WAIT1状态持续时间的彩票类源码搭建结论。接下来,文章转向讨论更复杂的问题,即在接收端进程未完全退出的情况下,数据传输为何能够继续进行。这涉及到TCP状态机在缓存层面上的特性,以及数据如何在进程已退出的情况下继续发送。
实验显示,尽管接收端进程已退出,但由于发送端已发送的大量数据仍存在于缓冲区,数据传输并未立即停止。在发送端进程退出后,即使接收端进程不存在,TCP状态机仍会将FIN包排队到发送缓冲区,使得连接进入FIN_WAIT1状态,直到缓冲区中的所有数据发送完毕。这表明,即使接收端进程已完全退出,数据传输仍能继续一段时间。
最后,文章探讨了如何应对这种“假连接”或“死连接”问题。这涉及到在正常情况下引入的Keepalive机制,用于检测连接的活跃性并避免状态机的僵化。尽管Keepalive机制有助于解决假连接问题,但在特定情况下,下载android 10 源码如用户态未设置Keepalive,连接仍可能成为死连接。文章强调了理解TCP状态机及其实现的必要性,并指出在排查和确认逻辑时,源码并不是唯一的参考,关键在于理解协议标准和其背后的实现建议。
keepalive部署虚拟IP项目
在..4.和..4.上部署虚拟IP,通过keepalive实现高可用性。
在..4.配置(主):
1. 安装依赖包(gcc, gcc-c++, kernel-devel, openssl-devel, popt, libnl, libnl-devel)。
2. 使用源码安装keepalive。
3. 创建软链接,将keepalive文件链接至系统路径。
4. 编辑配置文件(/etc/keepalive/keepalive.conf),设置router_id、虚拟路由ID、优先级和虚拟IP地址。
5. 重启服务。
在..4.配置(从):
1. 安装依赖包。
2. 使用源码安装keepalive。
3. 创建软链接。
4. 编辑配置文件(/etc/keepalive/keepalive.conf),设置为从机,并设置相关参数。
5. 重启服务。
Keepalived支持多种服务的高可用性,通过VRRP协议实现自动接管。
查看部署的虚拟IP使用命令:ip addr。
默认日志路径为:/var/log/messages。
在...(nat公网)上部署虚拟IP..4.5:
安装依赖包、源码安装keepalive、创建软链接、编辑配置文件、重启服务。
完成配置后,使用命令检查进程和端口,验证虚拟IP部署成功。
go语言中的channel实现原理是什么?
channel在Go语言中用于不同协程之间的通信,实现机制基于hchan结构体和循环队列。channel的底层实现包含sendx、recvx、sendq、recvq等关键元素,以及sudog结构体用于管理被阻塞的goroutine。
创建channel时主要涉及内存分配与初始化,makechan()函数负责此过程,确保创建的channel具备所需属性,如数据个数和等待队列。
发送数据分为同步、异步与阻塞三种模式,同步发送和接收数据的处理逻辑通过流程图和源码展现,异步发送与接收则通过类似方式实现。阻塞发送与接收则在适当条件下等待资源可用,发送操作的源码实现为chansend函数,接收操作为chanrecv函数。
关闭channel涉及释放资源与唤醒被阻塞的goroutine,通过closechan()函数执行这一流程,确保所有等待的goroutine能够继续执行。
讨论Go channel的底层实现过程中的疑问,包括是否会被垃圾回收、elemtype *_type的用途、KeepAlive源码的作用、无缓冲channel的应用场景以及gopark goready的内核态切换问题。这些问题可以通过深入研究Go语言的源码和相关资料来解答。
keep-alive的vue2和vue3的源码以及LRU算法
0.LRU算法
LRU(leastrecentlyused)根据数据的历史记录来淘汰数据,重点在于保护最近被访问/使用过的数据,淘汰现阶段最久未被访问的数据
LRU的主体思想在于:如果数据最近被访问过,那么将来被访问的几率也更高
经典的LRU实现一般采用双向链表+Hash表。借助Hash表来通过key快速映射到对应的链表节点,然后进行插入和删除操作。这样既解决了hash表无固定顺序的缺点,又解决了链表查找慢的缺点。
但实际上在js中无需这样实现,可以参考文章第三部分。先看vue的keep-alive实现。
1.keep-alivekeep-alive是vue中的内置组件,使用KeepAlive后,被包裹的组件在经过第一次渲染后的vnode会被缓存起来,然后再下一次再次渲染该组件的时候,直接从缓存中拿到对应的vnode进行渲染,并不需要再走一次组件初始化,render和patch等一系列流程,减少了script的执行时间,性能更好。
使用原则:当我们在某些场景下不需要让页面重新加载时我们可以使用keepalive
当我们从首页–>列表页–>商详页–>再返回,这时候列表页应该是需要keep-alive
从首页–>列表页–>商详页–>返回到列表页(需要缓存)–>返回到首页(需要缓存)–>再次进入列表页(不需要缓存),这时候可以按需来控制页面的keep-alive
在路由中设置keepAlive属性判断是否需要缓存。
2.vue2的实现实现原理:通过keep-alive组件插槽,获取第一个子节点。根据include、exclude判断是否需要缓存,通过组件的key,判断是否命中缓存。利用LRU算法,更新缓存以及对应的keys数组。根据max控制缓存的最大组件数量。
先看vue2的实现:
exportdefault{ name:'keep-alive',abstract:true,props:{ include:patternTypes,exclude:patternTypes,max:[String,Number]},created(){ this.cache=Object.create(null)this.keys=[]},destroyed(){ for(constkeyinthis.cache){ pruneCacheEntry(this.cache,key,this.keys)}},mounted(){ this.$watch('include',val=>{ pruneCache(this,name=>matches(val,name))})this.$watch('exclude',val=>{ pruneCache(this,name=>!matches(val,name))})},render(){ constslot=this.$slots.defaultconstvnode:VNode=getFirstComponentChild(slot)constcomponentOptions:?VNodeComponentOptions=vnode&&vnode.componentOptionsif(componentOptions){ //checkpatternconstname:?string=getComponentName(componentOptions)const{ include,exclude}=thisif(//notincluded(include&&(!name||!matches(include,name)))||//excluded(exclude&&name&&matches(exclude,name))){ returnvnode}const{ cache,keys}=thisconstkey:?string=vnode.key==null?componentOptions.Ctor.cid+(componentOptions.tag?`::${ componentOptions.tag}`:''):vnode.keyif(cache[key]){ vnode.componentInstance=cache[key].componentInstance//makecurrentkeyfreshestremove(keys,key)keys.push(key)}else{ cache[key]=vnodekeys.push(key)//pruneoldestentryif(this.max&&keys.length>parseInt(this.max)){ pruneCacheEntry(cache,keys[0],keys,this._vnode)}}vnode.data.keepAlive=true}returnvnode||(slot&&slot[0])}}可以看到<keep-alive>组件的实现也是一个对象,注意它有一个属性abstract为true,是一个抽象组件,它在组件实例建立父子关系的时候会被忽略,发生在initLifecycle的过程中:
//忽略抽象组件letparent=options.parentif(parent&&!options.abstract){ while(parent.$options.abstract&&parent.$parent){ parent=parent.$parent}parent.$children.push(vm)}vm.$parent=parent然后在?created?钩子里定义了?this.cache?和?this.keys,用来缓存已经创建过的?vnode。
<keep-alive>直接实现了render函数,执行<keep-alive>组件渲染的时候,就会执行到这个render函数,接下来我们分析一下它的实现。
首先通过插槽获取第一个子元素的vnode:
constslot=this.$slots.defaultconstvnode:VNode=getFirstComponentChild(slot)<keep-alive>只处理第一个子元素,所以一般和它搭配使用的有component动态组件或者是router-view。
然后又判断了当前组件的名称和include、exclude(白名单、黑名单)的关系:
//checkpatternconstname:?string=getComponentName(componentOptions)const{ include,exclude}=thisif(//notincluded(include&&(!name||!matches(include,name)))||//excluded(exclude&&name&&matches(exclude,name))){ returnvnode}functionmatches(pattern:string|RegExp|Array<string>,name:string):boolean{ if(Array.isArray(pattern)){ returnpattern.indexOf(name)>-1}elseif(typeofpattern==='string'){ returnpattern.split(',').indexOf(name)>-1}elseif(isRegExp(pattern)){ returnpattern.test(name)}returnfalse}组件名如果不满足条件,那么就直接返回这个组件的vnode,否则的话走下一步缓存:
const{ cache,keys}=thisconstkey:?string=vnode.key==null?componentOptions.Ctor.cid+(componentOptions.tag?`::${ componentOptions.tag}`:''):vnode.keyif(cache[key]){ vnode.componentInstance=cache[key].componentInstance//makecurrentkeyfreshestremove(keys,key)keys.push(key)}else{ cache[key]=vnodekeys.push(key)//pruneoldestentryif(this.max&&keys.length>parseInt(this.max)){ pruneCacheEntry(cache,keys[0],keys,this._vnode)}}如果命中缓存,则直接从缓存中拿vnode的组件实例,并且重新调整了key的顺序放在了最后一个;否则把vnode设置进缓存,如果配置了max并且缓存的长度超过了this.max,还要从缓存中删除第一个。
这里的实现有一个问题:判断是否超过最大容量应该放在put操作前。为什么呢?我们设置一个缓存队列,都已经满了你还塞进来?最好先删一个才能塞进来新的。
继续看删除缓存的实现:
functionpruneCacheEntry(cache:VNodeCache,key:string,keys:Array<string>,current?:VNode){ constcached=cache[key]if(cached&&(!current||cached.tag!==current.tag)){ cached.componentInstance.$destroy()}cache[key]=nullremove(keys,key)}除了从缓存中删除外,还要判断如果要删除的缓存的组件tag不是当前渲染组件tag,则执行删除缓存的组件实例的$destroy方法。
————————————
可以发现,vue实现LRU算法是通过Array+Object,数组用来记录缓存顺序,Object用来模仿Map的功能进行vnode的缓存(created钩子里定义的this.cache和this.keys)
2.vue3的实现vue3实现思路基本和vue2类似,这里不再赘述。主要看LRU算法的实现。
vue3通过set+map实现LRU算法:
constcache:Cache=newMap()constkeys:Keys=newSet()并且在判断是否超过缓存容量时的实现比较巧妙:
if(max&&keys.size>parseInt(maxasstring,)){ pruneCacheEntry(keys.values().next().value)}这里巧妙的利用Set是可迭代对象的特点,通过keys.value()获得包含keys中所有key的可迭代对象,并通过next().value获得第一个元素,然后进行删除。
3.借助vue3的思路实现LRU算法Leetcode题目——LRU缓存
varLRUCache=function(capacity){ this.map=newMap();this.capacity=capacity;};LRUCache.prototype.get=function(key){ if(this.map.has(key)){ letvalue=this.map.get(key);//删除后,再set,相当于更新到map最后一位this.map.delete(key);this.map.set(key,value);returnvalue;}return-1;};LRUCache.prototype.put=function(key,value){ //如果已经存在,那就要更新,即先删了再进行后面的setif(this.map.has(key)){ this.map.delete(key);}else{ //如果map中不存在,要先判断是否超过最大容量if(this.map.size===this.capacity){ this.map.delete(this.map.keys().next().value);}}this.map.set(key,value);};这里我们直接通过Map来就可以直接实现了。
而keep-alive的实现因为缓存的内容是vnode,直接操作Map中缓存的位置代价较大,而采用Set/Array来记录缓存的key来模拟缓存顺序。
参考:
LRU缓存-keep-alive实现原理
带你手撸LRU算法
Vue.js技术揭秘
原文;/post/广东开展公平竞争政策宣传周系列活动
同花顺主力动向源码_同花顺主力动向指标
iis网站源码安装_iis网站搭建
bt分享网站源码
广西罗城:12315解决涉老消费纠纷 消费者点赞赠锦旗
小程序 快递 源码_小程序 快递 源码是什么