腾讯泛工业化后台开发面试问题汇总

本文深入探讨了数据库的四种隔离级别,包括可重复读、读已提交、读未提交和可串行化,以及它们在并发处理和数据一致性方面的表现。此外,还介绍了协程的概念,作为轻量级线程的优势,以及Java中的BIO、NIO和AIO的区别。同时,分析了微服务架构的优缺点,如模块化开发、独立部署和扩展性,以及面临的分布式复杂性、测试挑战和部署难题。最后,讨论了服务器面临连接上限时的处理策略,如调整系统参数和使用负载均衡。
摘要由CSDN通过智能技术生成

自我介绍:

应该考察基本信息,这个按照自己的实际情况回答。


做过的最难的东西是啥:

应该考察技术顶点是啥,这个按照自己的实际情况回答。(我回答了个spark算法的优化点)


zookeeper 原理:

from:https://blog.csdn.net/java_66666/article/details/81015302
 


数据库隔离机制:

隔离级别说明

MySQL定义了四种隔离级别,包括一些具体规则,用于限定事务内外哪些改变是可见的,哪些改变是不可见的。低级别的隔离一般支持更高的并发处理,并且拥有更低的系统开销。

REPEATABLE READ Repeatable Read 可重复读

MySQL数据库默认的隔离级别。该级别解决了READ UNCOMMITTED隔离级别导致的问题。它保证同一事务的多个实例在并发读取事务时,会“看到同样的”数据行。不过,这会导致另外一个棘手问题“幻读”。InnoDB和Falcon存储引擎通过多版本并发控制机制解决了幻读问题。

READ COMMITTED Read Committed 读取提交内容

大多数数据库系统的默认隔离级别(但是不是MySQL的默认隔离级别),满足了隔离的早先简单定义:一个事务开始时,只能“看见”已经提交事务所做的改变,一个事务从开始到提交前,所做的任何数据改变都是不可见的,除非已经提交。这种隔离级别也支持所谓的“不可重复读”。这意味着用户运行同一个语句两次,看到的结果是不同的。

READ UNCOMMITTED Read UnCommitted 读取未提交内容

在这个隔离级别,所有事务都可以“看到”未提交事务的执行结果。在这种级别上,可能会产生很多问题,除非用户真的知道自己在做什么,并有很好的理由选择这样做。本隔离级别很少用于实际应用,因为它的性能也不必其他性能好多少,而别的级别还有其他更多的优点。读取未提交数据,也被称为“脏读”

SERIALIZABLE Serializable 可串行化

该级别是最高级别的隔离级。它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简而言之,SERIALIZABLE是在每个读的数据行上加锁。在这个级别,可能导致大量的超时Timeout和锁竞争Lock Contention现象,实际应用中很少使用到这个级别,但如果用户的应用为了数据的稳定性,需要强制减少并发的话,也可以选择这种隔离级

下面的表格总结了各种隔离级别和各自的缺点

隔离级别脏读可能性不可重复读可能性幻读可能性加锁读
READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ
SERIALIZABLE

from:https://blog.csdn.net/sinat_35322593/article/details/81040479


协程是什么?

协程是比线程更小的一种执行单元,你可以认为是轻量级的线程,之所以说轻,其中一方面的原因是协程所持有的栈比线程要小很多,java当中会为每个线程分配1M左右的栈空间,而协程可能只有几十或者几百K,栈主要用来保存函数参数、局部变量和返回地址等信息。

我们知道,而线程的调度是在操作系统中进行的,而协程调度则是在用户空间进行的,是开发人员通过调用系统底层的执行上下文相关api来完成的,有些语言,比如nodejs、go在语言层面支持了协程,而有些语言,比如C,需要使用第三方库才可以拥有协程的能力。

由于线程是操作系统的最小执行单元,因此也可以得出,协成是基于线程实现的,协程的创建、切换、销毁都是在某个线程中来进行的。

使用协程是因为线程的切换成本比较高,而协程在这方面很有优势。

为什么协程的切换很廉价

关于这个问题,我找了很多资料,得到的答案都没有太高的说服力,我了解了一下线程切换的过程:

  • 线程在进行切换的时候,需要将CPU中的寄存器的信息存储起来,然后读入另外一个线程的数据,这个会花费一些时间
  • CPU的高速缓存中的数据,也可能失效,需要重新加载
  • 线程的切换会涉及到用户模式到内核模式的切换,据说每次模式切换都需要执行上千条指令,很耗时。

协程的切换之所以快,可能的原因是:

  • 在切换的时候,寄存器需要保存和加载的数据量比较小。
  • 高速缓存可以有效利用
  • 没有用户模式到内核模式的切换操作。
  • 更有效率的调度,因为协程是非抢占式的,前一个协程执行完毕或者堵塞,才会让出CPU,而线程则一般使用了时间片的算法,会进行很多没有必要的切换(为了尽量让用户感知不到某个线程卡)。

有哪些协程的实现

