微信搜索 【微观技术】,关注这个不喜欢内卷的程序员。

精彩文章汇总 GitHub https://github.com/aalansehaiyang/technology-talk ,Star 12K ,汇总java生态圈常用技术框架、开源中间件,系统架构、数据库、大公司架构案例、常用三方类库、项目管理、线上问题排查、个人成长、思考等知识

大家好,我是Tom哥~

面试官拿到我们的简历,一般会关注两块内容,一块是专业技能,另一块是项目经历。

简单的个人介绍后,一般会先问些偏基础的技术问题,热热身。当然也有很多面试官上来就顺着项目问。根据你介绍项目的过程细节,穿插设置一系列的技术问题。

面试官一般会关注一些有挑战性的方案设计、解决了什么复杂难题,简单一句话,就是你的项目一定要有亮点。

那么,什么是亮点?我们的项目如何积累这些亮点?

下面我们会介绍项目中一些高频亮点设计,我们平时做项目,设计技术方案时也可以多用用,积累些实战经验 。

面对复杂业务,架构设计有什么通用思路?

答案:业务理解转化能力、思维抽象能力、软件建模能力、高并发、高性能、高可用的分布式系统架构设计能力。

谈谈对 DDD 的理解?

答案:通过实体、值对象、聚合根、领域服务、领域对象、限界上下文、资源库,指导微服务落地,将一个大的复杂业务域拆分成若干业务子域。定义领域模型(包含数据、行为),相似业务聚合。

画下项目的业务架构图?

答案:要对简历的项目非常熟悉,不只是自己负责的那部分,观整体通细节。

很多同学面试前没有系统化梳理,面试时现组织语言,给人感觉思路凌乱、条理不够清晰。

面试前可以先自己画画系统架构,理清其中的依赖关系。同时,提炼核心有挑战的技术难点,面试时,重点介绍其来龙去脉。

项目中用过哪些设计模式?

答案:工厂、装饰、克隆、代理、适配器、观察者、策略、模板、单例、责任链、门面等23种软件设计模式,这是软件开发的基本功,每一种设计模式都要非常熟悉。否则很难写出扩展性很高的代码。

之前写过三篇文章,每一种模式都有详细介绍:

如何提升系统的吞吐量?

答案:围绕系统的 “三高原则”,高并发、高性能、高可用,三个方向展开。

面对海量数据,什么是水平拆分、垂直拆分?

答案:

1、垂直拆分可以分为业务维度、技术维度。

  • 业务维度:结合DDD领域驱动设计,将一个大的业务域拆分为若干业务子域,比如电商可以拆分为商户、商品、库存、权限、会员、营销、交易、支付、履约、订单、结算、仓储、物流、财务等。

  • 技术维度:将一个有很多字段的表,按字段的大小、使用频率等特点,拆分为多张表。

2、水平拆分

由于单台机器的性能有限,无法支撑海量数据存储。我们引入逻辑表概念,采用集群模式,将一张逻辑表拆分成多张物理表分散存储在不同服务器,通过分表键路由,比如:时间区域用户id等。

特点:虽然有多张表,但每张表的表结构都是一样的,区别是数据不一样。所有表的数据合并起来才是这个业务表的完整数据。

画外音:数据量大,就分表;并发高,就分库

更多内容,参考 单台 MySQL 支撑不了这么多的并发请求,我们该怎么办?

分库分表时,全局性主键ID有哪些生成方案?

答案:

1、UUID,生成的是 32 位的字符串,虽然可以做到全局唯一性,但我们一般推荐使用整型。

2、SNOWFLAKE,雪花算法,生成一个 64 位的Long类型数据。组成结构:正数位(占1位)+ 时间戳(占41位)+ 工作机器id(10位)+ 序列号部分(12位)

3、数据库号段模式,对不同的业务类型定义初始值和步长,业务系统引入SDK,本地缓存预申请一定数据量的主键ID值,满足一定的并发要求。

4、TinyID,滴滴的开源框架

5、Redis 的 incr 命令

6、Leaf,美团的开源框架

7、Uidgenerator,百度的开源框架

不停机情况下,数据库扩容要怎么做?

答案:

1、首先,创建好新库,应用端修改代码,采用双写机制,将数据也同步一份到新库中

2、数据迁移,将老库中的数据迁移到新库中

3、对新老数据库做数据核对,对不一致的数据做定向同步

4、开关打开,读操作切换到新库,通过线上真实流量验证数据的准确性。

5、经过一段时间的线上验证后,如果没问题,将老库的写操作下线

缓存更新常用策略?

答案:

  • Cache aside,通常会先更新数据库,然后再删除缓存,为了兜底还会设置缓存时间。

  • Read/Write through, 一般是由一个 Cache Provider 对外提供读写操作,应用程序不用感知操作的是缓存还是数据库。

  • Write behind,延迟写入,Cache Provider 每隔一段时间会批量写入数据库,大大提升写的效率。像操作系统的page cache也是类似机制。

写操作时,缓存和数据库如何保持一致性?

答案:常见的方案有以下几个

1、先更新数据库,再更新缓存。

由于是两个操作,如果多线程并发情况下,很难保证线程之间的顺序,可能导致缓存的是旧数据。一般不推荐这种方案

2、先删除缓存,再更新数据库

两个操作,如果中间执行过程中,缓存被删除,恰好有其他线程来读数据,缓存会被重新预热旧的数据。一般不推荐这种方案

3、先更新数据库,再删缓存。

可能会导致无效删除,但是删除本身具有幂等性。该方案成本最低,一般推荐该方案

4、借助消息中间件,对缓存的数据强制维护,但也只能保证最终一致性。

