Java面试题

面试题

synchronized和lock的区别

1.作用位置不同

synchronized可以给方法,代码块加锁,lock只能给代码块加锁

2.锁的华侨锁和释放机制不同:

synchronized无需手动获取和释放锁,发生异常会自动解锁,不会出现死锁

lock需要自己加锁和释放锁,如lock()和unlock(),如果忘记使用unlock()则会出现死锁

所以一般我们会在finally里面使用unlock()

synchronized修饰成员方法时,锁对象就是当前对象

synchronized修饰静态方法时,默认的锁对象,是当前类的class对象,比如User.class

66,TCP和UDP的区别

首先,两者都是传输层协议

其次,

tcp提供可靠的传输协议,传输前需要建立连接,面向字节流,传输慢

udp无法保证传输的可靠性,无需创建连接,以报文的方式传输,效率高

TCP三次握手:

  1. 客户端给服务端发送一个随机数x

  2. 服务端给客户端发送x+1和一个随机数y

  3. 客户端给服务端发送x+1和y+1

TCP四次挥手:(双工通信模式)

  1. 客户端-->服务端,FIN=1,seq=u

  2. 服务端-->客户端,ACK=1 ack=u+1 seq=v

  3. 服务端-->客户端,FIN=1 ack=ack+1 seq=w

  4. 客户端-->服务端,ACK=1 seq=x ack=w+1

7层网络模型

7.应用层  HTTP,FTP,SMTP,DNS.Telenet,RIP,TFTP

6.表示层

5.会话层

4.传输层 TCP,UDP

3.网络层 IP,ICMP,OSPF,BGP,IGMP,ARP,RARP

2.数据链路层 SLIP,CSLIP,PPP,MTU,ARP,RARP

1.物理层 ISO2110,IEEE802

如何防止死锁:

      1. 尽量采用tryLock(timeout)方法,可以设置超时时间,这样超时之后,就可以主动退出,防止死锁(关键)

  1. 减少同步代码嵌套操作

  2. 降低锁的使用粒度,不要几个功能共用一把锁

反射:

一种在程序运行时,动态获取当前类对象的所有属性和方法的能力,可以动态执行方法,给属性赋值等操作的能力

Class代表的就是所有的字节码对象的抽象,利用反射实现动态效果

对Spring的认识:

核心的IOC容器技术(控制反转,依赖注入),帮助我们自动管理依赖的对象,不需要我们自己创建和管理依赖对象,从而实现了层与层之间的解耦,所以重点是解耦。

核心的AOP技术(面向切面编程),方便我们将一些非核心业务逻辑抽离,从而实现核心业务和非核心业务的解耦,比如添加一个商品信息,那么核心业务就是做添加商品信息记录这个操作,非核心业务比如事务管理,日志,性能检测,读写分离的实现等。

Spring 的bean作用域有哪些?

1.默认是singleton,单例模式

2.prototype,

3.request

4.session

5.global-session

Spring的bean是线程安全的吗?

Spring的bean模式是单例,后端的程序,处于一个多线程的工作环境

bean是无状态的,从这点来说是安全的

所谓无状态就是没有存储数据,即没有通过数据的状态来作为下一步操作的判断依据。

事务的传播特性以及Spring支持的特性有哪些?

PROPAGATION_REQUIRED:    支持当前事务,如果当前没有事务,新建一个事务。这是最常见的选择

PROPAGATION_SUPPORTS

PROPAGATION_MANDATORY

PROPAGATION_REQUIRES_NEW

PROPAGATION_NOT_SUPPORTED

PROPAGATION_NEVER

乐观锁,悲观锁:

悲观锁是利用数据库本身的锁机制来实现的,会锁记录

实现方式是:select * from t_table where id = 1 for update

乐观锁是一种不锁记录的方式,采用CAS(compare and set/swap)模式,减一采用version字段来作为判断的依据。

