NIO:一个请求一个线程,但客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。
NIO的特点:事件驱动模型、单线程处理多任务、非阻塞I/O,I/O读写不再阻塞、基于block的传输比基于流的传输更高效、更高级的IO函数zero-copy、IO多路复用大大提高了Java网络应用的可伸缩性和实用性。基于Reactor线程模型。
NIO是面向缓冲区的,而传统IO是面向流的。
2. NIO的三大核心部分
NIO主要包括:java.nio.channels包中的Selector和Channel抽象,java.nio包中的Buffer抽象。
a) Channel和IO中的Stream(流)是差不多一个等级的。只不过Stream是单向的,譬如:InputStream, OutputStream.而Channel是双向的,既可以用来进行读操作,又可以用来进行写操作。Channel是数据的源头或者目的地,用于向buffer提供数据或者读取buffer数据。
b) Buffer是一块连续的内存块,是NIO数据读写的中转地。
c) Selector,异步 IO 的核心类,它能检测一个或多个通道 (channel) 上的事件,并将事件分发出去。使用一个 select 线程就能监听多个通道上的事件,并基于事件驱动触发相应的响应。而不需要为每个 channel 去分配一个线程。
3. NIO的服务端建立过程
4. Selector.open():打开一个Selector;ServerSocketChannel.open():创建服务端的Channel;bind():绑定到某个端口上。并配置非阻塞模式;register():注册Channel和关注的事件到Selector上;select()轮询拿到已经就绪的事件
5. Reactor线程模型
a) 单线程模型
b) 多线程模型
c) 主从多线程模型
6. Netty的线程模型
Netty通过Reactor模型基于多路复用器接收并处理用户请求,内部实现了两个线程池,boss线程池和work线程池。Boss线程池负责处理请求的accept事件,把对应的socket封装到一个NioSocketChannel中,并交由work线程池处理;work线程池负责请求的read和write事件,而事件处理过程交由具体的handler处理(参考Reactor的主从多线程模型)
7. Netty的特点
a) 并发高——NIO的Reactor模型(基于事件驱动的设计模式)
b) 传输快——数据直接从IO读到内存。Netty通过ByteBuf实现零拷贝
c) 封装好——通过channel、Bytebuf、code的封装提升易用性
8. Netty的零拷贝实现原理
Netty的接收和发送ByteBuffer采用DIRECT BUFFERS,使用堆外直接内存进行Socket读写,不需要进行字节缓冲区的二次拷贝。堆内存多了一次内存拷贝,JVM会将堆内存Buffer拷贝一份到直接内存中,然后才写入Socket中。
9. Dubbo的架构
Provider: 暴露服务的服务提供方
Consumer: 调用远程服务的服务消费方
Registry: 服务注册与发现的注册中心
Monitor: 统计服务的调用次调和调用时间的监控中心
Container: 服务运行容器
10. Dubbo的通信协议
a) Dubbo——默认的,单纯长连接、NIO异步通信协议。适合数据量小、并发的的场景
b) RMI、Hessian、Http、websocket
11. Dubbo默认使用什么序列化框架
默认使用Hessian序列化,还有Duddo、FastJson、Java自带序列化。
12. 服务提供者能实现失效踢出是什么原理?
zookeeper中节点是有生命周期的.具体的生命周期取决于节点的类型.节点主要分为持久节点、持久顺序节点、临时节点、临时顺序节点。
所谓持久节点,是指在节点创建后,就一直存在,直到有删除操作来主动清除这个节点,也就是说不会因为创建该节点的客户端会话失效而消失。
临时节点的生命周期和客户端会话绑定,也就是说,如果客户端会话失效,那么这个节点就会自动被清除掉。
在分布式系统中,我们常常需要知道某个机器是否可用,ZK中我们让所有的机其都注册一个临时节点,我们判断一个机器是否可用,我们只需要判断这个节点在ZK中是否存在就可以了,不需要直接去连接需要检查的机器,降低系统的复杂度。
13. dubbo中zookeeper做注册中心,如果注册中心集群都挂掉,那发布者和订阅者还能通信吗?
可以的,消费者在启动时,消费者会从zk拉取注册的生产者的地址接口等数据,缓存在本地。每次调用时,按照本地存储的地址进行调用。
14. 测试和生产环境公用一套zookeeper,如何保证消费不冲突
a) 通过自定义Filter来实现IP白名单功能
b) 通过service分组功能实现
c) 通过版本控制实现
15. Dubbo集群容错怎么做?
读操作建议使用Failover失败自动切换,默认重试两次其他服务器。写操作建议使用Failfast快速失败,发一次调用失败就立即报错。
16. zookeeper是如何保证事务的顺序一致性的
zookeeper采用了递增的事务Id来标识,所有的proposal都在被提出的时候加上了zxid,zxid实际上是一个64位的数字,高32位是epoch用来标识leader是否发生改变,如果有新的leader产生出来,epoch会自增,低32位用来递增计数。当新产生proposal的时候,会依据数据库的两阶段过程,首先会向其他的server发出事务执行请求,如果超过半数的机器都能执行并且能够成功,那么就会开始执行
17. zookeeper的leader选举
当leader崩溃或者leader失去大多数的follower,这时候zk进入恢复模式,恢复模式需要重新选举出一个新的leader,让所有的Server都恢复到一个正确的状态。Zk的选举算法使用ZAB协议:
a) 选举线程首先向所有Server发起一次询问
b) 收到所有Server回复以后,就计算出zxid最大的那个Server,并将这个Server相关信息设置成下一次要投票的Server
c) 线程将当前zxid最大的Server设置为当前Server要推荐的Leader,如果此时获胜的Server获得n/2 + 1的Server票数, 设置当前推荐的leader为获胜的Server
18. 客户端对zookeeper serverList的轮询机制
Zookeeper初始化的过程中会将server保存在一个list中,然后随机打散,之后从0号位一个一个使用
19. 创建的临时节点什么时候会被删除,是连接一断就删除吗?延时是多少?
连接断了之后,ZK不会马上移除临时数据,只有当session失效之后,才会把这个会话建立的临时数据移除。
20. ZooKeeper集群中服务器之间是怎样通信的?
Leader服务器会和每一个Follower/Observer服务器都建立TCP连接,同时为每个F/O都创建一个叫做LearnerHandler的实体。LearnerHandler主要负责Leader和F/O之间的网络通讯,包括数据同步,请求转发和Proposal提议的投票等。Leader服务器保存了所有F/O的LearnerHandler。
21. 出现调用超时com.alibaba.dubbo.remoting.TimeoutException异常怎么办?
通常是业务处理太慢,可在服务提供方执行:jstack PID > jstack.log 分析线程都卡在哪个方法调用上,这里就是慢的原因。如果不能调优性能,请将timeout设大。
22. 出现java.util.concurrent.RejectedExecutionException或者Thread pool exhausted怎么办?
RejectedExecutionException表示线程池已经达到最大值,并且没有空闲连,拒绝执行了一些任务。原因可能是连接池不够用。
Thread pool exhausted通常是min和max不一样大时,表示当前已创建的连接用完,进行了一次扩充,创建了新线程,但不影响运行。
调整dubbo.properites中的:
// 设成一样大,减少线程池收缩开销
dubbo.service.min.thread.pool.size=200
dubbo.service.max.thread.pool.size=200
23. Spring中IOC的实现原理。
Spring中的IoC的实现原理就是工厂模式加反射机制。IOC中最基本的技术就是“反射(Reflection)”,通俗来讲就是根据给出的类名来动态地生成对象,这种编程方式可以让对象在生成时才被决定到底是哪一种对象。在Spring中要生产的对象都在配置文件中给出定义,目的就是提高灵活性和可维护性。
Spring IOC 负责创建对象,管理对象(通过依赖注入(DI),装配对象,配置对象,并且管理这些对象的整个生命周期。
24. Spring AOP解决了什么问题?怎么实现的?
面向切面编程主要的目的是将业务代码和通用代码分离,将通用代码(入事务、日志)抽离,从而降低应用程序的复杂度的一种编程思想。
Spring aop 采用动态代理机制,在代码运行期间为目标对象生成一个代理对象,而将横切对象织入到这个代理对象中,系统使用这个代理对象,而不是真正的目标对象。
JDK的动态代理——通过反射和动态编译实现的
Cglib的动态代理——通过集成方式做动态代理
25. spring的依赖注入有哪几种方式
a) setter注入
b) 构造器注入
26. SpringMVC处理请求的流程。
a) DispatcherServlet收到请求并进行映射路径匹配
b) 根据请求到HandlerMapping中获取对应的处理器
c) 处理请求并返回ModelAndView模型给dispatcher
d) Dispatcher借助视图解析器解析完成逻辑视图名到真正视图名的解析工作
e) 得到真正试图对象view后,dispatcher就使用这个view对modelAndview进行渲染
27. Mybatis中,#{}和${}的区别是什么?
#{}是预编译处理,${}是字符串替换。
Mybatis在处理#{}时,会将sql中的#{}替换为?号;
Mybatis在处理${}时,就是把${}替换成变量的值。
使用#{}可以有效的防止SQL注入,提高系统安全性。
28. 当实体类中的属性名和表中的字段名不一样,怎么办?
a) 通过在查询的sql语句中定义字段名的别名,让字段名的别名和实体类的属性名一致
b) 通过
29. Mybatis是如何进行分页的?分页插件的原理是什么?
Mybatis使用RowBounds对象进行分页,它是针对ResultSet结果集执行的内存分页,而非物理分页,可以在sql内直接书写带有物理分页的参数来完成物理分页功能,也可以使用分页插件来完成物理分页。分页插件的基本原理是使用Mybatis提供的插件接口,实现自定义插件,在插件的拦截方法内拦截待执行的sql,然后重写sql,根据dialect方言,添加对应的物理分页语句和物理分页参数。
30. 在mapper中如何传递多个参数?
a) 使用占位符#{0}
b) 使用@param注解
31. MyBatis中批量插入
a) 设置ExecutorType.BATCH,然后利用动态sql的foreach拼接sql实现批量插入。
b) 坑:
i. 里的内容会被解析器忽略,因此使用动态sql时不要用
ii. 单次插入数据量过大时,在同一事务范围内,分批commit insert batch
iii. 使用insert table values () (),而不是多个insert拼接
32. Kafka的架构
33. Kafka的几个基本概念
a) Topic:特指Kafka处理的消息源(feeds of messages)的不同分类。
b) Partition:Topic物理上的分组,一个topic可以分为多个partition,每个partition是一个有序的队列。partition中的每条消息都会被分配一个有序的id(offset)。
c) Message:消息,是通信的基本单位,每个producer可以向一个topic(主题)发布一些消息。
d) Producers:消息和数据生产者,向Kafka的一个topic发布消息的过程叫做producers。
e) Consumers:消息和数据消费者,订阅topics并处理其发布的消息的过程叫做consumers。
f) Broker:缓存代理,Kafka集群中的一台或多台服务器统称为broker。
34. Kafka消息发送的流程
Producer根据指定的partition方法(round-robin、hash等),将消息发布到指定topic的partition中
kafka集群接收到Producer发过来的消息后,将其持久化到硬盘,并保留消息指定时长(可配置),而不关注消息是否被消费。
Consumer从kafka集群pull数据,并控制获取消息的offset
35. Kayka的设计要点
a) 直接使用linux文件系统的cache,来高效缓存数据。
b) 采用linux Zero-Copy提高发送性能。
c) 数据在磁盘上存取代价为O(1)。
d) 显式分布式,即所有的producer、broker和consumer都会有多个,均为分布式的。Producer和broker之间没有负载均衡机制。broker和consumer之间利用zookeeper进行负载均衡。
36. 我们可以在没有Zookeeper的情况下使用Kafka吗?
不可能越过Zookeeper,直接联系Kafka broker。一旦Zookeeper停止工作,它就不能服务客户端请求。
a) Zookeeper主要用于在集群中不同节点之间进行通信
b) 在Kafka中,它被用于提交偏移量,因此如果节点在任何情况下都失败了,它都可以从之前提交的偏移量中获取
c) 除此之外,它还执行其他活动,如: leader检测、分布式同步、配置管理、识别新节点何时离开或连接、集群、节点实时状态等等。
37. 在数据制作过程中,你如何能从Kafka得到准确的信息?
为了精确地获得Kafka的消息,你必须遵循两件事: 在数据消耗期间避免重复,在数据生产过程中避免重复。
这里有两种方法,可以在数据生成时准确地获得一个语义:
a) 每个分区使用一个单独的写入器,每当你发现一个网络错误,检查该分区中的最后一条消息,以查看您的最后一次写入是否成功
b) 在消息中包含一个主键(UUID或其他),并在用户中进行反复制
38. 什么是ISR?
ISR是一组与leaders完全同步的副本同步队列,也就是说ISR中包含了所有提交的消息。ISR应该总是包含所有的副本,直到出现真正的故障。如果一个副本从leader中脱离出来,将会从ISR中删除。
39. Kafka的复制原理
为了提高消息的可靠性,Kafka每个topic的partition有N个副本(replicas),其中N(大于等于1)是topic的复制因子(replica fator)的个数。Kafka通过多副本机制实现故障自动转移,当Kafka集群中一个broker失效情况下仍然保证服务可用。
40. kafka数据可靠性保证
当producer向leader发送数据时,可以通过request.required.acks参数来设置数据可靠性的级别:
a) 1(默认):这意味着producer在ISR中的leader已成功收到的数据并得到确认后发送下一条message。如果leader宕机了,则会丢失数据。
b) 0:这意味着producer无需等待来自broker的确认而继续发送下一批消息。这种情况下数据传输效率最高,但是数据可靠性确是最低的。
c) -1:producer需要等待ISR中的所有follower都确认接收到数据后才算一次发送完成,可靠性最高。