JAVA和Nginx 教程大全

网站首页 > 精选教程 正文

面试题之你们项目架构是怎样的? 被面试官问项目技术架构

wys521 2024-11-03 16:58:05 精选教程 26 ℃ 0 评论


你好 我是懂java的测试



前言


现在的面试很卷,卷到你不仅要懂测试、还要了解后端技术,最经典的就是:"你们项目架构是怎样的?",每当被问到这个问题,很多人就很懵逼,甚至心里会痛骂,我?只是做测试的,为什么要了解后端架构啊?


骂也没用,目前就这样的行情,你不懂并不表示别人不懂,别人回答上来,就可以拿到满意的offer,你只能生闷气,为了不让你生闷气,气坏身体,打算用几篇文章详细聊聊后端架构的演变过程,帮助大家理解后端架构的从前、现在和未来。

基本概念解答


文章可能会时常蹦出一些难以理解的技术名词,为了帮助大家理解,所以提前拎出来解释一波。


分布式和集群的区别


分布式,系统中的多个模块在不同服务器上部署,即可称为分布式系。譬如电商系统中,商品模块、订单模块、支付模块等,在不同的服务器上部署,这个就叫分布式系统;


集群就是单独订单模块部署在几台机器上,形成一个订单模块集群,同样其他模块也是;


总结来说,就是分布式架构是多个模块业务部署在多台机器上,而集群就是一个模块业务部署多台机器上;


服务注册和发现


还是上面的例子,假如说,订单模块收到前端下单成功去支付的请求,去调用支付模块的接口,怎么办?java中比较传统老旧的做法就是通过Httpclient 包去调用,但是前提是代码或配置写死支付模块的接口路径和域名(ip);如截图:

由于支付模块是集群部署的,暴露三个ip(实例),这样会以下几个问题:

1、client 怎么把请求均匀打到这三台实例上?

2、这三台实例挂了一台,client察觉不到,还是会把请求发送到已故障的机器上。怎么避免?

3、业务高峰期,支付模块服务器压力过大,加了5台机器,那订单模块得先关闭服务,人工把这5台实例 ,写到代码或配置文件里,然后重启?

大哥,这是业务高发期,你关闭线上应用服务,确定老板不弄死你?

架构设计上有个很经典的哲学,“任何软件工程遇到的问题都可以通过增加一个中间层来解决!如果未解决,那就再加一层”,


因此,需要设置专门的服务来对实时变化的服务实例状态进行同步


说的能让人听懂的话就是,我在client和service 的中间加个中间层叫服务注册发现,管理service的服务实例;如截图



目前微服务的服务发现机制主要包含三个角色:服务提供者、服务消费者和服务注册表

服务提供者(Service Provider):服务启动时将服务实例信息注册到服务注册表,服务退出时主动发送请求将服务注册表的服务实例信息删除掉。


服务消费者(Service Consumer):从服务注册表获取服务提供者的最新网络位置等服务信息,维护与服务提供者之间的通信。


服务注册表(Service Registry):联系服务提供者和服务消费者的桥梁,维护服务提供者的最新服务实例信息。并和服务提供者保持一个心跳,通俗的说就是,每个服务实例会定期(30秒)发送请求给Service Registry ,告诉他我还活着,如果超过这个定期时间,没发送请求给Service Registry,那么Service Registry就认为这个实例挂掉了,从注册表剔除这个实例信息,那么Consumer大部分情况下,就不调用这个挂掉的实例了。


这样订单模块想调用支付模块的接口,就不用傻不拉几的在项目里写死对方的接口路径和ip,直接从服务注册中间层拿到支付模块的服务实例信息即可,直接调用。


负载均衡和高可用


还是结合上面的例子说明,订单模块通过服务注册发现中间件,拿到了三个支付模块的服务实例,那应该调用哪个呢?总不能只搁一只羊身上薅羊毛吧?得在三只羊身上均衡地薅,这样才不会被看出来。


为了让流量均衡打到这三个实例上,所以得做个负载均衡吧,但是放心吧,一般服务注册发现中间层会给你做好,订单模块只要配置好负载均衡策略就行了,


除此之外呢,前端的下单支付请求要打到订单模块这层,需要经过重重关卡,其中包括Nginx(具体看项目,不是所有的项目都用这玩意,但是这玩意真的很好,谁用谁知道),怎么把流量均匀的打到订单模块呢?负载均衡呗,