每次对数据更新的操作,都会对version+1,这样提交更新操作是,如果version的值已经被更改,则更新失败

乐观锁如果不选择version字段,选择其他字段,比如业务字段store,那么可能出现ABA问题(中间经历过其它状态)

MyBatis缓存机制,一级缓存、二级缓存

缓存,主要作用是提高查询性能,减少跟数据库交互次数,从而减轻了数据库承受的压力

适用于读多写少的场景,如果数据变化频率非常高,则不适用。

MyBatis一级缓存:

默认生效,作用域在于sqlSession,如果中间有对数据的更新操作,则将清空一级缓存

MyBatis二级缓存:作用域SqlSessionFactory,作用域比一级缓存更大

默认开启,

开启需要设置:1.<setting name ="cacheEnabled" value="true"/>

2.在Mapper.xml中,配置二级缓存(也支持在接口配置)

在标签<mapper>下面添加<cache/>标签即可

默认二级缓存的特点:

所有的select语句将会被缓存

所有的更新语句将会刷新缓存

缓存将采用LRU(least recently used最近最少使用)算法来回收

缓存会存储1024个对象的引用,

回收算法建议采用LRU,还提供了FIFO,SOFT(软引用),WEAR(弱引用)等其他算法

配置例子:

<cache evicition="LRU" readonly="true" size="1024"></cache>

MyBatis的二级缓存默认采用的是Map来实现,可以集成第三方缓存来保存MyBatis的二级缓存,如EhCache和Redis,推荐Redis

MyBatis分页方式:

逻辑分页:使用MyBatis自带的RowBunds分页,它会一次查出多条数据,然后再检索分页中的数据,具体一次查多少条数据,受封装JDBC配置的fetch-size决定

物理分页:从数据库查询指定条数的数据,分页插件PageHelper实现就是物理分页

MyBatis分页插件(拦截器)原理:

分页插件的原理就是使用MyBatis提供的插件接口,实现自定义插件,在插件的拦截方法内,拦截待执行的SQL,然后根据设置的dialect和设置的分页参数,重写SQL,生成带分页语句的SQL,执行重写后的sql,从而实现分页

发起请求到响应要经历什么?

1.浏览器检查协议,域名,请求参数的格式输入是否正确

2.检查是否有缓存,有就直接使用缓存

3.到DNS服务器进行域名解析,获取IP地址

4.通过3次握手协议和服务器建立连接

5.通过4次挥手和服务器断开连接

synchronized底层原理:

synchronized是由一对monitorenter和monitorexit指令来实现同步的,在JDK6之前monitor的实现是依赖于操作系统内部的互斥锁来实现的,所以需要进行用户态和内核态的切换,所以此时的同步操作是一个重量级的操作,性能很低

但是JDK1.6带来了新的变化,提供了3中monitor的实现方式,分别是偏向锁,轻量级锁,重量级锁,即锁会先从偏向锁再根据情况逐渐升级到轻量级锁和重量级锁。

这就是锁升级

在锁对象的对象头里面有一个threadid字段,默认情况下为空,当第一次有线程访问时,则将该threadid设置为当前的线程id,我们称之为获取偏向锁,当线程执行结束,则重新将threadid设置为空(用户态)

之后如果线程再次进入的时候,会先判断threadID与该线程的id是否一致,如果一致,则可以获取该对象,如果不一致,则发生锁升级,从偏向锁升级为轻量级锁(用户态)

轻量级锁的工作模式是通过自旋循环的方式来获取锁,看对方线程是否已经释放了锁,如果执行一定次数后,还是没有获取到锁,则发生锁升级,从轻量级锁升级为重量级锁(内核态)

偏向锁、轻量极锁实际上是一个缓冲的过程,不用马上就从用户态进入内核态,减少锁带来的性能消耗

synchronized如何保证可见性?

就是当获取到锁之后,每次读取都从主内存读取,当释放锁的时候,都会将本地内存的信息写到主内存,从而实现可见性

