目录
7、说说分库与分表设计、分库与分表带来的分布式困境与应对之策
7、你怎么理解 RESTful(Resource REpresentational State Transfer)
8、说说如何设计一个良好的 API(Application Programming Interface,应用程序编程接口)
分布式
1、分布式的与缺点
2、谈谈业务中使用分布式的场景
系统为什么使用分布式:
随着互联网的发展,传统单工程项目的很多性能瓶颈越发凸显,性能瓶颈可以有几个方面:
1、应用服务层:随着用户量的增加,并发量增加,单项目难以承受如此大的并发请求导致的性能瓶颈。
2、底层数据库层:随着业务的发展,数据库压力越来越大,导致的性能瓶颈。
场景1:应用系统集群的 Session 共享
应用系统集群最简单的就是服务器集群,比如:Tomcat 集群。应用系统集群的时候,比较凸显的问题是 Session 共享,Session 共享我们一是可以通过服务器插件来解决。另外一种也可以通过 Redis 等中间件实现。
场景2:应用系统的服务化拆分
服务化拆分,是目前非常火热的一种方式。现在都在提微服务。通过对传统项目进行服务化拆分,达到服务独立解耦,单服务又可以横向扩容。服务化拆分遇到的经典问题就是分布式事务问题。目前,比较常用的分布式事务解决方案有几种:消息最终一致性、TCC 补偿型事务等。
场景3:底层数据库的压力分摊
如果系统的性能压力出现在数据库,那我们就可以读写分离、分库分表等方案进行解决。
3、Session 分布式方案
第一种:使用硬件F5做粘性会话(不会,只是知道可以这么干),成本太高,后期也不好维护。
第二种:使用Nginx的ip_hash特性做粘性会话,可以让用户每次访问都转发到该用户第一次访问的web容器上,但是当该web容器上的应用挂了,nginx不会将该用户的请求转发到别的web容器,体验不好。
第三种:基于cookie实现,将session直接存储到cookie中(安全问题,虽然可以加密存储,但是觉得不能将敏感数据放在客户端)
第四种:使用容器扩展来实现,大家比较容易接受的是通过容器插件来实现,比如基于Tomcat的memcached-session-manager / tomcat-redis-session-manager,基于Jetty的jetty-nosql-memcache / jetty-session-redis等等。好处是对项目来说是透明的,无需改动代码。不过前者目前还不支持Tomcat 8,或者说不太完善。此方法过于依赖容器,一旦容器升级或者更换意味着又得从新来过。并且代码不在项目中,对开发者来说维护也是个问题(如果你使用的是weblogic、jboss、websphere等商业web容器,根本没有这种第三方容器扩展,web容器换了厂商就不行了)。
第五种:自己实现一套会话管理,将session读取/存储到Redis或其他nosql或数据库(网站用户量大的情况下,频繁dml数据,对db压力大)中。很显然这个方案灵活性最大,但开发需要一些额外的时间。弄懂了会挺不错的。
第六种:使用框架的会话管理工具spring-session,可以理解是替换了Servlet那一套会话管理,既不依赖容器,又不需要改动代码,并且是用了spring-data-redis那一套连接池,可以说是最完美的解决方案。当然,前提是项目要使用Spring Framework才行。
第七种:如果项目中使用shiro这种自带session(非httpsession)的权限框架,需要重写shiro的SessionDao将session存入redis(或其他)来实现session共享,可以自己重写(也不是很麻烦)或者找现成的(shiro-redis微笑脸,省的自己造轮子了,知道原理就行)。
4、分布式锁的场景及分布是锁的实现方案
https://www.cnblogs.com/zhisheng/p/8947996.html
5、分布式事务
https://www.cnblogs.com/jiangyu666/p/8522547.html
6、集群与负载均衡的算法与实现
什么是负载均衡:
负载均衡,英文名称为Load Balance,指由多台服务器以对称的方式组成一个服务器集合,每台服务器都具有等价的地位,都可以单独对外提供服务而无须其他服务器的辅助。通过某种负载分担技术,将外部发送来的请求均匀分配到对称结构中的某一台服务器上,而接收到请求的服务器独立地回应客户的请求。负载均衡能够平均分配客户请求到服务器阵列,借此提供快速获取重要数据,解决大量并发访问服务问题,这种集群技术可以用最少的投资获得接近于大型主机的性能。
负载均衡分为软件负载均衡和硬件负载均衡,前者的代表是阿里章文嵩博士研发的LVS,后者则是均衡服务器比如F5。
负载均衡的常用算法:
1、随机(Random)
通过随机数生成算法选取一个服务器,然后把连接发送给它。
2、轮询(Round Robin)
轮询调度算法的原理:
每一次把来自用户的请求轮流分配给内部中的服务器,从1开始,直到N(内部服务器个数),然后重新开始循环。算法的优点是其简洁性,它无需记录当前所有连接的状态,所以它是一种无状态调度。
缺点:不考虑每台服务器的处理能力
3、加权轮询(Weight Round Robin)
由于每台服务器的配置、安装的业务应用等不同,其处理能力会不一样。所以,我们根据服务器的不同处理能力,给每个服务器分配不同的权值,使其能够接受相应权值数的服务请求。
4、Source Hashing(源地址Hash)
源地址散列调度算法是一种静态映射算法,它通过一个散列(Hash)函数将一个源IP地址映射到一台服务器,若该服务器是可用的并且没有超负荷,将请求发送到该服务器,否则返回空。它采用的散列函数与目标地址散列调度算法的相同。它的算法流程与目标地址散列调度算法的基本相似,除了将请求的目标IP地址换成请求的源IP地址,所以这里不一个一个叙述。
5、Destination hashing(目标地址Hash)
目标地址散列调度算法也是针对目标IP地址的负载均衡,它是一种静态映射算法,通过一个散列(Hash)函数将一个目标IP地址映射到一台服务器。目标地址散列调度算法先根据请求的目标IP地址,作为散列键(Hash Key)从静态分配的散列表找出对应的服务器,若该服务器是可用的且未超载,将请求发送到该服务器,否则返回空。
6、一致哈希(consistent-hash)
一致哈希(consistent-hash)
7、Least-Connection(最少连接)
最少连接调度算法是把新的连接请求分配到当前连接数最小的服务器,最小连接调度是一种动态调度短算法,它通过服务器当前所活跃的连接数来估计服务器的负载均衡,调度器需要记录各个服务器已建立连接的数目,当一个请求被调度到某台服务器,其连接数加1,当连接中止或超时,其连接数减一,在系统实现时,我们也引入当服务器的权值为0时,表示该服务器不可用而不被调度。
Dubbo负载均衡:https://www.cnblogs.com/javanoob/p/dubbo_loadbalance.html
7、说说分库与分表设计、分库与分表带来的分布式困境与应对之策
微服务
1、前后端分离是如何做的
淘宝前后分离实践:https://2014.jsconfchina.com/slides/herman-taobaoweb/index.html#/57
https://blog.csdn.net/fuzhongmin05/article/details/81591072
https://blog.csdn.net/weixin_37539378/article/details/79956760
https://blog.csdn.net/belalds/article/details/81571830
前后端分离的优势:
1、可以实现真正的前后端解耦,前端服务器使用nginx。前端/WEB服务器放的是css,js,图片等等一系列静态资源(甚至你还可以css,js,图片等资源放到特定的文件服务器,例如阿里云的oss,并使用cdn加速),前端服务器负责控制页面引用&跳转&路由,前端页面异步调用后端的接口,后端/应用服务器使用tomcat(把tomcat想象成一个数据提供者),加快整体响应速度。(这里需要使用一些前端工程化的框架比如nodejs,react,router,react,redux,webpack)
2、发现bug,可以快速定位是谁的问题,不会出现互相踢皮球的现象。页面逻辑,跳转错误,浏览器兼容性问题,脚本错误,页面样式等问题,全部由前端工程师来负责。接口数据出错,数据没有提交成功,应答超时等问题,全部由后端工程师来解决。双方互不干扰,前端与后端是相亲相爱的一家人。
3、在大并发情况下,我可以同时水平扩展前后端服务器,比如淘宝的一个首页就需要2000+台前端服务器做集群来抗住日均多少亿+的日均pv。
4、减少后端服务器的并发/负载压力。除了接口以外的其他所有http请求全部转移到前端nginx上,接口的请求调用tomcat,参考nginx反向代理tomcat。且除了第一次页面请求外,浏览器会大量调用本地缓存。
5、即使后端服务暂时超时或者宕机了,前端页面也会正常访问,只不过数据刷不出来而已。
6、也许你也需要有微信相关的轻应用,那样你的接口完全可以共用,如果也有app相关的服务,那么只要通过一些代码重构,也可以大量复用接口,提升效率。(多端应用)
7、页面显示的东西再多也不怕,因为是异步加载。
8、nginx支持页面热部署,不用重启服务器,前端升级更无缝。
9、增加代码的维护性&易读性(前后端耦在一起的代码读起来相当费劲)。
10、提升开发效率,因为可以前后端并行开发,而不是像以前的强依赖。
11、在nginx中部署证书,外网使用https访问,并且只开放443和80端口,其他端口一律关闭(防止黑客端口扫描),内网使用http,性能和安全都有保障。
12、前端大量的组件代码得以复用,组件化,提升开发效率,抽出来!
前后端分离注意事项
1、相关会议前后端工程师必须全部参加,并且需要制定好接口文档,后端工程师要写好测试用例,不要让前端工程师充当你的专职测试,推荐使用chrome的插件postman或soapui或jmeter,service层的测试用例拿junit写。ps:前端也可以玩单元测试吗?
2、上述的接口并不是java里的interface,说白了调用接口就是调用你controler里的方法。
3、加重了前端团队的工作量,减轻了后端团队的工作量,提高了性能和可扩展性。
4、我们需要一些前端的框架来解决类似于页面嵌套,分页,页面跳转控制等功能。
5、如果页面上有一些权限等等相关的校验,那么这些相关的数据也可以通过ajax从接口里拿。
6、对于既可以前端做也可以后端做的逻辑,我建议是放到前端,为什么?因为你的逻辑需要计算资源进行计算,如果放到后端去run逻辑,则会消耗带宽&内存&cpu等等计算资源,你要记住一点就是服务端的计算资源是有限的,而如果放到前端,使用的是客户端的计算资源,这样你的服务端负载就会下降(高并发场景)。类似于数据校验这种,前后端都需要做!
7、前端需要有机制应对后端请求超时以及后端服务宕机的情况,友好的展示给用户。
2、如何解决跨域(CSRF)
https://segmentfault.com/a/1190000015597029
3、微服务哪些框架
4、你怎么理解 RPC 框架
5、说说 RPC 的实现原理
RPC的经典调用的流程
6、说说 Dubbo 的实现原理
https://blog.csdn.net/gangsijay888/article/details/88630019
7、你怎么理解 RESTful(Resource REpresentational State Transfer)
8、说说如何设计一个良好的 API(Application Programming Interface,应用程序编程接口)
(1)要明确
这也许是最重要一点。如果你有一个方法getUser,如果不明确它可能引起一些副作用,最终会导致很多问题。比如getUser明确的只是返回一个用户,不会对用户的id进行增加。
尽可能多的提供更多的行为。不要指望用户会潜水你的源码,以发现隐藏的行为。
(2)让a p i表面积尽可能小
没有人喜欢臃肿的程序,如果你能够暴露更少的api就能完成工作,这对于每个人都是一个很好的体验。
是否人们真的要求你写这个新的api?一直到它是一个真正需要有人去解决的问题的时候,你才可以去做它。
(3)减少样板
尽可能的在内部处理各种细节,以减少客户端的负担。客户端调用的时候做的越少,漏洞才可能越少。
喜欢干净的代码?那就保持你的api很干净,那么,你的api的客户调用就会很简洁。
(4)降低依赖
尽可能的保证你的代码人自我封闭,你有更多的依赖,就意味着潜在的问题会影响到下游代码。
如果你希望从另外一个模块里,获取一块功能,那么尽可能的只提取你需要的。在代码重用和紧耦合和之间有一个平衡,如果功能比较小,那么就值得你自己重新实现它。
(5)返回有意义的错误状态
返回null是毫无意义的,他什么也意味不了。错误信息要能够有可以进行改善的提示。Error.USER_NOT_CREATED 或Error.USER_DELETED都是有意义的。
(6)异常应该有真正的含义
如果你使用的语言没有异常,祝贺你,函数式语言在提供有意义的错误状态方面会做的更好。
一场已经在java领域被滥用,getUser时如果没有发现用户,不要抛UserNotFoundException,而是返回一个正常的错误状态。
比一个蹦溃的程序更坏的事情是,不要因为一个不确定的状态导致崩溃。
(7)对所有的事情要建立文档
文档是无聊的,但必不可少,良好的文档会保存你的理智思考,会避免api消费的很多问题。
一个好的文档包括:
1.有关模块是如何工作的高层次概述
2.公共方法和接口的javadoc
3.如何使用api的案例
不是所有的抽象都需要文档的,一些小类就不需要案例代码。
文档必须是演进,如果有很多问题问同样的事情,你就可能需要把它加到文档里。
太多的文档也是浪费时间,因为你必须保持不断的更新,但是如果仍没有人使用,它就没有什么价值,所以要保证足够的重点和适当的文档。
(8)编写测试
这是是正确性的证明,文档和示例代码都可以包括进去。它为中国提供了巨大的价值,能够让你在事情改变时候,很自信的快速移动。
那些想对你的api实现深入研究的人总是,通过阅读测试实现的,能够更多的了解你的代码行为和意图。这些都是文档无法实现的。
(9)变得可测试
测试你的代码是一回事儿,让人们对你的api更容易地编写测试代码又是另外一回事儿。
你需要有针对调试和产品环境的不同配置。
(10)允许用户选择
不是每一个客户端都以同样的方式调用你的api,有些人可能喜欢同步调用,而另外一些人更喜欢一部回调。
让用户选择他们自己喜欢的方式,你的api就更容易集成到他们现有的编程环境中,更可能地被使用。
(11)不要给用户太多的选择
不要给用户太多的选择,否则他们就有选择障碍,总是提供合理的默认行为,也就是你的api默认的使用方式。
api应该鼓励规范行为,不要让消费者修改内部状态,如果你无意中暴露一些怪异的行为,它会产生一些不可预见的后果。
给出态度的选择就会失去重点,在正确和灵活之间要进行平衡和选择。
总之,设计一个api是一种艺术,需要更多的实践。
9、如何理解 RESTful API 的幂等性
https://blog.csdn.net/garfielder007/article/details/55684420
10、如何保证接口的幂等性
幂等策略分析:https://www.cnblogs.com/geyifan/p/6128425.html
11、说说 CAP 定理、 BASE 理论(见分布式)
https://www.cnblogs.com/jiangyu666/p/8522547.html
12、怎么考虑数据一致性问题(分布式事务)
https://www.cnblogs.com/jiangyu666/p/8522547.html
13、说说最终一致性的实现方案
14、你怎么看待微服务
15、微服务与 SOA 的区别
16、如何拆分服务
服务的拆分是一个非常有学问的技术活,要围绕业务模块进行拆分,拆分粒度应该保证微服务具有业务的独立性与完整性,尽可能少的存在服务依赖,链式调用。但是,在实际开发过程中,有的时候单体架构更加适合当前的项目。实际上,微服务的设计并不是一蹴而就的,它是一个设计与反馈过程。因此,我们在设计之初可以将服务的粒度设计的大一些,并考虑其可扩展性,随着业务的发展,进行动态地拆分也是一个不错的选择。
17、微服务如何进行数据库管理
https://www.jianshu.com/p/cd726b32342e
18、如何应对微服务的链式调用异常
一般情况下,每个微服务之间是独立的,如果某个服务宕机,只会影响到当前服务,而不会对整个业务系统产生影响。但是,服务端可能会在多个微服务之间产生一条链式调用,并把整合后的信息返回给客户端。在调用过程中,如果某个服务宕机或者网络不稳定可能造成整个请求失败。因此,为了应对微服务的链式调用异常,我们需要在设计微服务调用链时不宜过长,以免客户端长时间等待,以及中间环节出现错误造成整个请求失败。此外,可以考虑使用消息队列进行业务解耦,并且使用缓存避免微服务的链式调用从而提高该接口的可用性。
19、对于快速追踪与定位问题
https://blog.51cto.com/wks97/2074615
https://www.jianshu.com/p/904c48e6bc0c
20、微服务的安全
https://blog.csdn.net/qq_36807862/article/details/81284327
安全问题
1、安全要素与 STRIDE 威胁
http://blog.720ui.com/2017/security_stride/
2、防范常见的 Web 攻击
3、服务端通信安全攻防
4、HTTPS 原理剖析
5、HTTPS 降级攻击
http://blog.jobbole.com/106792/
6、授权与认证
7、基于角色的访问控制
8、基于数据的访问控制
http://blog.720ui.com/2017/msa_rbac_data/
性能优化
1、性能指标有哪些
性能测试监控关键指标说明:
资源指标
CPU使用率:指用户进程与系统进程消耗的CPU时间百分比,长时间情况下,一般可接受上限不超过85%。
内存利用率:内存利用率=(1-空闲内存/总内存大小)*100%,一般至少有10%可用内存,内存使用率可接受上限为85%。
磁盘I/O: 磁盘主要用于存取数据,因此当说到IO操作的时候,就会存在两种相对应的操作,存数据的时候对应的是写IO操作,取数据的时候对应的是是读IO操作,一般使用% Disk Time(磁盘用于读写操作所占用的时间百分比)度量磁盘读写性能。
网络带宽:一般使用计数器Bytes Total/sec来度量,Bytes Total/sec表示为发送和接收字节的速率,包括帧字符在内。判断网络连接速度是否是瓶颈,可以用该计数器的值和目前网络的带宽比较。
系统指标:
并发用户数:某一物理时刻同时向系统提交请求的用户数。
在线用户数:某段时间内访问系统的用户数,这些用户并不一定同时向系统提交请求。
平均响应时间:系统处理事务的响应时间的平均值。事务的响应时间是从客户端提交访问请求到客户端接收到服务器响应所消耗的时间。对于系统快速响应类页面,一般响应时间为3秒左右。
事务成功率:性能测试中,定义事务用于度量一个或者多个业务流程的性能指标,如用户登录、保存订单、提交订单操作均可定义为事务,如下图所示:
单位时间内系统可以成功完成多少个定义的事务,在一定程度上反应了系统的处理能力,一般以事务成功率来度量,计算公式如下所示:
超时错误率:主要指事务由于超时或系统内部其它错误导致失败占总事务的比率。
2、如何发现性能瓶颈
https://blog.csdn.net/sd4015700/article/details/50467346
https://www.jianshu.com/p/87ef6d1c3398
3、性能调优的常见手段、说说你在项目中如何进行性能调优