面试10-20
11.Dubbo的架构设计是怎样的
Dubbo中的架构设计是非常优秀的,分为了很多层次,并且每层都是可以扩展的,比如:
- Proxy服务代理层,支持JDK动态代理、javassist等代理机制
- Registry注册中心层,支持Zookeeper、Redis等作为注册中心
- Protocol远程调用层,支持Dubbo、Http等调用协议
- Transport网络传输层,支持netty、mina等网络传输框架
- Serialize数据序列化层,支持JSON、Hessian等序列化机制
各层说明
- config配置层:对外配置接口,以ServiceConfig, ReferenceConfig 为中心,可以直接初始化配置类,也可以通过spring解析配置生成配置类
- proxy 服务代理层:服务接口透明代理,生成服务的客户端Stub和服务器端Skeleton, 以 ServiceProxy为中心,扩展接口ProxyFactory
- registry 注册中心层:封装服务地址的注册与发现,以服务URL为中心,扩展接口为RegistryFactory , Registry
- cluster路由层:封装多个提供者的路由及负载均衡,并桥接注册中心,以Invoker为中心,扩展接口为Cluster, Directory ,Router , LoadBalance。
- monitor监控层:RPC调用次数和调用时间监控,以Statistics为中心,扩展接口为MonitorFactory ,Monitor, MonitorService
- protocol远程调用层:封装RPC调用,以Invocation ,Result为中心,扩展接口为 Protocol, Invoker, Expoter
- exchange信息交换层:封装请求响应模式,同步转异步,以Request,Response为中心,扩展接口为Exchanger,ExchangeChannel , Exchangeclient ,ExchangeServer
- transport网络传输层:抽象mina和netty为统一接口,以Message为中心,扩展接口为(Channel, Transporter,Client,Server, Codec
- serialize数据序列化层:可复用的一些工具,扩展接口为Serialization , ObjectInput , ObjectOutput, ThreadPool
关系说明
- 在RPC中,Protocol是核心层,也就是只要有Protocol + lnvoker + Exporter就可以完成非透明的RPC调用,然后在Tlnvoker的主过程上Fiter拦截点。
- 图中的Consutmer和Provider是抽象概念,只是想让看图者更直观的了解哪些类分属于客户端与服务器端,不用Client和Sever的原因是Dube 在很多场景下都使用Provider, Consumier, Registry,Monitor划分逻辑拓普节点,保持统一概念。
- 而Cluster是外围概念,所以Cluster 的目的是将多个Inwvoker仿装成一个 lnvoker,这样其它人只要关注Protocol层Invcker即可,加上Cluster或者去掉(Cluster对其它层都不会造成影响,因为只有一个提供者时,是不需要Cluster的。
- Proxy 层封装了所有接口的透明化代理,而在其它层都以Inwvoker 为中心,只有到了暴露给用户使用时,才用Prory将 imvoker韩成接口,或将接口实现转成lInwoker ,也就是去掉 Proxy层RPC是可以Run的,只是不那么透明,不那么看起来像调本地服务一样调远程服务。
- 而Remoting 实现是 Dubo协议的实现,如果你选择RMI协议,整个Remoting 都不会用上,Remoting 内部再划为 Transport传翰层和Exchange信息交换层,Transport层只负责单向消息传输,是对Mina, Netty, Grizly 的抽象,它也可以扩展UDP传输,而 Exchange层是在传输层之上封装了Request-REesponse语义。。
- Registry和Monitor实际上不算一层,而是一个独立的节点,只是为了全局概览,用层的方式画在一起。
12.Dubbo是如何完成服务导出的
- 首先Dubo会将程序员所使用的@DubboService注解或@Sevice注解进行解析得到程序员所定义的服务参数,包括定义的服务名、服务接口、服务超时时间、服务协议等等,得到一个ServiceBean。
- 然后调用serviceBean的export方法进行服务导出
- 然后将服务信息注册到注册中心,如果有多个协议,多个注册中心,那就将服务按单个协议,单个注册中心进行注册
- 将服务信息注册到注册中心后,还会绑定一些监听器,监听动态配置中心的变更
- 还会根据服务协议启动对应的Web服务器或网络框架,比如Tomcat、Netty等
13.Dubbo是如何完成服务引入的?
- 当程序员使用@Reference注解来引入一个服务时,Dubbo会将注解和服务的信息解析出来,得到当前所引用的服务名
- 然后从注册中心进行查询服务信息,得到服务的提供者信息,并存在消费端的服务目录中
- 并绑定一些监听器用来监听动态配置中心的变更
- 然后根据查询得到的服务提供者信息生成一个服务接口的代理对象,并放入Spring容器中作为Bean
14.Dubbo支持哪些负载均衡策略
- 随机:从多个服务提供者随机选择一个来处理本次请求,调用量越大则分布越均匀,并支持按权重设置随机概率
- 轮询:依次选择服务提供者来处理请求,并支持按权重进行轮询,底层采用的是平滑加权轮询算法
- 最小活跃调用数:统计服务提供者当前正在处理的请求,下次请求过来则交给活跃数最小的服务器来处理
- 一致性哈希:相同参数的请求总是发到同一个服务提供者
15.epoll和poll的区别
- select模型,使用的是数组来存储Socket连接文件描述符,容量是固定的,需要通过轮询来判断是否发生了10事件
- pol模型,使用的是链表来存储Socket连接文件描述符,容量是不固定的,同样需要通过轮询来判断是否发生了10事件
- epol模型,epoll和poll是完全不同的, epoll是一 种事件通知模型, 当发生了I0事件时,应用程序才进行I0操作,不需要像polI模型那样主动去轮询
16.Explain语句结果中各个字段分表表示什么
| 列名 | 描述 |
|---|---|
| id | 查询语询中每出现一个SELECT关键字, MySQL就会 为於分配个唯一的id值, 某些子查询会被优化为 join查询,那么出现的id会一样 |
| select_type | SELECT关键字对应的那个查询的类型 |
| table | 表名 |
| partitions | 匹配的分区信息 |
| type | 针对单表的查询方式(全表扫描、索引) |
| possible_keys | 可能用到的索引 |
| key | 实际上使用的索引 |
| key_len | 实际使用到的索引长度 |
| ref | 当使用索引列等值查询时,与索引列进行等值匹配的对象信息 |
| rows | 预估的需要读取的记录条数 |
| filtered | 某个表经过搜索条件过滤后剩余记录条数的百分比 |
| Extra | 一些额外信息,比如排序等 |
17.HashMap的扩容机制
1.7版本
1.先生成新数组
2.遍历老数组中的每个位置上的链表上的每个元素
3.取每个元素的key,基于新数组长度,计算出每个元素在新数组中的下标
4.将元素添加到新数组中去
5.所有元素转移完了之后,将新数组赋值给HashMap对象的table属性
1.8版本
1.先生成新数组
2.遍历老数组中的每个位置上的链表或红黑树
3.如果是链表,则直接将链表中的每个元索重新计算下标,并添加到新数组中去
4.如果是红黑树,则先遍历红黑树,先计算出红黑树中每个元索对应在新数组中的下标位置
a.统计每个下标位置的元素个数
b.如果该位置下的元索个数超过了8,则生成一个新的红黑树, 并将根节点的添加到新数组的对应位置
c.如果该位置下的元素个数没有超过8,那么则生成一个链表, 将链表的头节点添加到新数组的对应位置
5.所有元素转移完了之后,将新数组赋值给HashMap对象的table属性
18.Innodb是如何实现事务的
lInnodb通过Buffer Pool,LogBuffer,Redo Log,Undo Log来实现事务,以一个update语句为例:
- Innodb在收到一个update语句后,会先根据条件找到数据所在的页,并将该页缓存在Buffer Pool中
- 执行update语句,修改Buffer Pool中的数据,也就是内存中的数据
- 针对update语句生成一个RedoLog对象,并存入LogBuffer中
- 针对update语句生成undolog日志,用于事务回滚
- 如果事务提交,那么则把RedoLog对象进行持久化,后续还有其他机制将Buffer Pool中所修改的数据页持久化到磁盘中6.如果事务回滚,则利用undolog日志进行回滚
19.Java死锁如何避免
造成死锁的几个原因:
1.一个资源每次只能被一个线程使用
2.—个线程在阻塞等待某个资源时,不释放已占有资源
3.一个线程已经获得的资源,在未使用完之前,不能被强行剥夺
4.若干线程形成头尾相接的循环等待资源关系
这是造成死锁必须要达到的4个条件,如果要避免死锁,只需要不满足其中某一个条件即可。而其中前3个条件是作为锁要符合的条件,所以要避免死锁就需要打破第4个条件,不出现循环等待锁的关系。
在开发过程中:
1.要注意加锁顺序,保证每个线程按同样的顺序进行加锁2.要注意加锁时限,可以针对所设置一个超时时间
3.要注意死锁检查,这是一种预防机制,确保在第一时间发现死锁并进行解决
20.Java中的异常体系是怎样的
- Java中的所有异常都来自顶级父类Throwable.
- Throwable下有两个子类Exception和Error。
- Error表示非常严重的错误,比如java.lang.StackOverFlowError和Java.lang.OutOfMemoryError, 通常这些错误出现时,仅仅想靠程序自己是解决不了的,可能是虚拟机、磁盘、操作系统层面出现的问题了,所以通常也不建议在代码中去捕获这些Error,因为捕获的意义不大,因为程序可能已经根本运行不了了。
- Exception表示异常,示程序出现Exception时,可以靠程自己来解决的,比如NullPointerException、 llgalAccessException等 ,我们可以捕获这些异常来做特殊处理。
- Exception的子类通常又可以分为RuntimeException和非RuntimeException两类
- RunTimeException表示运行期异常,示这个异常是在代码运行过程中抛出的,这些异常是非检查异常,程序中可以选择捕获处理,可以怀处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生,比如NullPointerException、 IndexOutOfBoundsException等。
- 非RuntimeException表示非运行期异常,也就是我们常说的检查异常,是必须进行处理的异常,如果不处理,程序就不能检查异常通过。如IOException、 SQL Exception等以及
胪自定义的Exception异常。
21.Java中有哪些类加载器
JDK自带有三个类载器: bootstrap ClassLoader、ExtClassLoader、AppClassLoader。
- BootStrapClassLoader是ExtClassLoader的父类加载器,默认负责加载%JAVA_ HOME%lib下的jar包和class文件。
- ExtClassLoader是AppClassLoader的父类加载器,负责加载%JAVA _HOME%/ib/ext文件夹下的jar包和class类。
- AppClassLoader是自定义类加载器的父类, 负责加载classpath下的类文件。
22.Innodb和Myisam的区别?
1)InnoDB支持事务,MyISAM不支持,这一点是非常之重要。事务是一种高级的处理方式,如在一些列增删改中只要哪个出错还可以回滚还原,而MyISAM就不可以了。
2)MyISAM适合查询以及插入为主的应用,InnoDB适合频繁修改以及涉及到安全性较高的应用
3)InnoDB支持外键,MyISAM不支持
4)从MySQL5.5.5以后,InnoDB是默认引擎
5)InnoDB不支持FULLTEXT类型的索引
6)InnoDB中不保存表的行数,如select count() from table时,InnoDB需要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。注意的是,当count()语句包含where条件时MyISAM也需要扫描整个表
7)对于自增长的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中可以和其他字段一起建立联合索引
8)清空整个表时,InnoDB是一行一行的删除,效率非常慢。MyISAM则会重建表
9)InnoDB支持行锁(某些情况下还是锁整表,如 update table set a=1 where user like ‘%lee%’。
-
InnoDB支持事务,MyISAM不支持,对于InnoDB每一条SQL语言都默认封装成事务,自动提交,这样会影响速度,所以最好把多条SQL语言放在begin和commit之间,组成一个事务;
-
InnoDB支持外键,而MyISAM不支持。对一个包含外键的InnoDB表转为MYISAM会失败;
-
InnoDB是聚集索引,使用B+Tree作为索引结构,数据文件是和(主键)索引绑在一起的(表数据文件本身就是按B+Tree组织的一个索引结构),必须要有主键,通过主键索引效率很高。但是辅助索引需要两次查询,先查询到主键,然后再通过主键查询到数据。因此,主键不应该过大,因为主键太大,其他索引也都会很大。
MyISAM是非聚集索引,也是使用B+Tree作为索引结构,索引和数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的。
也就是说:InnoDB的B+树主键索引的叶子节点就是数据文件,辅助索引的叶子节点是主键的值;而MyISAM的B+树主键索引和辅助索引的叶子节点都是数据文件的地址指针。 -
InnoDB不保存表的具体行数,执行select count(*) from table时需要全表扫描。而MyISAM用一个变量保存了整个表的行数,执行上述语句时只需要读出该变量即可,速度很快(注意不能加有任何WHERE条件);
那么为什么InnoDB没有了这个变量呢?
因为InnoDB的事务特性,在同一时刻表中的行数对于不同的事务而言是不一样的,因此count统计会计算对于当前事务而言可以统计到的行数,而不是将总行数储存起来方便快速查询。InnoDB会尝试遍历一个尽可能小的索引除非优化器提示使用别的索引。如果二级索引不存在,InnoDB还会尝试去遍历其他聚簇索引。
如果索引并没有完全处于InnoDB维护的缓冲区(Buffer Pool)中,count操作会比较费时。可以建立一个记录总行数的表并让你的程序在INSERT/DELETE时更新对应的数据。和上面提到的问题一样,如果此时存在多个事务的话这种方案也不太好用。如果得到大致的行数值已经足够满足需求可以尝试SHOW TABLE STATUS -
Innodb不支持全文索引,而MyISAM支持全文索引,在涉及全文索引领域的查询效率上MyISAM速度更快高;PS:5.7以后的InnoDB支持全文索引了
-
MyISAM表格可以被压缩后进行查询操作
-
InnoDB支持表、行(默认)级锁,而MyISAM支持表级锁
InnoDB的行锁是实现在索引上的,而不是锁在物理行记录上。潜台词是,如果访问没有命中索引,也无法使用行锁,将要退化为表锁。
8、InnoDB表必须有唯一索引(如主键)(用户没有指定的话会自己找/生产一个隐藏列Row_id来充当默认主键),而Myisam可以没有
9、Innodb存储文件有frm、ibd,而Myisam是frm、MYD、MYIInnodb:frm是表定义文件,ibd是数据文件 Myisam:frm是表定义文件,myd是数据文件,myi是索引文件
23.JDK1.7到JDK1.8 HashMap发生了什么变化(底层)?
- 1.7中底层是数组+链表,1.8中底层是数组+链表+红黑树,加红黑树的目的是提高HashMap插入和查询整体效率
- 1.7中链表插入使用的是头插法,1.8中链表插入使用的是尾插法,因为1.8中插入key和value时需要判断铤表元素个数,所以需要遍历链表统计链表元素个数,所以正好就直接使用尾插法
- 1.7中哈希算法比较复杂,存在各种右移与异或运算,1.8中进行了简化,因为复杂的哈希算法的目的就是提高散列性,来提供H ashMap的整体效率,而1.中新增了红黑树,所以可以适当的简化哈希算法,节省CPU资源

浙公网安备 33010602011771号