synchronized和volatile的区别?

  1. 作用位置不同synchronized是修饰方法、代码块,volatile是修饰变量

  2. 作用不同,synchronized,可以保证变量修改的可见性以及原子性,可能会造成线程的阻塞

  3. volatile仅能实现变量修改的可见性,但无法保证原子性,不会造成线程的阻塞

volatile的作用:

是一个轻量级的线程同步机制,特征之一:保证变量在线程之间的可见性。

所谓的可见性是指当一个线程修改了变量的值之后,其他线程可以感知该变化。

为什么会有可见性问题?

因为硬件速度不匹配问题,CPU的速度要明显快于主内存

为了解决速度不匹配问题,在CPU和主内存之间有多级缓存。

这个时候会发生,一个线程修改了数据,数据还没有及时刷到主内存,那么其他线程读取到的数据依然还是旧的,这就是可见性问题发生的根源。

通过给变量设置volatile关键字修饰,可以保证变量在线程修改之后,会刷新到共享内存,这样其他线程就可以读取到最新的内容。

volatile保证了在多个线程之间是可见的,但不能保证原子性操作。

当变量被声明为volatile之后,线程每次都会从主内存读取,而不会去读取自己的工作内存,这样实现了线程之间的可见性。

前后端分离,接口文档,:URL, 请求方式,请求参数,返回参数,示例

一般采用swagger生成接口文档

服务拆分:

  1. 抽取公共的基础服务(短信,邮件,文件管理)

  1. 以业务为边界,拆分服务

  2. 要管理这么一堆服务,需要注册中心(Eureka,zookeeper)

  3. 服务之间需要通信,通信方式:

        4.1 同步调用

            Dubbo,RPC的方式,底层采用Netty来实现,基于TCP建立的长连接

            注意:BIO,NIO只是一种网络通信模式

            BIO( Blocking I/O ):为每个连接建立一个线程

            NIO( Non-blocking I/O):一个线程服务多个连接,有弊端,当连接数太多,性能下降

            Netty:封装NIO,在它的基础上,添加注册处理组,BossGroup,WorkerGroup

            编程思想:Reactor(反应堆)思想,NIO,Netty是一种实现

            SpringCloud ,restful http的方式,短连接的方式

            性能角度: Dubbo>SpringCloud

        4.2异步通知

                MQ调用方无需等待执行放处理的结果

    5.服务之间的共享资源,如何保证数据的安全性

        

        单体架构:单机部署的时候,采用JDK提供的synchronized就可以实现

        分布式架构:多机部署的时候(多个JVM),上面的方式就不能满足,只能控制一个JVM

        分布式锁的方案:保证锁是共享的第三方资源,1.上锁,2.解锁

        数据库的方式:t_lock ,id lock(0)

        上锁:将数值修改为1

        解锁:将数值修改为0

        

        数据库:创建一张表,t_lock,其中包含字段,lock(1),默认为0,有客户获得锁,将其置为1

        

        Redis:setnx: 不存在就设置成功,否则,设置失败(最终可用性,AP模式,可用性要高些)

        上锁:成功执行setnx key value

        解锁:delete key

        避免死锁:需要设置过期时间expire key timeout

        注意:需要将两个操作变成一个原子操作

        4.0之前:Redis+lua脚本 ,lua脚本帮助我们扩充Redis指令

        4.0之后:直接使用线程的指令,在设置数据的时候,同时设置时间

        避免无锁:释放锁的时候,检查这把锁是不是我的

        zookeeper:采用树状节点的方式来保存我们的服务的注册信息(znode)

        以节点作为锁,创建成功,表示获取锁成功

        上锁:创建节点lock

        解锁:删除结点lock

        避免死锁:节点,为临时节点类型,客户端如果挂掉,会自动删除

        节点分:持久性、非持久性(临时节点)

        存在“羊群效应”:一旦锁失效后,假设有上百个客户端都会去争抢这个锁

        解决方法:时序节点(节点有序号)