5、不管最终采用哪种方案,Key都要设置一个过期时间,借助自身的淘汰机制保证数据的更新。

如何减少接口的响应时间?

答案:

  • 1、减少接口的处理内容,将非核心逻辑移除,采用MQ解耦,异步化处理。

  • 2、接口内部引入本地缓存和分布式缓存,提升数据加载速度

  • 3、引入池化技术(线程池、进程池、对象池、内存池、连接池、协程池)

整理了一份大厂常考面试题,这份pdf包括 Java基础、Java并发、JVM、MySQL、Redis、Spring、MyBatis、Kafka、设计模式等面试题,分享给大家。
下载地址:百度云链接:https://pan.baidu.com/s/1XHT4ppXTp430MEMW2D0-Bg 提取码: s3ab

事务有哪些特性?

答案:

1、原子性(Atomicity),原子性是指事务是一个不可分割的工作单位,事务中的操作要么全部成功,要么全部失败。

2、持久性(Durability),事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。

3、一致性(Consistency),事务必须使数据库从一个一致性状态变换到另外一个一致性状态。

4、隔离性(Isolation),一个事务不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。

分布式事务,有哪些解决方案?

答案:

1、执行业务逻辑前,先插入流水任务,如果中间过程调用外部RPC接口服务或者本地数据库操作失败时,流水任务会被定时调度任务周期性触发、重试,直到成功。前提条件,所有接口服务都要实现幂等。当执行成功时,流水记录会被删除。

2、基于事务消息,能保证本地数据库一定成功,其他业务系统做为订阅方,通过重试机制保证最终一致性,但要注意接口幂等。

3、两阶段提交

4、引入业务状态机,初始为 init 状态(对外不可见),待所有依赖的RPC接口全部调用一遍,待所有接口的数据全部初始化,然后开始第二轮调用,将状态置为对外可见。当然,此阶段可能会部分调用失败,需要多次重试

5、TCC 模式。Try:尝试待执行的业务;Confirm:执行业务;Cancel:回滚执行的业务

6、Seata 阿里开源框架,把分布式事务定义为由若干本地事务(分支)组成的全局事务。被全局事务管理的全部分支,将在协调器的协调下,保证一起成功或一起回滚。

上面列举的方案细节,可以查看 如何解决分布式事务

如何预防死锁?

答案:互斥条件、请求和保持条件、环路等待、不可剥夺。只要打破其他一个条件即可。

什么是乐观锁?什么是悲观锁?

答案:

  • 乐观锁:分为三个阶段:数据读取、写入校验、数据写入。在数据进行提交更新时,才会正式对数据的冲突与否进行检测,如果发现冲突了,则返回错误信息,让用户决定如何去做,fail-fast机制。

  • 悲观锁:对数据的修改持保守态度,在整个数据处理过程中,将数据处于锁定状态,期间其他用户长时间无法访问,影响程序的并发访问性。

常见的限流策略有哪些?

答案:

接口幂等性,有哪些方案?

答案:Select 查询天然支持幂等,而写操作 多次执行可能会导致数据错误,下面简单列举常见的解决方案:

  • insert、update 之前,先select 查询校验

  • 表中加唯一约束

  • 加悲观锁 , select * from order where order_id= 100000 for update; 对操作行锁定。

  • 加乐观锁,表中增加一个attribute_cc自增字段,借助CAS机制控制并发

  • 有些表不适合添加唯一约束,可以单独建一张防重表,在防重表插入成功,在操作其它业务表

  • 引入状态机, update order set status = "wait_seller_send_good" where id=1 and status = "wait_buyer_pay";

  • 采用 分布式锁,第一次请求可以成功加锁,后续请求加锁失败,认为是重复请求。

  • token机制,client 首先请求获取token,提交时除了业务参数外还要带上这个token,server端会对这个token核销,只能核销一次。如果 server 查询不到token,则认为是重复请求。

定时任务,有哪些实现方案?

  • Time,JDK自带的定时器类,与 TimerTask 一起配合使用

  • ScheduledExecutorService,位于java.util.concurrent并发包下,基于多线程。

  • spring task,通过 @Scheduled 注解定义定时规则

  • quartz,开源框架

  • xxl-job,大众点评开源的一个分布式任务调度平台

  • elastic-job,当当网开源的弹性分布式任务调度系统,采用zookeeper实现分布式协调,实现任务高可用以及分片,适用于高并发等复杂业务场景。

经历过的项目,有没有遇到过什么线上问题?

答案:结合自己的工作经历来讲,一个程序员肯定都经历过线上救火的场景。那么找些有技术难度的整理下,如:

  • 没有正确使用Redis的结构,缓存对象的粒度较大,高并发流量导致带宽不足,网络拥堵,连接无法及时释放,客户端报获取连接超时,进而引发整个系统的雪崩。

  • Pulsar系统告警,消息堆积。经排查,某个业务需求改动,SQl没有命中索引,导致接口处理时间增加数倍,从而降低了消费速度,进而消息堆积。

  • 线上系统报OOM问题、内存泄露问题

以上,只是个举个例子。不同的业务,不同的系统,不同的人,经历的线上问题也千奇百怪,可以多收集些。


关于我:前阿里P7技术专家,出过专利,竞赛拿过奖,CSDN博客专家,负责过电商交易、社区生鲜、互联网金融等业务,多年团队管理经验。

Logo

欢迎加入西安开发者社区!我们致力于为西安地区的开发者提供学习、合作和成长的机会。参与我们的活动,与专家分享最新技术趋势,解决挑战,探索创新。加入我们,共同打造技术社区!

更多推荐