003-常见问题整理

     熟悉Java虚拟机原理,Java高级特性和类库,Java网络与服务器编程,Java多线程编程,常见开源产品,精通1-2种常见开源产品的实现原理;

    理解tcp协议各种状态流转、以及原理,理解linux epoll等网络io模型,理解netty/mina等网络框架的实现原理;

 

1. 基础知识相关:

    1.1 mongo集群架构:

          副本集:集群当中包含了多份数据,保证主节点挂掉了,备节点能继续提供数据服务,提供的前提就是数据需要和主节点一致。默认设置下,主节点提供所有增删查改服务,备节点不提供任何服务。但是可以通过设置使备节点提供查询服务,这样就可以减少主节点的压力,当客户端进行数据查询时,请求自动转到备节点上。

          主从:官方不推荐,主节点挂掉后,备节点不能提供服务。

          分片:最为复杂,大数据,Sharding才能显现威力,毕竟备节点同步数据是需要时间的。请求分发、结果组合也需要时间。

 

    1.2 CMS垃圾回收器:

        a) 主要针对老年代的数据进行GC;

        b)  七个过程:初始标记(标记老年代的root)、并发标记、预清理、重标记(扫描整个堆,包括新生代,因为有可能新生代重新引用老年代)、并发清理、重置整理。

        其中:初始标记,单线程,应用会暂停;重标记,多线程,应用会暂停

        c) CMS重标记时间较长,原因在于扫描整个堆,CMSMaxAbortablePrecleanTime 可以设置预清理执行多长时间进行一次minorGC;

        d) 清理完成后没有碎片整理步骤,即只删除但是不整理。对大对象的分配会有问题,有可能提前触发fullGC;

        e) G1回收器:一是在内存清理后增加了内存整理功能;二是在CMS基础上增加分区/分块的概念,一块一块处理。

 

    1.3 性能问题排查常用工具:

         a) top命令、top -Hp pid命令,查看各线程的CPU使用情况,找到cpu占用率高的线程;

               jstack pid命令,查看进程下的各线程状态,找到对应的线程情况,分析线程堆栈信息;

         b) jstat命令,查看包括新老GC的次数,时间,新老代内存使用量等数据;

         c) jmap dump内存文件,分析占比最大的数据及产生的源头;

                jmap -histo 打印每个class的实例数目,内存占用,类全名信息,在线分析内存数据;

          

    1.4 paxos与zab协议:

        a) paxos没有解决活锁的问题,运行过程中无leader;

        b) paxos直接应用到工业界会比较复杂,工业界往往根据使用场景有所改造和舍弃;

        c) paxos没有解决时序的问题;

    1.5 zab协议:

        a) zab协议在paxos基础上发展而来,引入leader,解决paxos活锁,同时为了解决单leader存在的单点问题,又扩展了包括选举、发现、同步、广播等功能;

        b) 为每个事务生成全局递增的唯一id,保证时序性;

        c) 崩溃时的恢复,能快速选出leader,并恢复数据。

 

    1.6 并发包的使用:

         包括:volatile、AtomicInteger,Synchronized, 锁优化与膨胀, TheadLocal类, 线程池,

         

 

2. 遇到的线上问题及解决方式:

    2.1 mongo主从数据不一致导致的数据统计上的问题:

         线上mongo数据库采用副本集的集群架构,那么在时序非常严格的操作下(先更新,然后立刻进行统计数据),这是有可能出现主从节点数据不一致导致的

 

    2.2 mongo数据处理超时:

              更新:mongo数据量大,更新时索引列key有变化,长度超长,插入超时。

              查询:无索引,有索引但是不恰当使用索引列,如范围查询,索引列上有计算。

 

    2.4 内存溢出导致系统挂掉:

         批量查询没有范围限制,或有无参数出错导致查询大批量的数据,内存被占满;

         导出操作时,无参数范围限制,也没有并行度控制,导致内存使用过大,溢出;

 

    2.5 新生代、老年代比例设置导致老年代频繁GC:

         新生代设置过下,导致晋升老年代的动态年龄降低,大量数据晋升到老年代,导致老年代数据过多,频繁触发GC;

 

    2.6 CMS重标记时间过长导致的应用中断时间过长,请求处理超时:

         时效性和并发度都很高的基础服务,在高峰期会出现请求延时的情况,分析得知延时时发生了GC,然后判断是重标记时间过长导致的服务中断;最后设置在重标记前强制执行monirGC,降低重标记的时间;

 

    2.7 大List(10万级数据量)求交集,导致CPU使用率100%;

         缓存队列list设计不合理,导致存储数据量过大(数量达到10万级),当进行交集运算时会出现CPU被耗尽;

 

3. 设计模式与源码相关:

    3.1 常用设计模式:

         a) 单例、工厂方法这些基本设计模式;

         b) 适配器,各种请求参数、实体bean的转换,例如风控SDK对业务方请求参数的统一封装;

         c) 动态代理,如自定义注解、AOP、myBatis的使用;

         d) 职责链与过滤器,如权限校验、请求参数校验这些;

         e) 模板方法:风控引擎对策略执行,统一按固定模板来执行,先获取和解析请求对应的策略、特征、再从数据网关取数据、运行规则、策略,然后命中的规则取处罚结果。

 

    3.2 myBaits设计:

          动态代理,myBatis也就是JDK动态代理的引用,二级缓存、一级缓存;

 

    3.3 AOP动态代理:

          a) JDK动态代理,CGLib动态代理;JDK为什么需要接口,通过反射调用,是需要知道类型,包括参数类型,结果类型等;

          b) Cglib运行效率更高,但创建效率低。Cglib不能代理final修饰的类。

 