Eureka:

EurekaServer的注册表存储结构,采用内存的方式来管理服务信息。map结构

服务注册:新增一个key-value的映射关系

服务发现:获取一个key-value的映射集合

ConcurrentHashMap:一个线程安全且性能兼顾的map(HashTable:线程安全,但性能一般)

  1. 解决服务之间的session共享问题:

有状态:服务器依然要存储用户的信息生成cookie(user_token:uuid),从而来帮助我们确定存储在Redis中的用户凭证信息

此处的UUID等同于之前的sessionid,有状态的方式需要消耗一定的内存空间来存储用户信息

无状态:服务器不需要保存用户的状态,但是需要耗费一定的CPU资源来计算

基于一种算法的方式:JWT(JSON WEB Token)

token:用户本身信息+时效信息

依赖于解析结果,如果发生异常,说明凭证已经失效,如果没有异常,说明状态正常。

cookie之所以能够成功,有一个非常重要的前提:所有的子系统都是同父域的情况,无法实现跨域

如何理解CAP

C:一致性,每一次请求得到的数据是一样的,每个节点保存的数据是一致的

A:可用性,每次请求都可以得到正确的响应,但是数据不一定是最新的

P:分区容错性,

    分区:是一种现象,由于网络的不稳定性,造成部分节点之间的通信出现了问题,于是就产生了分区

    容错性:是一种目标,就是发生分区之后,服务的节点是否能对外提供服务

QPS:query每秒可以处理的查询请求量

TPS:transaction事务,每秒可以处理的事务请求数量

响应时间,处理一次请求消耗的时间

吞吐量:单位时间可以处理的请求数量

并发量:同一时刻有多少请求访问服务器

PV:page view当前页面被访问的次数

UV:user view当前被多少用户访问

日活:一天活跃用户

调优,通过压力测试工具,以上性能指标有没有变化

如何应对高并发?

1.垂直升级

    单机硬件升级

    摩尔定律

2.水平扩展升级

    单机的硬件发展速度跟不上业务的发展速度

    所以我们要求采用水平扩展升级的方案,这样在理论上,只有增加机器就可以让处理能力无限扩展

3.整体的基数架构图

    三大法宝:限流,缓存,熔断

如何实现分布式系统的数据一致性问题(分布式事务)

之前我们控制事务的实现非常简单

1编写一个service方法,里面可以做多个dao操作,然后再seervice方法上实现事务的控制

,使用SpringAOP实现了事务的控制

2,局域数据库本身的事务机制,从而保证数据的原子性

现在结构发生了变化,所以原先的解决方案没用了

采用分布式事务,实现类似上述达到的效果

1.刚性事务,依然要么都成功,要么都失败

    2PC,TCC

2.柔性事务,追求的是数据的最终一致性,允许出现中间状态

    基于MQ方式来实现

    生产者 --> MQ --> 消息消费者(各种服务)

关键点:MQ如何保证消息可达(不丢失)

对BASE理论的理解

BA(basiclly available)基本可以

S (soft state)柔性状态

E (Eventual Consistency)最终一致性

BASE理论,通过牺牲强一致性,保证最终一致性,来获取高可用性

谈谈Dubbo

Dubbo的底层网络通信是基于Netty网络框架,而Netty是对NIO的封装

NIO可以多路复用,效率高

SpringCloud是一系列主流框架的集合,基于SpringBoot进行开发

屏蔽了复杂的配置和实现原理,给用户提供的一套简单易懂,容易不是,容易维护的分布式系统开发工具集

解决的是非业务的共性问题

集成了:服务注册与服务发现(注册中心):Eureka Server

负载均衡:Ribbon

熔断: Hystrix

配置中心: config server

网关:Zuul,SpringCloudGatway

消息总线:

链路监控:zipkin server