目前协程有很多版本的实现,比如云风(原网易的研发总监,开发过《大话西游》、《梦幻西游》等知名游戏)的基于ucontext实现的coroutine,还有人用C语言语法switch-case来实现的。

from:https://www.jianshu.com/p/658cb5360960


java的BIO、BIO和AIO分别是什么,区别是什么?

from:https://blog.csdn.net/m0_38109046/article/details/89449305?utm_medium=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param


aAuth是如何登陆?

OAuth2.0是什么——豆瓣和QQ的故事

OAuth简单说就是一种授权的协议,只要授权方和被授权方遵守这个协议去写代码提供服务,那双方就是实现了OAuth模式。

举个例子,你想登录豆瓣去看看电影评论,但你丫的从来没注册过豆瓣账号,又不想新注册一个再使用豆瓣,怎么办呢?不用担心,豆瓣已经为你这种懒人做了准备,用你的qq号可以授权给豆瓣进行登录,请看

from:https://www.cnblogs.com/flashsun/p/7424071.html


java的 hash 原理是什么,假如自己实现一个,如何实现,思路是什么?

hashmap是一个key-value键值对的数据结构,从结构上来讲在jdk1.8之前是用数组加链表的方式实现,jdk1.8加了红黑树,hashmap数组的默认初始长度是16,hashmap数组只允许一个key为null,允许多个value为null
hashmap的内部实现,hashmap是使用数组+链表+红黑树的形式实现的,其中数组是一个一个Node[]数组,我们叫他hash桶数组,它上面存放的是key-value键值对的节点。HashMap是用hash表来存储的,在hashmap里为解决hash冲突,使用链地址法,简单来说就是数组加链表的形式来解决,当数据被hash后,得到数组下标,把数据放在对应下表的链表中。
然后再说一下hashmap的方法实现
put方法,put方法的第一步,就是计算出要put元素在hash桶数组中的索引位置,得到索引位置需要三步,去put元素key的hashcode值,高位运算,取模运算,高位运算就是用第一步得到的值h,用h的高16位和低16位进行异或操作,第三步为了使hash桶数组元素分布更均匀,采用取模运算,取模运算就是用第二步得到的值和hash桶数组长度-1的值取与。这样得到的结果和传统取模运算结果一致,而且效率比取模运算高
jdk1.8中put方法的具体步骤,先判断hashmap是否为空,为空的话扩容,不为空计算出key的hash值i,然后看table[i]是否为空,为空就直接插入,不为空判断当前位置的key和table[i]是否相同,相同就覆盖,不相同就查看table[i]是否是红黑树节点,如果是的话就用红黑树直接插入键值对,如果不是开始遍历链表插入,如果遇到重复值就覆盖,否则直接插入,如果链表长度大于8,转为红黑树结构,执行完成后看size是否大于阈值threshold,大于就扩容,否则直接结束
get方法就是计算出要获取元素的hash值,去对应位置取即可。
扩容机制,hashmap的扩容中主要进行两部,第一步把数组长度变为原来的两倍,第二部把旧数组的元素重新计算hash插入到新数组中,在jdk1.8时,不用重新计算hash,只用看看原来的hash值新增的一位是零还是1,如果是1这个元素在新数组中的位置,是原数组的位置加原数组长度,如果是零就插入到原数组中。扩容过程第二部一个非常重要的方法是transfer方法,采用头插法,把旧数组的元素插入到新数组中。
3.hashmap大小为什么是2的幂次方
在计算插入元素在hash桶数组的索引时第三步,为了使元素分布的更加均匀,用取模操作,但是传统取模操作效率低,然后优化成h&(length-1),设置成2幂次方,是因为2的幂次方-1后的值每一位上都是1,然后与第二步计算出的h值与的时候,最终的结果只和key的hashcode值本身有关,这样不会造成空间浪费并且分布均匀,如果不是2的幂次方
如果length不为2的幂,比如15。那么length-1的2进制就会变成1110。在h为随机数的情况下,和1110做&操作。尾数永远为0。那么0001、1001、1101等尾数为1的位置就永远不可能被entry占用。这样会造成浪费,不随机等问题。

from:https://blog.csdn.net/qq_40574571/article/details/91569521

微服务架构的优势和劣势是什么?

微服务架构的好处

微服务架构模式有很多好处。首先,通过分解巨大单体应用为多个服务方法解决了复杂性问题。在功能不变的情况下,应用被分解为多个可管理的分支或服务。每个服务都有一个用 RPC- 或者消息驱动 API 定义清楚的边界。微服务架构模式给采用单体式编码方式很难实现的功能提供了模块化的解决方案,由此,单个服务很容易开发、理解和维护。

第二,这种架构使得每个服务都可以有专门开发团队来开发。开发者可以自由选择开发技术,提供 API 服务。当然,许多公司试图避免混乱,只提供某些技术选择。然后,这种自由意味着开发者不需要被迫使用某项目开始时采用的过时技术,他们可以选择现在的技术。甚至于,因为服务都是相对简单,即使用现在技术重写以前代码也不是很困难的事情。

