1.bio与nio的区别
1、bio同步阻塞io:在此种⽅式下,⽤户进程在发起⼀个IO操作以后,必须等待IO操作的完成,只有当真正完成了IO操作以后,⽤户
进程才能运⾏。JAVA传统的IO模型属于此种⽅式!
2、nio同步⾮阻塞式I/O;java NIO采⽤了双向通道进⾏数据传输,在通道上我们可以注册我们感兴趣的事件:连接事件、读写事件;
NIO主要有三⼤核⼼部分:Channel(通道),Buffer(缓冲区), Selector。传统IO基于字节流和字符流进⾏操作,⽽NIO基于Channel和
Buffer(缓冲区)进⾏操作,数据总是从通道读取到缓冲区中,或者从缓冲区写⼊到通道中。Selector(选择区)⽤于监听多个通道的事件
(⽐如:连接打开,数据到达)。因此,单个线程可以监听多个数据通道。
4.cap理论
1、概念:⼀个分布式系统最多只能同时满⾜⼀致性(Consistency)、可⽤性(Availability)和分区容错性(Partition tolerance)这
三项中的两项。
2、⼀致性:更新操作成功并返回客户端完成后,所有节点在同⼀时间的数据完全⼀致,所以,⼀致性,说的就是数据⼀致性。
3、可⽤性:服务⼀直可⽤,⽽且是正常响应时间。
4、分区容错性:分布式系统在遇到某节点或⽹络分区故障的时候,仍然能够对外提供满⾜⼀致性和可⽤性的服务。
5.⼆段式满⾜cap理论的哪两个理论
两阶段提交协议在正常情况下能保证系统的强⼀致性,但是在出现异常情况下,当前处理的操作处于错误状态,需要管理员⼈⼯⼲预
解决,因此可⽤性不够好,这也符合CAP协议的⼀致性和可⽤性不能兼得的原理。
6.线程池的参数配置,为什么java官⽅提供⼯⼚⽅法给线程池
1、线程池简介:
2、核⼼参数:
3、⼯⼚⽅法作⽤:ThreadPoolExecutor类就是Executor的实现类,但ThreadPoolExecutor在使⽤上并不是那么⽅便,在实例化时需
要传⼊很多歌参数,还要考虑线程的并发数等与线程池运⾏效率有关的参数,所以官⽅建议使⽤Executors⼯程类来创建线程池对
象。
7.分布式框架dubbo的好处,不⽤dubbo可不可以。为什么要使⽤分布式
1、dubbo好处:
1、远程通讯: 提供对多种基于⻓连接的NIO框架抽象封装, 包括多种线程模型,序列化,以及“请求-响应”模式的信息交换⽅
式。
2、软负载均衡及容错机制: 提供基于接⼝⽅法的透明远程过程调⽤,包括多协议⽀持,以及软负载均衡,失败容错,地址路由,
动态配置等集群⽀持。
可在内⽹替代F5等硬件负载均衡器,降低成本,减少单点。
3、服务⾃动注册与发现: 基于注册中⼼⽬录服务,使服务消费⽅能动态的查找服务提供⽅,使地址透明,使服务提供⽅可以平滑
增加或减少机器 。
4、提供完善的管理控制台dubbo-admin与简单的控制中⼼dubbo-monitor
5、Dubbo提供了伸缩性很好的插件模型,很⽅便进⾏扩展(ExtensionLoader)
2、不⽤dubbo可不可以:可以,使⽤springcloud。
3、分布式作⽤:
a. 系统之间的耦合度⼤⼤降低,可以独⽴开发、独⽴部署、独⽴测试,系统与系统之间的边界⾮常明确,排错也变得相当容易,
开发效率⼤⼤提升。
b. 系统之间的耦合度降低,从⽽系统更易于扩展。我们可以针对性地扩展某些服务。假设这个商城要搞⼀次⼤促,下单量可能会
⼤⼤提升,因此我们可以针对性地提升订单系统、产品系统的节点数量,⽽对于后台管理系统、数据分析系统⽽⾔,节点数量维
持原有⽔平即可。
c. 服务的复⽤性更⾼。⽐如,当我们将⽤户系统作为单独的服务后,该公司所有的产品都可以使⽤该系统作为⽤户系统,⽆需重
复开发。
8.七个垃圾回收器之间如何搭配使⽤
当写⼊⼀个volatile变量时,JMM会把该线程对应的本地内存中的共享变量刷新到主内存。
当读⼀个volatile变量时,JMM会把该线程对应的本地内存置为⽆效,从主内存中读取所有的共享变量。
4.
读之前会先判断count(jdk1.6),其中的count是被volatile修饰的(当变量被volatile修饰后,每次更改该变量的时候会将更改结果
写到系统主内存中,利⽤多处理器的缓存⼀致性,其他处理器会发现⾃⼰的缓存⾏对应的内存地址被修改,就会将⾃⼰处理器的缓存⾏设置为失效,并
强制从系统主内存获取最新的数据。),故可以实现⽆锁读。
36、 分布式锁的实现
基本原理:⽤⼀个状态值表示锁,对锁的占⽤和释放通过状态值来标识。
1、三种分布式锁:
1、Zookeeper:基于zookeeper瞬时有序节点实现的分布式锁,其主要逻辑如下(该图来⾃于IBM⽹站)。⼤致思想即为:每个客户端对
某个功能加锁时,在zookeeper上的与该功能对应的指定节点的⽬录下,⽣成⼀个唯⼀的瞬时有序节点。判断是否获取锁的⽅式很简单,只需要判断
有序节点中序号最⼩的⼀个。当释放锁的时候,只需将这个瞬时节点删除即可。同时,其可以避免服务宕机导致的锁⽆法释放,⽽产⽣的死锁问题。
2、优点
锁安全性⾼,zk可持久化,且能实时监听获取锁的客户端状态。⼀旦客户端宕机,则瞬时节点随之消失,zk因⽽能第⼀时间释放
锁。这也省去了⽤分布式缓存实现锁的过程中需要加⼊超时时间判断的这⼀逻辑。
3、缺点
性能开销⽐较⾼。因为其需要动态产⽣、销毁瞬时节点来实现锁功能。所以不太适合直接提供给⾼并发的场景使⽤。
4、实现
可以直接采⽤zookeeper第三⽅库curator即可⽅便地实现分布式锁。
5、适⽤场景
对可靠性要求⾮常⾼,且并发程度不⾼的场景下使⽤。如核⼼数据的定时全量/增量同步等。
2、memcached:memcached带有add函数,利⽤add函数的特性即可实现分布式锁。add和set的区别在于:如果多线程并发set,则每
个set都会成功,但最后存储的值以最后的set的线程为准。⽽add的话则相反,add会添加第⼀个到达的值,并返回true,后续的添加则都会返回
false。利⽤该点即可很轻松地实现分布式锁。
2、优点
并发⾼效
3、缺点
memcached采⽤列⼊LRU置换策略,所以如果内存不够,可能导致缓存中的锁信息丢失。
memcached⽆法持久化,⼀旦重启,将导致信息丢失。
4、使⽤场景
⾼并发场景。需要 1)加上超时时间避免死锁; 2)提供⾜够⽀撑锁服务的内存空间; 3)稳定的集群化管理。
3、redis:redis分布式锁即可以结合zk分布式锁锁⾼度安全和memcached并发场景下效率很好的优点,其实现⽅式和memcached类
似,采⽤setnx即可实现。需要注意的是,这⾥的redis也需要设置超时时间。以避免死锁。可以利⽤jedis客户端实现。
1 ICacheKey cacheKey = new ConcurrentCacheKey(key, type);
2 return RedisDao.setnx(cacheKey, “1”);
2、数据库死锁机制和解决⽅案:
1、死锁:死锁是指两个或者两个以上的事务在执⾏过程中,因争夺锁资源⽽造成的⼀种互相等待的现象。
2、处理机制:解决死锁最有⽤最简单的⽅法是不要有等待,将任何等待都转化为回滚,并且事务重新开始。但是有可能影响并发性能。
1、超时回滚,innodb_lock_wait_time设置超时时间;
2、wait-for-graph⽅法:跟超时回滚⽐起来,这是⼀种更加主动的死锁检测⽅式。InnoDB引擎也采⽤这种⽅式。
37、分布式session ,如何保持⼀致
1、Session粘滞
1、将⽤户的每次请求都通过某种⽅法强制分发到某⼀个Web服务器上,只要这个Web服务器上存储了对应Session数据,就可以
实现会话跟踪。
2、优点:使⽤简单,没有额外开销。
3、缺点:⼀旦某个Web服务器重启或宕机,相对应的Session数据将会丢失,⽽且需要依赖负载均衡机制。
4、适⽤场景:对稳定性要求不是很⾼的业务情景。
2、Session集中管理
1、在单独的服务器或服务器集群上使⽤缓存技术,如Redis存储Session数据,集中管理所有的Session,所有的Web服务器都从
这个存储介质中存取对应的Session,实现Session共享。
2、优点:可靠性⾼,减少Web服务器的资源开销。
3、缺点:实现上有些复杂,配置较多。
4、适⽤场景:Web服务器较多、要求⾼可⽤性的情况。
5、可⽤⽅案:开源⽅案Spring Session,也可以⾃⼰实现,主要是重写HttpServletRequestWrapper中的getSession⽅法,博主
也动⼿写了⼀个,github搜索joincat⽤户,然后⾃取。
3、基于Cookie管理
1、这种⽅式每次发起请求的时候都需要将Session数据放到Cookie中传递给服务端。
2、优点:不需要依赖额外外部存储,不需要额外配置。
3、缺点:不安全,易被盗取或篡改;Cookie数量和⻓度有限制,需要消耗更多⽹络带宽。
4、适⽤场景:数据不重要、不敏感且数据量⼩的情况。
总结
这四种⽅式,相对来说,Session集中管理更加可靠,使⽤也是最多的。
38、消息中间件都⽤到哪些,他们的区别
中⼩型公司⾸选RabbitMQ:管理界⾯简单,⾼并发。
⼤型公司可以选择RocketMQ:更⾼并发,可对rocketmq进⾏定制化开发。
⽇志采集功能,⾸选kafka,专为⼤数据准备。
丰巢–0313
我们知道hashmap线程不安全,那⽤什么类可以代替它保证线程安全呢?他们⼜是如何实现线程安全的呢?
使⽤ConcurrentHashMap保证线程安全,ConcurrentHashMap是HashMap的线程安全实现,允许多个修改操作同时进⾏(使⽤
特性 ActiveMQ RabbitMQ RocketMQ kafka
开发语⾔ java erlang java scala
单机吞吐量 万级 万级 10万级 10万级
时效性 ms级 us级 ms级 ms级以内
可⽤性 ⾼(主从架构) ⾼(主从架构) ⾮常⾼(分布式架构) ⾮常⾼(分布式架构)
功能特性
成熟的产品,在很多公司
得到应⽤;有较多的⽂
档;各种协议⽀持较好
基于erlang开发,所以并
发能⼒很强,性能极其
好,延时很低;管理界⾯较
丰富
MQ功能⽐较完备,扩展
性佳
只⽀持主要的MQ功能,
像⼀些消息查询,消息回
溯等功能没有提供,毕竟
是为⼤数据准备的,在⼤
数据领域应⽤⼴。
了锁分离技术),它使⽤了多个锁来控制对hash表的不同段进⾏的修改,每个段其实就是⼀个⼩的hashtable,它们有⾃⼰的锁。
说说⼏种GC机制?
引⽤计数法(没有被java采⽤):
a. 原理:对于⼀个对象A,只要有任何⼀个对象引⽤了A,则A的引⽤计数器就加1,当引⽤失效时,引⽤计数器就减1,只要
对象A的引⽤计数器的值为0,则对象A就会被回收。
b. 问题:
i. 引⽤和去引⽤伴随加法和减法,影响性能;
ii. 很难处理循环引⽤。
标记清除法:
a. 原理:现代垃圾回收算法的思想基础。标记-清除算法将垃圾回收分为两个阶段:标记阶段和清除阶段。⼀种可⾏的实现
是,在标记节点,⾸先通过根节点,标记所有从根节点开始的可达对象。因此,未被标记的对象就是未被引⽤的垃圾对象。
然后在清除阶段,清除所有未被标记的对象。
b. 问题:
i. 标记和清除两个过程效率不⾼,产⽣内存碎⽚导致需要分配较⼤对象时⽆法找到⾜够的连续内存⽽需要触发⼀次GC操
作。
标记压缩法:
a. 原理:适合⽤于存活对象较多的场合,如⽼年代。它在标记-清除算法的基础上做了⼀些优化。标记阶段⼀样,但之后,
将所有存活对象压缩到内存的⼀端。之后,清除边界外所有的空间。
b. 优点:
i. 解决了标记- 清除算法导致的内存碎⽚问题和在存活率较⾼时复制算法效率低的问题。
复制算法:
a. 原理:将原有的内存空间分为两块,每次只使⽤其中⼀块,在垃圾回收时,将正在使⽤的内存中的存活对象复制到未使⽤
的内存块中,之后清除正在使⽤的内存块中的所有对象,交换两个内存的⻆⾊,完成垃圾回收。
b. 问题:
i. 不适⽤于存活对象⽐较多的场合,如⽼年代。
分代回收法:
a. 原理:根据对象存活周期的不同将内存划分为⼏块,⼀般是新⽣代和⽼年代,新⽣代基本采⽤复制算法,⽼年代采⽤标记
整理算法。
说说⼀致性hash?
1、⼀致性hash算法:我们的memcached客户端(这⾥我看的spymemcache的源码),使⽤了⼀致性hash算法ketama进⾏数据存储节点
的选择。与常规的hash算法思路不同,只是对我们要存储数据的key进⾏hash计算,分配到不同节点存储。⼀致性hash算法是对我们要存储数据的服
务器进⾏hash计算,进⽽确认每个key的存储位置。这⾥提到的⼀致性hash算法ketama的做法是:选择具体的机器节点不在只依赖需要缓存数据的
key的hash本身了,⽽是机器节点本身也进⾏了hash运算。
1、⼀致性hash算法是分布式系统中常⽤算法,设计⽬的是为了解决因特⽹中的热点(hot spot)问题。解决了P2P环境最为关键问题—
如何在动态⽹络拓扑中分布存储和路由;
2、⼀致性hash算法引⼊虚拟节点机制,解决服务节点少时数据倾斜问题(即对每⼀个服务节点计算多个哈希,每个计算结果位置都放
置⼀个此服务节点,称为虚拟节点。);
2、具体做法:如果有⼀个写⼊缓存的请求,其中Key值为K,计算器hash值Hash(K), Hash(K) 对应于图 – 1环中的某⼀个点,如果该
点对应没有映射到具体的某⼀个机器节点,那么顺时针查找,直到第⼀次找到有映射机器的节点,该节点就是确定的⽬标节点,如果超过了2^32仍然
找不到节点,则命中第⼀个机器节点。⽐如 Hash(K) 的值介于A~B之间,那么命中的机器节点应该是B节点(如上图 )。
3、数据保存流程:
1、⾸先求出memcached服务器(节点)的哈希值,并将其配置到0~232的圆(continuum)上。
2、然后采⽤同样的⽅法求出存储数据的键的哈希值,并映射到相同的圆上。
3、然后从数据映射到的位置开始顺时针查找,将数据保存到找到的第⼀个服务器上。如果超过232仍然找不到服务器,就会保存到第⼀
台memcached服务器上。
mybatis基础知识;
需了解基础语法;
mysql基础知识;
需了解sql优化、搜索引擎。
mysql单表达到多少数据量需要分库分表?
理论上确实5000万以上才会性能急剧下降,有些db架构师也是这么说过。但是实际情况却不⼀定,按照⼀部分的真实项⽬,
500万以上就会开始慢了。当然,这个跟具体的业务逻辑、响应要求、表设计也是很有关系的。表字段全是int类型的,可以到1000万以上
再优化。到了300万,是时候作好优化的技术储备了。但是不⼀定分表,可以通过缓存、搜索引擎等技术也都可以提⾼性能。
hibernate基础知识。
需要了解hibernate⼀级缓存和⼆级缓存。
说说kafka的原理,为什么能保证这么⾼的吞吐量?
1.消息分类按不同类别,分成不同的Topic,Topic⼜拆分成多个partition,每个partition均衡分散到不同的服务器(提⾼并发访问的能
⼒)
2.消费者按顺序从partition中读取,不⽀持随机读取数据,但可通过改变保存到zookeeper中的offset位置实现从任意位置开始读取
3.服务器消息定时清除(不管有没有消费)
4.每个partition还可以设置备份到其他服务器上的个数以保证数据的可⽤性。通过Leader,Follower⽅式
5.zookeeper保存kafka服务器和客户端的所有状态信息.(确保实际的客户端和服务器轻量级)
6.在kafka中,⼀个partition中的消息只会被group中的⼀个consumer消费;每个group中consumer消息消费互相独⽴;我们可以认为
⼀个group是⼀个"订阅"者,⼀个Topic中的每个partions,只会被⼀个"订阅者"中的⼀个consumer消费,不过⼀个consumer可以消费多个
partitions中的消息
7.如果所有的consumer都具有相同的group,这种情况和queue模式很像;消息将会在consumers之间负载均衡.
8.如果所有的consumer都具有不同的group,那这就是"发布-订阅";消息将会⼴播给所有的消费者.
9.持久性,当收到的消息时先buffer起来,等到了⼀定的阀值再写⼊磁盘⽂件,减少磁盘IO.在⼀定程度上依赖OS的⽂件系统(对⽂件系统本
身优化⼏乎不可能)
10.除了磁盘IO,还应考虑⽹络IO,批量对消息发送和接收,并对消息进⾏压缩。
11.在JMS实现中,Topic模型基于push⽅式,即broker将消息推送给consumer端.不过在kafka中,采⽤了pull⽅式,即consumer在和
broker建⽴连接之后,主动去pull(或者说fetch)消息;这种模式有些优点,⾸先consumer端可以根据⾃⼰的消费能⼒适时的去fetch消息并处
理,且可以控制消息消费的进度(offset);此外,消费者可以良好的控制消息消费的数量,batch fetch.
12.kafka⽆需记录消息是否接收成功,是否要重新发送等,所以kafka的producer是⾮常轻量级的,consumer端也只需要将fetch后的
offset位置注册到zookeeper,所以也是⾮常轻量级的.
–kafka使⽤场景
对于⼀些常规的消息系统,kafka是个不错的选择;partitons/replication和容错,可以使kafka具有良好的扩展性和性能优势.
不过到⽬前为⽌,我们应该很清楚认识到,kafka并没有提供JMS中的"事务性"“消息传输担保(消息确认机制)”“消息分组"等企业级特性;
kafka只能使⽤作为"常规"的消息系统,在⼀定程度上,尚未确保消息的发送与接收绝对可靠(⽐如,消息重发,消息发送丢失等)
kafka的特性决定它⾮常适合作为"⽇志收集中⼼”;application可以将操作⽇志"批量""异步"的发送到kafka集群中,
⽽不是保存在本地或者DB中;kafka可以批量提交消息/压缩消息等,这对producer端⽽⾔,⼏乎感觉不到性能的开⽀.
consumer端采⽤批量fetch⽅式,此时consumer端也可以使hadoop等其他系统化的存储和分析系统
对webservice有什么了解?
WebService,顾名思义就是基于Web的服务。它使⽤Web(HTTP)⽅式,接收和响应外部系统的某种请求。从⽽实现远程调⽤.
我们可以调⽤互联⽹上查询天⽓信息Web服务,然后将它嵌⼊到我们的程序(C/S或B/S程序)当中来,当⽤户从我们的⽹点看到天
⽓信息时,他会认为我们为他提供了很多的信息服务,但其实我们什么也没有做,只是简单调⽤了⼀下服务器上的⼀段代码⽽已。
学习WebService可以将你的服务(⼀段代码)发布到互联⽹上让别⼈去调⽤,也可以调⽤别⼈机器上发布的WebService,就像使⽤⾃
⼰的代码⼀样.。
说说你们公司git分⽀管理⽅案?
mysql如何进⾏分表分库?
⼀般就是垂直切分和⽔平切分,这是⼀种结果集描述的切分⽅式,是物理空间上的切分。 我们从⾯临的问题,开始解决,阐述:
⾸先是⽤户请求量太⼤,我们就堆机器搞定(这不是本⽂重点)。
然后是单个库太⼤,这时我们要看是因为表多⽽导致数据多,还是因为单张表⾥⾯的数据多。 如果是因为表多⽽数据多,使⽤垂直切
分,根据业务切分成不同的库。
如果是因为单张表的数据量太⼤,这时要⽤⽔平切分,即把表的数据按某种规则切分成多张表,甚⾄多个库上的多张表。 分库分
表的顺序应该是先垂直分,后⽔平分。 因为垂直分更简单,更符合我们处理现实世界问题的⽅式。
你们如何和前端进⾏接⼝联调?
开发前先定义好接⼝⽂档;
开发时严格按照接⼝⽂档开发;
如接⼝有调整需及时告知前端;
开发完成之后联调测试,保证业务逻辑正常。
说说你平时遇到的重⼤难题或者挑战,以及你解决问题的思路和流程。
平时关注⼀下公司线上问题的解决⽅案。