做到独立部署,可方便进行水平扩展,独立访问等特点

Spring Cloud VS Dubbo

1.Dubbo,RPC,性能比http性能好,并发能力强

2.springcloud,http协议,性能差些

3.springcloud主打微服务架构全家桶,组件齐全,功能齐全

4.融合,springcloud融合其他组件,如springcloud alibaba

适合缓存的数据:

1.高频访问数据

2.变化频率不高

2.非敏感数据

Redis基本数据类型:

string:用户信息,分布式锁,验证码,(点赞,点踩,数字)

hash:可以快速定位,需要存储信息,且这个信息需要频繁被修改时,就可以采用这个结构

list:队列和栈,双向列表(秒杀,保存待抢购的商品列表)

set:无序唯一(唯一,秒杀,保存抢购到商品的幸运用户,保证每个人每件商品只能抢购一件)

zset:可排序特性,分数(数值,可排序,排行榜)

Redis内存回收:

1.惰性回收,执行get指令,刚好这个key已经过期了,那么这个时候会自动删除

2.采用定时回收的方式 10/s

3.具体回收算法:

    TTL:过期时间

     LRU:最近最少使用,采样方式

Redis持久化策略

1.RDB,产出二进制文件,默认开启

save 900 60

触发持久化,并非实时的方式,适合做全量备份

2.AOF,产出日志文件,默认不开启

触发时机:每秒*(推荐),每次操作

如何实现缓存的高可用?

单点情况,放生故障对系统造成很大影响

实现:

主从方式,同时有哨兵这个服务来监控主从节点的健康状况

当主节点宕机,此时哨兵服务具体要做什么呢?

1.哨兵要选择一台从机器作为新主机,这里面有一个关键指标,就是偏移量,这个是来看主机跟从机数据同步的状态,执行指令:slaveof no master

2.其他的从机要重新建立跟新主机的关系,slaveof newip newport

3.客户端是连接哨兵服务的,所以哨兵服务会给客户端返回新的主机地址

哨兵服务监控主机的情况,主机保存从机的信息,所以哨兵也会监控从机的状况

RedisCluster:

redis3.0之后的版本提供的特性

特点:

1.没有中间层,客户端直接更RedisCluster的节点进行连接

2.每个主节点都支持读写操作,分担了写的压力,后期继续增加新主机,然后做hash迁移,新主机就可以分担压力

3.因为每个节点负责的区域是不同的,所以往里面保存数据的时候,要根据key来做crc16算法,从而得到一个值,从而确定存储哪个节点

4.为了保证每个节点的高可用,所以每个节点可以做主从

消息中间件应用场景:

适合的场景:不需要实时性的

1.解耦

2.异步化

3.限流削峰:前后两个交互的系统处理的速度不匹配,为了保护处理慢的系统,从而引入消息中间件,来实现削峰限流处理

方案1 ,异步写的方案,保护数据库,缓解瞬间写的压力

方案二:比如秒杀系统,会产生很多订单消息,此时也可以通过MQ来保护订单系统,节省服务器成本

OCP原则:对修改关闭,对扩展开放

如何保证消息的可达或不丢失

1.确认机制+补偿发送

异步confirm模式,客户端通过设置comfirm监听器,获取MQ服务器的异步响应。如果消息成功传递到MQ服务器,则服务器会传递回ACK=true,否则ack=false

消息队列做持久化,宕机后重启不会丢失未处理的消息

消费端的手工确认模式开启,只有消费端手动确认后,才表示这个信息已经被正确处理

避免消息重复处理依然失败的情况,设置重复处理3尺,如果3次还有问题,则错误信息记录到日志表,然后人工介入处理,

避免堵塞后面的消息处理

有可能MQ服务器没有收到消费端发送的确认消息,会重复处理,所以要保证接口的幂等性,不会被重复消费

延迟队列?

需要延迟处理的消息,我们将使用延迟队列来达到这个效果

 消息超过了有效期,没有人处理,就称为死信

