Question

137 阅读8分钟

一、线程池扩容机制,多线程,写一个线程池?  线程池的固定容量值怎么取值?

1.1)线程池默认线程容量值设置:三方面影响:

服务器配置、服务器资源预算(CPU、内存、IO支持的最大QPS)------------IO最大QPS(服务器每秒响应的进程请求次数)、任务自身特性(IO密集型还是CPU密集型)。

1.2)不同任务对应的线程数量

在一般任务中,设CPU数量为N,任务分为IO密集型和CPU(计算)密集型,如果是IO密集型,设置线程数为2*N;如果是CPU密集型,则设置线程数为N+1(某时因为发生一个页面错误或其他原因而暂停,这个额外线程可以确保不会停止工作)。

具体操作中,很少出现纯IO和纯计算任务,大部分任务是计算后修改内存,因此要按照一个思路去设置线程数。主要考量两方面,一个是CPU的利用率+数量,另一个是IO任务支持的最大QPS

1.3)计算思路

​ 首先确定一点,我们认为一个线程在运行的时候是占用一个CPU的,在这个单位时间内,CPU的使用率是100%,而如果有一个线程,处理两个耗时相同的任务,一个计算,一个IO(IO操作执行的时候,线程是会被挂起的,因为IO涉及数据的读取或修改,会遇到锁,此时CPU是不工作的),那么这整个时间段内,线程有一半时间是挂起的,因此CPU使用率=线程使用时间/总时间=50%。如果设置两个线程,那么在这段时间内,当一个线程被挂起时,另一个线程可以使用,CPU始终被使用,此时CPU利用率为100%。 ​ 

如上所说,我们的整体思路就是:确保每时每刻都有且仅有一条线程在运行,这样CPU的使用率就保持在100%,那么问题就转化为:IO任务进行的这段时间里,让计算任务继续进行,且每一个计算任务都分配一个线程,确保单核多线程并发执行。 

可计算出每个CPU需要处理的线程数量为(105/5=)21条。对于N个CPU的服务器(设8个),公式为:

线程数= N * (总任务时长/计算任务时长)

​ 即设置(21 * 8 =)168条线程,实际工作中,CPU利用率达不到100%,上面的公式是一个理想值,需要完善。

接下来考量IO最大QPS(服务器每秒响应的进程请求次数),我们已经知道我们整个任务进程的处理时间为105ms,那么每秒(1000ms)能处理的进程次数为(1000/105=)9.52,这是单线程的处理能力,也就是说按照设置的168个线程,服务器的N个CPU每秒能处理的请求次数1600,为但是能处理不代表能接收,我们还要看服务器能否每秒接收这么多请求,如果服务器QPS已知最高为800,那么显然每秒会有一半数量的线程是空闲的(工厂生产能力够,但是订单不够),那么我们修改设置的线程数最终为168*(800/1600)=84个。 

二、数据库查询优化

数据库查询优化有哪些?建立索引、联合索引机制?explan?数据库表中多个字段的最左查询?索引失效机制?索引覆盖?

三、高并发

多线程读写,加锁机制

线程池的拒绝策略、线程池的扩容机制?

分布式锁机制

一文搞定Redis分布式锁的实现和原理:baijiahao.baidu.com/s?id=173071…

四、Spring相关注解机制

五、Redis缓存数据库机制原理

5.1、Redis常用数据结构及场景

    String字符串:String是redis中最基本的数据类型,一个key对应一个value

**List列表:**Redis中的List其实就是链表(Redis用双端链表实现List)。 列表包含的元素,相同的元素可以重复出现。

实战场景:》微博TimeLine: 有人发布微博,用lpush加入时间轴,展示新的列表信息。》消息队列

Set集合: Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。

六、Kafka保证消息的不丢失与不重复消费?

6.1、Kafka消息的丢失

1、生产者

1.1 丢失原因: 

  • kafka生产端异步发送消息后,不管broker是否响应立即返回,伪代码producer.send(msg),由于网络抖动,导致消息压根就没有发送到broker端;
  •  kafka生产端发送消息超出大小限制,broker端接到以后没法进行存储;

 1.2 解决方案:

  1. 生产者调用异步回调消息。伪代码如下: producer.send(msg,callback); 
  2. 生产者增加消息确认机制,设置生产者参数:acks = all。partition的leader副本接收到消息,等待所有的follower副本都同步到了消息之后,才认为本次生产者发送消息成功了;
  3. 生产者设置重试次数。比如:retries>=3,增加重试次数以保证消息的不丢失;
  4. 定义本地消息日志表,定时任务扫描这个表自动补偿,做好监控告警。
  5. 后台提供一个补偿消息的工具,可以手工补偿。 

2、Broker

2.1 丢失原因:

 kafka broker集群接收到数据后会将数据进行持久化存储到磁盘,消息都是先写入到页缓存,然后由操作系统负责具体的刷盘任务或者使用fsync强制刷盘,如果此时Broker宕机,且选举一个落后leader副本很多的follower副本成为新的leader副本,那么落后的消息数据就会丢失。

 2.2 解决方案:

  1.  同步刷盘(不太建议)。同步刷盘可以提高消息的可靠性,防止由于机器掉电等异常造成处于页缓存而没有及时写入磁盘的消息丢失。但是会严重影响性能。 
  2.  利用partition的多副本机制(建议)

 unclean.leader.election.enable=false:数据丢失太多的副本不能选举为leader副本,防止落后太多的消息数据而引起丢失; 

 replication.factor >= 3:消息分区的副本个数,这个值建议设为>=3;

 min.insync.replicas >1:消息写入多少副本才算已提交,这个值必须大于1,这个是要求一个leader 至少感知到有至少一个 follower还跟自己保持联系;(replication.factor>min.insync.replicas 这样消息才能保存成功) 