策略有哪些?轮询、加权轮询、随机、最小连接数等等;


高可用:还是上面的例子,支付模块为啥要有三个服务实例?一个不行吗?多省钱,多简单,如果有这样的想法,那就大错特错;


支付模块,最核心模块,没有之一,只有一台服务实例,万一挂了,整个系统暂时不能对外提供服务,那得损失多少money呐?


用户下单成功,支付不了,你觉得他下次还会再来吗?所以至少得2个服务实例,一个挂了,另一个还可以对外提供支付服务。这个就叫高可用。


中间件


顾名思义,中间件就是处于中间的软件。主要作用就是屏蔽操作系统的复杂性,屏蔽技术之间的局限性,使框架更加灵活。


譬如缓存中间件redis 是为了集中管理缓存空间,弥补本地缓存不能共享且资源有限的缺点。


消息中间件mq主要降低系统模块之间的耦合性、起到解耦、削峰的作用。


后端架构之过去


在上古时期,互联网公司应用刚起步,用户少,内容少、对高可靠,高性能的要求都很低。所以单体架构基本满足用户需求。


单体架构


一台服务器就搞定,运行应用程序和数据库,简单粗暴。


单体集群架构


随着互联网的发展,用户量增加,人们发现单体架构的弊端越来越明显,比如响应慢,性能低,在网站访问高峰时期,应用服务器会成为整个网站的瓶颈。因此增加应用服务器势在必然。


怎么把流量均衡打在这几台应用服务器上呢?通过负载均衡调度服务器,可将来自浏览器的访问请求分发到应用的集群中的任何一台服务器上,同时会用上本地缓存和分布式缓存,以提高网站响应效率。


分布式架构



以上单体应用所有模块都在一个项目里开发,在那个时代勉强满足用户需求。时间切回近代,不远也就前几年,大型互联网项目兴起,譬如淘宝电商系统,涉及到订单模块、支付、商品模块、购物车、个人中心、推荐模块、收藏、积分模块等等,如果还放在一个项目里去开发,会有以下几个问题:


1、代码变得臃肿不堪,各个模块,上千个代码文件,只改动了一行,编译部署一次却花费了将近半小时;


2、代码冲突变多,协作困难,多人开发同一个项目,提交代码,肯定会冲突,解决冲突又将是一场灾难;搞不好还会把别人辛辛苦苦写的代码,覆盖掉。


3、单模块的故障可能导致其他模块不可用,假如订单模块内存泄露、溢出,Jvm fullgc 频繁又会影响其他模块。


咋整?用广大人民群众最喜欢的一个字,拆!


根据业务实际情况把整个淘宝电商系统拆成订单、支付、库存等单独的模块,每个模块代码部署到一组应用服务器上,这个就是分布式架构,每组服务器就叫做集群。


与此同时,原本数据库里的订单表、库存表等等,按照业务模块垂直拆分,做到一个模块,一个库,每个库也可以读写分离或分库分表。如截图:



问题来了,单体应用模块之间的调用都是方法调用,拆成分布式架构以后咋调用?


服务注册与发现呗,使用zookeeper、nacos等组件,从这些服务注册中间件中拉取对方的服务实例,进行http或Rpc调用,处理后续业务,不过这些都是同步调用,即调用接口以后,理论上会得到调用的结果。


但是有些场景不需要实时知道结果,况且调用链路较长,浪费时间, 譬如淘宝下单,支付成功、给用户发货,发给用户优惠券等链路,其中发货这步操作,就没必要实时知道是否发货到用户手中的结果,可以考虑异步操作,提高接口响应时间。


订单模块收到支付模块的支付成功信息,发出一个消息,告诉下游系统,这个人给这笔单子付款成功了,然后可以去干其他事情,下游模块譬如物流模块接收到这个消息,按照对应的业务处理就可以了。使用消息队列实现(Rabbitmq, Rockermq,Kafka ,Redis 中的 list )

总结


本篇文章主要讲述了,后端架构中一些常见的技术名词,以及后端架构的历史演变,建议大家边读边理解,并结合自己的项目去思考你测试的项目目前是什么架构。


下篇文章会讲述,目前主流的后端架构情况,着重介绍微服务架构、serverless无服务架构和容器化技术的发展,敬请期待。


加我微信lvceshikaifa,免费面试辅导、学习资料、简历模板获取、加入学习群。

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表