第三,微服务架构模式使得每个微服务独立部署,开发者不再需要协调其它服务部署对本服务的影响。这种改变可以加快部署速度,譬如 UI 团队可以采用 AB 测试并快速部署变化。微服务架构模式使得持续化部署成为可能。

最后,微服务架构模式使得每个服务独立扩展。你可以根据每个服务的规模来部署满足需求的实利。甚至于,你可以使用更适合于服务资源需求的硬件。比如,你可以在 EC2 Compute Optimized instances 上部署 CPU 敏感的服务,而在 EC2 memory-optimized instances 上部署内存数据库。

微服务架构的不足

Fred Brooks 在 30 年前写道 “there are no silver bullets”,像任何其它科技一样,微服务架构也有不足。其中一个跟他的名字类似,“微服务”强调了服务大小,实际上,有一些开发者鼓吹建立稍微大一些的,10-100 LOC服务组。尽管小服务更乐于被采用,但是不要忘了微服务只是结果,而不是最终目的。微服务的目的是有效的拆分应用,实现敏捷开发和部署。

另外一个不足之处在于,微服务应用是分布式系统,由此会带来固有的复杂性。开发者需要在 RPC 或者消息传递之间选择并完成进程间通讯机制。此外,他们必须写代码来处理消息传递中速度过慢或者不可用等局部失效问题。当然这并不是什么难事,但相对于单体式应用中通过语言层级的方法或者进程调用,微服务下这种技术显得更复杂一些。

另外一个关于微服务的挑战来自于分区的数据库架构。同时更新多个业务主体的事务很普遍。这种事务对于单体式应用来说很容易,因为只有一个数据库。在微服务架构应用中,需要更新不同服务所使用的不同的数据库。使用分布式事务并不一定是好的选择,不仅仅是因为 CAP 理论,还因为当前高扩展性的 NoSQL 数据库和消息传递中间件并不支持这一需求。最终你不得不使用一个最终一致性的方法,从而对开发者提出了更高的要求和挑战。

测试一个基于微服务架构的应用也是很复杂的任务。比如,对于采用流行的 Spring Boot 架构的单体式 web 应用,测试它的 REST API,是很容易的事情。反过来,同样的服务测试需要启动与它有关的所有服务(至少需要这些服务的 stubs)。再重申一次,不能低估了采用微服务架构带来的复杂性。

另外一个挑战在于,微服务架构模式应用的改变将会波及多个服务。比如,假设你在完成一个案例,需要修改服务A、B、C,而 A 依赖 B,B 依赖 C。在单体应用中,你只需要改变相关模块,整合变化,部署就好了。对比之下,微服务架构模式就需要考虑相关改变对不同服务的影响。比如,你需要更新服务 C,然后是 B,最后才是 A。幸运的是,许多改变一般只影响一个服务,而需要协调多服务的改变很少。

部署一个微服务应用也很复杂,一个单体应用只需要在复杂均衡器后面部署各自的服务器就好了。每个应用实例是需要配置诸如数据库和消息中间件等基础服务。相比之下,一个微服务应用一般由大批服务构成。根据 Adrian Cockcroft 的分享,Hailo 由 160 个不同服务构成,而 NetFlix 则超过 600 个服务。每个服务都有多个实例,这就形成大量需要配置、部署、扩展和监控的部分。除此之外,你还需要完成一个服务发现机制(后续文章中发表),以用来发现与它通讯服务的地址(包括服务器地址和端口)。传统的解决问题办法并不能解决这么复杂的问题。最终,成功部署一个微服务应用需要开发者有足够的控制部署方法,并高度自动化。

自动化的方法之一是使用譬如 Cloud Foundry 这样的 PaaS 服务。PaaS 能让开发者轻松部署和管理微服务,让他们无需为获取并配置 IT 资源劳神。同时,配置 PaaS 的系统和网络专家可以采用最佳实践和策略来简化这些问题。另外一个自动部署微服务应用的方法是开发自己的基础 PaaS 系统。通常的起步方式是 Mesos 或 Kubernetes 这样的集群管理方案,配合 Docker 使用。作为一种基于软件的应用交付方法,NGINX 能够方便地在微服务层面提供缓冲、权限控制、API 统计、以及监控。我们会在后续的文章中分析它如何解决这些问题。


服务器网络连接达到上限,应该怎么处理?

1 受内存限制

每个tcp连接是一个打开的socket文件,因此linux服务器的最大连接数受linux操作系统单个进程同时打开的最大文件数的限制。

这个限制本质上是对单个进程内存的限制。

查看进程最大文件数:

ulimit -n 

设置进行最大文件数:

ulimit -n 100000

from:https://www.cnblogs.com/hustdc/p/10918744.html


总结:

基本上得按照简历进行准备,熟悉简历中的各个知识点。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值