限流降级:

Nginx

计数器

滑动时间窗口

令牌桶、漏桶算法

Hystrix

防刷验证码

流量削峰

秒杀下单接口地址隐藏

秒杀系统高阶优化:

Redis缓存高可用集群,Redis单机大概支持几万并发

独立秒杀服务

前端优化:

    页面静态化

    页面资源优化

      js/css压缩,减少流量

    JS/css组合,减少连接数

    CDN优化

Redis缓存雪崩:

大量缓存在同一时间失效,导致数据库访问量瞬间上升,导致无法正常提供服务

解决办法:

设置随机缓存失效时间

Redis集群 部署,不同热点的key放到不同的节点上去

不设置缓存失效时间(暴力解法)

定时刷缓存

缓存穿透:

使用不存在的参数发起请求,Redis查不到这样的数据,然后就会把请求打到数据库上

解决办法:

如果请求穿透Redis,无论数据库查询到什么结果都缓存到Redis,下次请求就不会穿透Redis

可以拉黑IP

校验参数合法性

使用布隆过滤器

缓存击穿:

当某一个非常热点的key失效的时候把大量请求打到数据库,导致服务失效

解决办法:

缓存永远不过期

分布式锁,互斥锁:请求数据库的时候上锁,只能由一个用户能操作这个数据库,然后把查询结果缓存到Redis,其他没有抢到的线程先睡几毫秒,可以使用zookeeper实现这个分布式锁

分布式锁

1.基于数据库

2.基于缓存(Redis等)

3.基于Zookeeper

基于数据库缺点:

  1. 强依赖于数据库,数据库是一个单点,一旦数据库挂掉,会导致业务系统不可用

  2. 锁没有失效时间,一旦解锁操作失败,就会导致锁记录一直在数据库中,其他线程无法再获得锁

  3. 这把锁只能是非阻塞的,因为数据的insert操作,一旦插入失败就会直接报错,没有获得锁的线程并不会进入排队队列,要想再次获得锁就要再次触发获得锁操作

  4. 这把锁是非重入的,同一个线程在没有释放锁之前无法再次获得该锁,因为数据库中数据已经存在

解决方案:

  1. 做主从数据库,数据之间双向同步,一旦主库挂掉迅速切换到从库

  2. 做一个定时任务,每隔一段时间把数据库中超时的数据清理一遍

  3. 搞个while循环,直到insert成功再返回成功

基于Redis缺点:

在主从结构中存在明显的竞态:

    客户端A从master获取到锁,

    在master将锁同步到slave之前,master宕掉

    slave节点被晋级为master节点

    客户端B获取了同一个资源被客户端A已经获取到的威朗我一个锁。安全失效。

Zookeeper的数据存储结构就像一棵树,这棵树由节点组成,这种节点叫做Znode

Znode分四种类型:

  1. 持久节点(Persistent),默认类型,创建节点的客户端和zookeeper断开连接后,该节点依旧存在

  2. 持久节点顺序节点(Persistent_sequential),根据创建的时间顺序给该节点名称进行编号

  3. 临时节点(Ephemeral),创建连接的客户端与zookeeper断开链接后删除节点

  4. 临时顺序节点(Ephemeral_sequential)

Zookeeper分布式锁原理:

Zookeeper分布式锁应用了临时顺序节点

详细步骤:

获取锁:

    首先在Zookeeper中创建一个持久节点ParentLock,在第一个客户端想要获取锁时,需要在Parentlock这个结点节点下面创建一个临时顺序节点Lock1

    之后,Client1查找ParentLock下面所有的临时顺序节点并排序,判断自己所创建的节点Lock1是不是顺序最靠前的一个。如果是第一个节点,则成功获取锁。

    这时候,如果有一个客户端Client2前来获取锁,则在ParentLock下再创建一个临时顺序节点Lock2,