4. 系统建设与架构:

    4.1 riskcenter优化与设计:

         a) 稳定性: 代码层面上,会有请求参数校验、异常捕捉与出现错误后返回默认结果等降级方案;重点模块和请求处理结果的监控、日志;

         b) 部署上:多节点部署是基本,不同业务线上的独立部署(如众悦和专车),做到物理上的隔离;

         c) 外部请求的隔离与限流:对不同类型请求的线程池的隔离和限流,然后在外部SDK、内部接口层做了双重流量的控制机制;

         d) 高效性:处理的时延上,对外部请求都会有超时中断的设置,比如下游数据网关的调用,超时后直接返回默认值;

         e) 本地数据预加载:本地缓存的使用,如规则、策略、特征的配置等数据。

   

     4.2 mihuan的设计:

         a) 基于同一接口下的不同实现(即多态),来处理不同数据源的数据查询问题,如es、cois集群、大数据指标仓库、以及dubbo接口;

         b) 目的是隔离不同数据源的操作,避免相互干扰和影响;

         c) 隔离开后,能够对不同数据源的数据进行并行处理,降低整个数据操作的时延,提升效率;

         d) 为后续接入其他数据源,提供了比较方便的扩展接口;     

 

5. jstorm、flink对比:

    5.1  jstorm在设计上是专用于流式计算的,flink在设计上则是将批处理和流式计算合在一起;

     5.2 从部分测试数据来看,吞吐量和延迟两个指标上,flink表现都是优于jstorm的;

     5.3 jstorm有完善的后台后台管理、监控系统,ACK机制对每个消息进行全链路跟踪,在稳定性和可靠性上,比较让人放心。

 

6. NIO(同步非阻塞,多路复用io模型,实现I/O多路复用)

    6.1 NIO核心部分:selectors, channels, buffers

         channels: FileChannel(文件), DatagramChannel(UDP), SocketChannel(TCP), ServerSocketChannel(监听新进来的TCP连接);

         buffer: ByteBuffer,CharBuffer,DoubleBuffer,FloatBuffer,IntBuffer,LongBuffer,ShortBuffer;

    6.2 selectors: Selector允许单线程处理多个 Channel,通过SelectionKey的值来检测一到多个channel,并判断channel是否就绪;

            要使用Selector,得向Selector注册Channel,然后调用它的select()方法。这个方法会一直阻塞到某个注册的通道有事件就绪。

    6.3 channel:ServerSocketChannel 是一个可以监听新进来的TCP连接的通道,就像标准IO中的ServerSocket一样;每一个新进来的连接都会创建一个SocketChannel,用于和buffer交换数据。

 

7. netty框架:

     7.1 利用NIO的非阻塞通信模式,避免线程出现阻塞的情况; 由原来的阻塞读写(占用线程)变成了复用器(selector)轮询事件,selector寻找读写就绪的channel进行操作;

    7.2 在NIO基础上运用reactor线程模型(注册所有感兴趣的事件处理器,单线程轮询选择就绪事件,执行事件处理器):

         reactor单线程:所有事件在一个线程上,包括连接请求,读、写请求;

         reactor多线程:一个专门的线程监听服务端ServerSocketChannel,处理客户端连接请求;网络读、写由一组线程池负责,处理数据的读、写、编解码;

         主从Reactor线程模型:接收客户端连接的不再是个1个单独的NIO线程,而是一个独立的NIO线程池;Acceptor接收到客户端TCP连接请求处理完成后,新创建的SocketChannel注册到另一个线程池,由它来处理读、写,编解码事件;

    ps: Selector.select()操作是阻塞的(没有可干的事情必须要阻塞),所以不用担心CPU空转;

    7.3 高效的序列化框架:默认使用谷歌的Protobuf的序列化框架,以及非常方便的扩展接口;

    7.4 缓冲区buffer的设计,使用堆外直接内存进行Socket读写,不需要进行字节缓冲区的二次拷贝。

    7.5 epoll和select的比较:

         a) epoll 和select poll一样,一种I/O多路复用技术;

         b) 只关注活跃的连接,而无需遍历所有的描述符集合;它不会随着监听fd数目的增长而降低效率。因为在内核中的select实现中,它是采用轮询来处理的,轮询的fd数目越多,自然耗时越多。

         c) 对于select模型当有I/O事件到来时,select通知应用程序有事件到了快去处理,而应用程序必须轮询所有的FD集合;Epoll不仅会告诉应用程序有I/0事件到来,还会告诉应用程序相关的信息,这些信息是应用程序填充的,因此根据这些信息应用程序就能直接定位到事件,而不必遍历整个FD集合。

              

 

8. 扩展之AIO:

    8.1 JDK7开始支持异步IO(即AIO),包为nio2;

    8.2 BIO、NIO、AIO比较:

          BIO: 同步阻塞,一个连接由一个线程处理,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,可以通过线程池机制改善。

          NIO:同步非阻塞,客户端发送的连接请求都会注册到多路复用器(selector)上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。连接数目多且连接比较短(轻操作)的架构,例如聊天服务器,并发局限于应用中。

         AIO:异步非阻塞,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理。连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作。

 

9. 机器学习算法:

    1. 分类算法:决策树、随机森林、贝叶斯估计、K近邻、支持向量机、人工神经网络等;

    2. 聚类算法:核心“距离”,K-means聚类,最小生成树聚类等;

 

 

 

 

 

 

 

 

 

 

 

 

     

你可能感兴趣的:(003-常见问题整理)