问题还有答案都在,欢迎大家一起讨论指正。
如何实现动态修改配置
我提到 1)通过MBean来保存配置信息,JMX来修改配置;还提到log4j2就是通过这种机制来实现日志级别的动态修改;2)开放telnet接口或者http接口来允许参数的修改;
他提到如何实现中心配置,我提到了zookeeper,而且提到一个好处,当参数修改时,可以实时通知;他提到zookeeper的客户端需要保持长连接才能接收参数变化的通知,这样连接数会很多,有没有其他方式;我提到可以通过push的方式,短连接来发送通知的方式。
Vertx的线程模式
线程模型和Netty的区别,回答不上来,只说了下Vertx的线程模型 - 分发线程和工作线程
Vertx和RxJava的区别
都是响应式框架,区别是什么?回答不上来
用了什么validation框架
Vertx-contract,若干个内置的validation rule,实质是对应一个正则表达;可以自定义validation rule,例如某个API的枚举类型数据;
NIO的BIO的区别
我回答到NIO内有selector,它可以注册事件,从而提高线程的使用效率;他问到selector背后的实现,我提到了epoll;继续问我是否知道epoll的两种触发方式 - 水平触发和边缘触发,我回答不上来。
Redis分布式锁的实现
我回答使用redisson的Redloc算法实现分布式锁,它提到了这个算法还是会有问题,但想不起来什么场景下会有问题了。
他提到了一个场景:如果有三个请求,第一个请求加了分布式锁,其他二个等待,在返回前第一个请求当机了,没有清除锁,这种情况怎么办?
我提到了通过TTL来防止死锁;我还提到了用setnx来加锁,用ttl来设置存活时间防止死锁;他提到这是两个命令,不是原子的,我回答可以将setnx的value内设置存活时间,这样当第二请求来的时候,尽管有分布式锁,但是显示锁已经过期,所以这个锁不会生效;
这个地方有些模糊,需要好好看一下,有点蒙过去的感觉。
further: 如上我的solution也是会有问题的,当后续线程并行可能同时检测到锁已经过期,例如B和C,这样就会同时执行delete操作,然后执行set操作,这时可能c删除的是B刚刚设置的锁,而不是最初的A锁。
所以可以这样,
1. 用一个更多参数的set方法,同时有NX和PX语义,即只有当不存在才设置,和同时设置过期时间在一个原子操作内,防止客户端执行第一步后宕机。
2. 两个语句 - setnx和expire, 当setnx失败的时候,会检测ttl是否存在,如果不存在则设置ttl防止死锁,这样即使A线程宕机没有来得及执行expire,也会被后续线程设置上。这样的side-effect是锁的持续时间会比预期要长些。
TTL过期后,什么时候Redis真正删除这个缓存?
回答不上来。过后查询的答案是:Redis使用惰性删除和定期删除的策略,惰性删除是在访问数据时,首先判断是否过期,如果过期,则删除缓存返回为空;定期删除是一定时间内对数据库进行扫描,清除掉过期数据,防止由于数据未被访问而内存没有释放。定期删除会设定最大的扫描时间以及每一个数据库抽样的个数;并且下次扫描会从根据上次扫描到的数据库继续扫描下一个数据库。
如上是删除过期数据,这里是删除未过期数据-当内存使用达到maxmemory阈值时,执行maxmemory-policy的策略,一共有6种策略来删除未过期的数据。
volatile-lru -> remove the key with an expire set using an LRU algorithm
# allkeys-lru -> remove any key according to the LRU algorithm
# volatile-random -> remove a random key with an expire set
# allkeys-random -> remove a random key, any key
# volatile-ttl -> remove the key with the nearest expire time (minor TTL)
# noeviction -> don't expire at all, just return an error on write operations
volatile指设置了ttl的元素; allkey指所有元素
lru指least rencently used,去除最近最不常访问的元素; random指随机删除元素。
ttl指按照ttl优先删除即将过期的元素。
默认是volatile-lru从设置过期时间的元素里删除最不长访问的元素。
分布式提交
是否用过分布式提交? 我提到二次提交,面试官说这是传统办法,对于互联网行业来说用的比较少,因为性能不够。
查询文档后,可以通过消息中间件转为本地事务。
消息中间件
我提到了kafka,
顺序存储是如何实现的?
我说不知道,应该是文件的追加写入,kafka不支持文件的随机写入;
是否知道zero-copy?
我回答的是有点类似堆外内存,少了内核态到用户态的拷贝,所以加快速度;另外我还提到了kafka的作弊,可以直接把一个几M文件直接返回,从而达到几M/s的吞吐量。
有没有了解push机制的中间件
不会回答
GC
Full GC频繁,如何查错?
我提到首先了解当前的配置信息,例如是那种GC collector,young/old区的大小;
开启GC日志来获取更多信息;
dump堆找出异常大或者异常多的可以对象,查看代码是否有内存泄露;
如何写代码模拟出Full GC频繁的现象
我回答 1)调节参数使得young区很小,这样对象直接分配到old区;2)调节参数,使得promotion的阈值很小,甚至为0,这样young区对象直接promote到old区;3)创建大的数组对象,因为需要连续空间,所以很容易直接分配到堆中;
什么情况下对象会创建在栈内?
我提到JVM有优化,会把对象打散,将基本数据存储在栈内;
是否听说过逃逸分析?
我回答:判断一个对象是否可能被其他线程调用,如果没有,则说明这个对象时线程安全的,不需要同步,即使有同步也会进行同步消除来提高性能。
如何优化spark程序?
1)改变数据的处理流程;2)充分利用DataFrame的缓存;3)调优参数
是否遇到数据不平衡问题
回答遇到过,举了分org存储的实际解决方案。