client2查找parentLock下面的所有临时顺序节点并排序,判断Lock2是不是顺序最靠前的节点,发现节点Lock2并不是最小的。于是,client2向排序仅比它靠前的节点Lock1注册Watcher,用于监听lock1节点是否存在,这意味着client2抢锁失败,进入等待状态。

    如果又有client3前来获取锁,就会在parentlock下新建临时顺序节点lock3,发现自己不是顺序最靠前的节点,于是就向排序比它前的lock2注册watcher。如果后面还有新的客户端,就在前面的临时节点注册一个watcher,形成一种链。

释放锁:

任务完成,客户端显示释放

任务执行过程中,客户端崩溃,相关联的节点会自动删除

前面的节点删除,监听它的客户端就会立刻收到通知,这时后面的节点会再次查询parentlock下面的所有节点,确认自己创建的节点是不是目前最小的节点,如果是最小的就获得锁,否则继续等待。

缺点:

性能上可能没有缓存服务那么高,因为每次在创建锁和释放锁的过程中,都要动态创建、销毁临时节点来实现锁功能。ZK中创建和删除节点只能通过Leader服务器来执行,然后将数据同步到所有的Follower机器上。

可能带来并发问题,只是不常见。由于网络抖动,客户端可ZK集群的session连接断了,那么zk以为客户端挂了,就会删除临时节点,这时候其他客户端就会获取到分布式锁了,就可能产生并发问题。这个问题不常见是因为zk有重试机制,一旦zk集群检测不到客户端的心跳,就会重试,Curator客户端有多种重试策略,多次重试之后还不行的话才删除临时节点。

Redis速度快的原因:

  1. 基于内存,时间花费主要集中在IO上,所以读取速度很快

  2. 单线程模型,保证每个操作的原子性,不用进行线程之间的切换和竞争

  3. 使用非阻塞IO,IO多路复用,使用了单线程来轮训描述符,将数据库的开、关、读、写都转换成了事件,减少了线程的上下文切换和竞争

  4. 全程使用hash数据结构,还有特殊的数据结构,对数据存储进行了优化,如压缩表,对短数据进行压缩存储,再如跳表,使用有序的数据结构加快读取的速度

  5. Redis采用自己实现的事件分离器,效率高,内部采用非阻塞的执行方式,吞吐能力比较大

IO多路复用技术详解:

同步阻塞IO(Blocking IO)

同步非阻塞IO(Non-blocking IO)

IO多路复用(IO Multiplexing)(异步阻塞IO)(最常使用)( Reactor反应堆设计模式 )

异步IO(Asynchronous IO)( Proactor设计模式 )

IO多路复用模型是建立在内核提供的多路分离函数select基础之上,使用select函数可以避免同步非阻塞IO模型中轮询等待的问题。

使用select以后最大的优势是用户可以在一个线程内同时处理多个socket的IO请求。用户可以注册多个socket,然后不断地调用select读取被激活的socket,即可达到在同一个线程内同时处理多个IO请求的目的。而在同步阻塞的模型中,必须通过多线程的方式才能达到这个目的。

dubbo心跳机制

网络层的可用性:使用了TCP中的keepAlive机制

应用层的连接可用性:心跳机制

就是客户端会开启一个定时任务,定时对已经建立连接的对端应用发送请求,服务端需要特殊处理该请求,返回响应。如果心跳持续多次没有收到响应,客户端会认为连接不可用,主动断开连接。

Netty提供一个经典的时间轮询定时器实现心跳机制

Dubbo采用双向心跳设计,即服务端会向客户端发送心跳,客户端也会向服务端发送心跳,接收方更新lastread字段,发送方更新lastwrite字段,超过心跳间隙的时间,便发送心跳请求给对端

长连接和短连接

HTTP1.1规定了默认保持长连接,数据传输完成了保持TCP连接不断开,等待在同域名下继续用这个通道传输数据;相反就是短连接。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值