3、消费者

3.1 丢失原因:

  • 消费者配置了offset自动提交参数。enable.auto.commit=true。
  • 消息者收到了消息,进行了自动提交offset,kafka以为消费者已经消费了这个消息,但其实刚准备处理这个消息,还没处理完成,消费者自己挂了,此时这条消息就会丢失。
  •  多线程消费消息,某个线程处理消息出现异常,还是会出现自动提交offset。

 3.2 解决方案:

  • 消费者关闭自动提交,采用手动提交offset。通过配置参数:enable.auto.commit=false,关闭自动提交offset,在完成业务逻辑以后手动提交offset,这样就不会丢失数据。 
  • 消费者多线程处理业务逻辑,等待所有线程处理完成以后,才手工提交offset。 
  • 消费者消费消息需要进行幂等处理,防止重复消费。

6.2、 kafka如何避免消息不重复消费?

消息重复消费原因:

  • kafka消费端重复提交导致消息重复消费,----------通过offset维护消息的消费顺序,每消费一个数据broker就会更新offset的值;默认情况下消息消费完以后,会自动提交Offset的值,避免重复消费。 但是kafka消费端的自动提交,会有一个默认的5秒间隔,在5秒之后的下一次向Broker拉取消息的时候才提交上一批消费的Offset。如果在消费者消费过程中遇到应用程序被强制的kill掉或者是宕机的情况,就会导致Offset没有及时提交从而产生重复消费的情况
  • Kafka服务端的Partition再均衡机制导致消息重复消费--------------Partition的Rebalance机制,会把多个Partition均衡的分配给多个消费者,消费者会从分配到的partition里面去消费消息,如果消费者在默认的5分钟内没有去处理完这批消息的话,就会触发kafka的rebalance机制,从而导致offset自动提交失败;而rebalance之后消费者还会从之前没有提交的offset位置开始消费,导致消息重复消费

消费重复消费的解决措施:

  1. 方法1:提高消费端的处理性能避免触发Balance---------如用多线程的方式来处理消息,缩短单个消息消费的时长; 或调整消息处理的超时时间; 减少一次性从Broker上拉取数据的条数。

  2. 方法2:使用ConsumerRebalanceLisenter,再均衡监听器------------用来设定发生再均衡动作前后的一些准备或者收尾工作;

  3. 方法3:开启kafka的消息幂等性-----------------

    prop.put(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG,true);
    

   或将消息生成MD5然后保存到MySQL或者Redis中,在处理消息之前先查询MySQL或者Redis,然后进行判断消息之前是否进行消费过。

6.3、当kafka集群有大量消息积压时采用多线程消费解决

内存队列中是否有新数据,多加几个消费线程但是带来的offset提交导致丢消息和重复消费的问题;

解决方案:提交最大连续offset值幂等性。 本地记录offset

七、软件项目管理

7.1、金字塔原理?

金字塔,即一种表达、思考和解决问题的结构化思维模式。

金字塔原理的基本结构是:结论先行,以上统下,归类分组,逻辑递进。先重要后次要,先总结后具体,先框架后细节。先结论后原因,先结果后过程,先论点后论据。

明确目标、层次分明、突出重点

**“金字塔”的核心原理其实很简单,就是把一件复杂的大事情分解开,横向纵向分解成简单的容易处理的几个小问题,这样更容易操作和执行!最后这些小问题都处理解决了,再组成这个大事情!这件大事情的完美程度,优秀程度,就是你对金字塔原理的利用能力的直接体现!
**

7.2、SMART原则?-----(S=Specific、M=Measurable、A=Attainable、R=Relevant、T=Time-bound)是为了利于员工更加明确高效地工作,更是为了管理者将来对员工实施绩效考核提供了考核目标和考核标准,使考核更加科学化、规范化,更能保证考核的公正、公开与公平。

Specific  具体明确的、

Measurable 能够衡量的、

Achievable 可以达到的、

Relevant 平衡关联的、

Time-Bound 设定期限的、

软件工程师与程序员的区别?

程序员:     程序员通常分为应用级程序员和研发级程序员,应用级程序员主要的工作内容是做业务功能实现,而研发级程序员往往解决的是系统级问题。简单的说,应用级程序员往往是调用研发级程序员的功能模块来解决业务问题。科技公司中应用级程序员的数量通常大于研发级程序员,尤其是大型软件企业。

工程师:    把一款软件比做一座大桥,那么软件工程师相当于施工总指挥,而一般的开发人员也就是程序员相当于建筑工人!软件工程师的工作不同于程序员但是一个软件工程师必定是一个优秀的程序员!

如果能让“编码”和“创新”相关联,则程序员的价值就大增,但“编码”到“创新”之间需要一个过渡的桥梁,这个桥梁就是**“分析与设计”**的能力,有了这个能力就可以朝着工程师的位置走去。

八、网络

域名解析过程 以www.baidu.com为例

主要通过五个步骤进行域名解析 :

1. 浏览器访问 www.baidu.com,询问**本地 DNS 服务器**是否缓存了该网址解析后的 IP 地址。 2. 如果本地 DNS 服务器没有缓存的话,就去 root-servers.net 根服务器查询该网址对应的 IP 地 址。

3. 根服务器返回顶级域名服务器的网址 gtld-servers.net,然后本地 DNS 服务器去顶级域名服务器查询该网址对应的 IP 地址。

4. 顶级域名服务器返回 www.baidu.com 主区域服务器的地址,然后本地 DNS 服务器去 www.baidu.com主区域服务器查询此域名对应的 IP 地址。

5. 本地DNS服务器拿到www.baidu.com解析后的IP地址后,缓存起来以便备查,然后把解析 后的IP地址返回给浏览器。