写点什么

你不知道这份超详细 JVM 内存结构,京东校招 Java 面试题

用户头像
极客开源
关注
发布于: 刚刚

原理讲解前,先看一个最经典的业务场景,如开发一个电商网站,要实现支付订单的功能,流程如下:


  1. 创建一个订单之后,如果用户立刻支付了这个订单,我们需要将订单状态更新为“已支付”

  2. 扣减相应的商品库存

  3. 通知仓储中心,进行发货

  4. 给用户的这次购物增加相应的积分



如上,微服务的应用场景和核心竞争力:


  • 降低耦合:每一个微服务专注于单一功能,并通过定义良好的接口清晰表述服务边界。由于体积小、复杂度低,每个微服务可由一个小规模开发团队完全掌控,易于保持高可维护性和开发效率。

  • 独立部署:由于微服务具备独立的运行进程,所以每个微服务也可以独立部署。当某个微服务发生变更时无需编译、部署整个应用。由微服务组成的应用相当于具备一系列可并行的发布流程,使得发布更加高效,同时降低对生产环境所造成的风险,最终缩短应用交付周期。

  • 选型灵活:微服务架构下,技术选型是去中心化的。每个团队可以根据自身服务的需求和行业发展的现状,自由选择最适合的技术栈。由于每个微服务相对简单,故需要对技术栈进行升级时所面临的风险就较低,甚至完全重构一个微服务也是可行的。

  • 容错机制:当某一组建发生故障时,在单一进程的传统架构下,故障很有可能在进程内扩散,形成应用全局性的不可用。在微服务架构下,故障会被隔离在单个服务中。若设计良好,其他服务可通过重试、平稳退化等机制实现应用层面的容错。

  • 灵活扩展:单块架构应用也可以实现横向扩展,就是将整个应用完整的复制到不同的节点。当应用的不同组件在扩展需求上存在差异时,微服务架构便体现出其灵活性,因为每个服务可以根据实际需求独立进行扩展。



Dubbo 对标 Spring Cloud 微服务


  • 背景分析:Dubbo,是阿里巴巴服务化治理的核心框架,并被广泛应用于中国各互联网公司;Spring Cloud 是知名的 Spring 家族的产品。阿里巴巴是一个商业公司,虽然也开源了很多的顶级的项目,但从整体战略上来讲,仍然是服务于自身的业务为主。Spring 专注于企业级开源框架的研发,不论是在中国还是在世界上使用都非常广泛,开发出通用、开源、稳健的开源框架就是他们的主业。

  • 活跃度对比:Dubbo 是一个非常优秀的服务治理框架,并且在服务治理、灰度发布、流量分发这方面做的比 Spring Cloud 还好,除过当当网在基础上增加了 rest 支持外,已有两年多的时间几乎都没有任何更新了。在使用过程中出现问题,提交到 GitHub 的 Issue 也少有回复。相反 Spring Cloud 自从发展到现在,仍然在不断的高速发展,从 GitHub 上提交代码的频度和发布版本的时间间隔就可以看出,现在 Spring Cloud 即将发布 2.0 版本,到了后期会更加完善和稳定。

  • 平台架构:Dubbo 框架只是专注于服务之间的治理,如果我们需要使用配置中心、分布式跟踪这些内容都需要自己去集成,这样无形中使用 Dubbo 的难度就会增加。Spring Cloud 几乎考虑了服务治理的方方面面,更有 Spring Boot 这个大将的支持,开发起来非常的便利和简单。

  • 技术前景:Dubbo 在各中小公司也从中受益不少。经过了这么多年的发展,互联网行业也是涌现了更多先进的技术和理念,Dubbo 有点可惜。Spring 推出 Spring Boot/Cloud 也是因为自身的很多原因。Spring 最初推崇的轻量级框架,随着不断的发展也越来越庞大,随着集成项目越来越多,配置文件也越来越混乱,慢慢的背离最初的理念。随着这么多年的发展,微服务、分布式链路跟踪等更多新的技术理念的出现,Spring 急需一款框架来改善以前的开发模式,因此才会出现 Spring Boot/Cloud 项目,我们现在访问 Spring 官网,会发现 Spring Boot 和 Spring Cloud 已经放到首页最重点突出的三个项目中的前两个,可见 Spring 对这两个框架的重视程度。Dubbo 实现如下:


Spring Cloud 实现思路


Eureka

原理:主管服务注册与发现,也就是微服务的名称注册到 Eureka,就可以通过 Eureka 找到微服务,而不需要修改服务调用的配置文件。


分析:Spring Cloud 封装了 Netflix 公司开发的 Eureka 模块来实现服务的注册与发现,采用的 c-s 的设计架构,Eureka Server 作为服务注册功能的服务器,他是服务注册中心。而系统的其他微服务,使用 Eureka 的客户端连接到 Eureka Server 并维持心跳。这样系统的维护人员可以通过 Eureka Server 来监控系统中的各个微服务是否正常运行。Spring Cloud 的一些其他模块(比如 Zuul)就可以通过 Eureka Server 来发现系统其他的微服务,并执行相关逻辑。


Eureka Server


Eureka Server 提供服务注册服务,各个节点启动后,会在 Eureka Server 中进行注册, 这样 Eureka Server 中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。


Eureka Client


Eureka Client 是一个 Java 客户端, 用于简化 Eureka Server 的交互,客户端同时也具备一个内置的、 使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向 Eureka Server 发送心跳(默认周期为 30 秒),以证明当前服务是可用状态。如果 Eureka Server 在一定的时间(默认 90 秒)未收到客户端的心跳,Eureka Server 将会从服务注册表中把这个服务节点移除。


Eureka Server 的自我保护机制


如果在 15 分钟内超过 85%的节点都没有正常的心跳,那么 Eureka 就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况:


  • Eureka 不再从注册列表中移除因为长时间没收到心跳而应该过期的服务

  • Eureka 仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上(即保证当前节点依然可用)

  • 当网络稳定时,当前实例新的注册信息会被同步到其它节点中


因此, Eureka 可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像 ZooKeeper 那样使整个注册服务瘫痪。


Eureka 和 ZooKeeper


著名的 CAP 理论指出,一个分布式系统不可能同时满足 C(一致性)、A(可用性)和 P(分区容错性)。由于分区容错性在是分布式系统中必须要保证的,因此我们只能在 A 和 C 之间进行权衡。


ZooKeeper 保证 CP


当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接受服务直接 down 掉不可用。也就是说,服务注册功能对可用性的要求要高于一致性。但是 ZooKeeper 会出现这样一种情况,当 Master 节点因为网络故障与其他节点失去联系时,剩余节点会重新进行 leader 选举。问题在于,选举 leader 的时间太长,30 ~ 120s,且选举期间整个 ZooKeeper 集群都是不可用的,这就导致在选举期间注册服务瘫痪。在云部署的环境下,因网络问题使得 ZooKeeper 集群失去 Master 节点是较大概率会发生的事,虽然服务能够最终恢复,但是漫长的选举时间导致的注册长期不可用是不能容忍的。


Eureka 保证 AP


Eurek 在设计时就优先保证可用性。Eureka 各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而 Eureka 的客户端在向某个 Eureka 注册或时如果发现连接失败,则会自动切换至其它节点,只要有一台 Eureka 还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)。


除此之外,Eureka 还有一种自我保护机制,见上。


总结


Eureka 可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像 ZooKeeper 那样使整个注册服务瘫痪。


Eureka 作为单纯的服务注册中心来说要比 ZooKeeper 更加“专业”,因为注册服务更重要的是可用性,我们可以接受短期内达不到一致性的状况。


Ribbon 和 Feign

在微服务架构中,业务都会被拆分成一个独立的服务,服务与服务的通讯是基于 HTTP RESTful 的。Spring Cloud 有两种服务调用方式,一种是 Ribbon+RestTemplate,另一种是 Feign。


概念


基于 Netflix Ribbon 用过轮询策略实现的一套客户端负载均衡的工具。


客户端负载均衡:负载均衡 Zuul 网关将一个请求发送给某一个服务的应用的时候,如果一个服务启动了多个实例,就会通过 Ribbon 来通过一定的负载均衡策略来发送给某一一个服务实例。Spring Cloud 中的 Ribbon,客户端会有一个服务器地址列表,在发送请求前通过负载均衡算法(如简单轮询,随机连接等)选择一个服务器,然后进行访问。


负载均衡


  • 负载均衡:用于将工作负载分布到多个服务器来提高网站、应用、数据库或其他服务的性能和可靠性。

  • 使用负载均衡带来的好处很明显:当集群里的 1 台或者多台服务器 down 的时候,剩余的没有 down 的服务器可以保证服务的继续使用;将访问压力分配到各个服务器,不会由于某一高峰时刻导致系统 cpu 急剧上升。

  • 负载均衡有好几种实现策略,常见的有:随机(Random),轮询(RoundRobin),一致性哈希(ConsistentHash),哈希(Hash),加权(Weighted)

  • Ribbon 的默认策略是轮询


RestTemplate


传统情况下在 Java 代码里访问 RESTful 服务,一般使用 Apache 的 HttpClient,不过此种方法使用起来太过繁琐。Spring 提供了一种简单便捷的模板类来进行操作,这就是 RestTemplate。


Feign 是一个声明式 http 客户端。使用 Feign 能让编写 http 客户端更加简单,它的使用方法是定义一个接口,然后在上面添加注解,避免了调用目标微服务时,需要不断的解析/封装 json 数据的繁琐。Spring Cloud 中 Feign 默认集成了 Ribbon,并和 Eureka 结合,默认实现了负载均衡的效果。


Ribbon 和 Feign 的区别


Feign 目标使编写 Java Http 客户端变得更容易


在使用 Ribbon+ RestTemplate 时,Ribbon 需要自己构建 http 请求,模拟 http 请求然后使用 RestTemplate 发送给其他服务,步骤相当繁琐。利用 RestTemplate 对 http 请求的封装处理,形成了-套模版化的调用方法。但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。所以,Feign 在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口的定义。


在 Feign 的实现下,我们只需创建一个接口并使用注解的方式来配置它(以前是 Dao 接口上面标注 Mapper 注解,现在是一个微服务接口上面标注一个 Feign 注解即可), 即可完成对服务提供方的接口绑定,简化了使用 Spring Cloud Ribbon 时,自动封装服务调用客户端的开发量。


Feign 集成了 Ribbon


Ribbon 通过轮询实现了客户端的负载均衡,而与 Ribbon 不同的是,Feign 是一个声明式的 Web 服务客户端, 使得编写 Web 服务客户端变得非常容易,只需要创建一个接口, 然后在上面添加注解,像调用本地方法一样调用它就可以,而感觉不到是调用远程方法。SpringCloud 中 Feign 默认集成了 Ribbon,并和 Eureka 结合,默认实现了负载均衡的效果。


Ribbon 和 Nginx 的区别


服务器端负载均衡 Nginx


Nginx 是客户端所有请求统一交给 Nginx,由 Nginx 进行实现负载均衡请求转发,属于服务器端负载均衡。既请求由 Nginx 服务器端进行转发。客户端负载均衡 Ribbon,Ribbon 是从 Eureka 注册中心服务器端上获取服务注册信息列表,缓存到本地,然后在本地实现轮询负载均衡策略。既在客户端实现负载均衡。


应用场景的区别


Nginx 适合于服务器端实现负载均衡,比如:Tomcat,Ribbon 适合与在微服务中 RPC 远程调用实现本地服务负载均衡,比如:Dubbo、Spring Cloud 中都是采用本地负载均衡。


Zuul

应用场景


假如当前有十几个微服务服务,订单,商品,用户等等,显然是客户端不需要和每个服务逐一打交道,这就需要有一个统一入口,它就是服务网关。API 网关所有的客户端请求通过这个网关访问后台的服务。他可以使用一定的路由配置来判断某一个 URL 由哪个服务来处理。并从 Eureka 获取注册的服务来转发请求。


核心功能


Zuul 包含了对请求的路由和过滤两个最主要的功能,是各种服务的统一入口,同时还会用来提供监控、授权、安全、调度等等。


路由功能:负责将外部请求转发到具体的微服务实例上,是实现外部访问统一入口的基础。


过滤器功能:则负责对请求的处理过程进行干预,是实现请求校验、服务聚合等功能的基础。


Zuul 和 Eureka 进行整合:将 Zuul 自身注册为 Eureka 服务治理下的应用,同时从 Eureka 中获得其他微服务的消息,也即以后的访问微服务都是通过 Zuul 跳转后获得。


注意:Zuul 服务最终还是会注册进 Eureka,提供代理+路由+过滤三大功能。


核心原理


Zuul 的核心是一系列的 filters,其作用可以类比 Servlet 框架的 Filter,或者 AOP。


过滤器之间没有直接进行通信,而是通过 Request Context(上下文)进行数据传递。


Zuul 的过滤器是由 Groovy 写成,这些过滤器文件被放在 Zuul Server 上的特定目录下面,Zuul 会定期轮询这些目录,修改过的过滤器会动态的加载到 Zuul Server 中以便过滤请求使用。


Zuul 负载均衡:Zuul 拦截对应的 API 前缀请求做转发,转发到对应的 serverId 上,在 Eureka 服务上同一个 serverId 可以对应多个服务,也就是说用同一个服务节点不同的端口注册两个实例,但是 serverId 是一样 Zuul 做转发的时候会结合 eureka-server 起到负载均衡的效果。


过滤器的种类:


  • PRE(前置):这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现鉴权、限流、参数校验调整等。

  • ROUTING(路由):这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用 Apache HttpClient 或 Netfilx Ribbon 请求微服务。

  • POST(后置):这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的 HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端、日志等。

  • ERROR(错误):在其他阶段发生错误时执行该过滤器。


Zuul 和 Nginx


Zuul 虽然在性能上和 Nginx 没法比,但它也有它的优点。Zuul 提供了认证鉴权,动态路由,监控,弹性,安全,负载均衡等边缘服务,在团队规模不大的情况下,没有专门负责路由开发时,使用 Zuul 当网关是一个快速上手的好方案。


Nginx 和 Zuul 是可以配合使用的,发挥各自的优点,使用 Nginx 作为负载均衡实现高并发的请求转发,Zuul 用作网关。


Zuul 和 Ribbon 实现负载均衡


Zuul 支持 Ribbon 和 Hystrix,也能够实现客户端的负载均衡。我们的 Feign 不也是实现客户端的负载均衡和 Hystrix 的吗?既然 Zuul 已经能够实现了,那我们的 Feign 还有必要吗?


可以这样理解:


Zuul 是对外暴露的唯一接口相当于路由的是 controller 的请求,而 Ribbonhe 和 Fegin 路由了 service 的请求。


Zuul 做最外层请求的负载均衡,而 Ribbon 和 Fegin 做的是系统内部各个微服务的 service 的调用的负载均衡。

Hystrix

介绍


Hystrix 是一个用于处理分布式系统的延迟和容错的开源库,在分布式系统里,许多依赖不可避兔的会调用失败,比如超时、异常等,Hystrix 能够保证在一个依赖出问题的情况下,不会导致整体服务失败,避免级联故障,以提高分布式系统的弹性。Hystrix 的出现就是为了解决雪崩效应。


服务雪崩


多个微服务之间调用的时候,假设微服务 A 调用微服务 B 和微服务 C,微服务 B 和微服务 C 又调用其它的微服务,这就是所谓的“扇出”。如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务 A 的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的”雪崩效应”。


服务熔断


熔断机制是应对雪崩效应的一种微服务链路保护机制。


当删除链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回”错误的响应信息。当检测到该节点微服务调用响应正常后恢复调用链路。在 SpringCloud 框架里熔断机制通过 Hystrix 实现。Hystrix 会监控微服务间调用的状况,当失败的调用到一定阈值,缺省是 5 秒内 20 次调用失败就会启动熔断机制。熔断机制的注解是 @HystrixCommand。


服务降级


整体资源快不够了,忍痛将某些服务先关掉,待渡过难关,再开启回来。


Hystrix 监控和断路器


我们只需要在服务接口上添加 Hystrix 标签,就可以实现对这个接口的监控和断路器功能。


Hystrix Dashboard 监控面板,提供了一个界面,可以监控各个服务上的服务调用所消耗的时间等。


Hystrix Turbine 监控聚合


使用 Hystrix 监控,我们需要打开每一个服务实例的监控信息来查看。而 Turbine 可以帮助我们把所有的服务实例的监控信息聚合到一个地方统查看。这样就不需要挨个打开一个个的页面一个个查看。


Zuul 的安全机制


签名机制,为防止接口数据篡改和重复调用,增加接口参数校验机制,sig 签名算法为 MD5(appKey+appSecret+timestamp),appKey 是分配给客户端的 ID,appSecret 是分配给客户端的密钥,timestamp 为 unix 时间戳,请求的 URL 有效时间为 15 分钟。


Token 机制,用户在登录之后会返回一个 access_ token,客户端在访问需要登录之后才能访问的资源,需要在在 Authorization 头部使用 Bearer 模式新增 token,如 head(“Authorization”,” Bearer token”)。


Hystrix 的设计原则


  • 资源隔离(线程池隔离和信号量隔离)机制:限制调用分布式服务的资源使用,某一个调用的服务出现问题不会影响其它服务调用。

  • 限流机制:限流机制主要是提前对各个类型的请求设置最高的 QPS 阈值,若高于设置的阈值则对该请求直接返回,不再调用后续资源。

  • 熔断机制:当失败率达到阀值自动触发降级(如因网络故障、超时造成的失败率真高),熔断器触发的快速失败会进行快速恢复。

  • 降级机制:超时降级、资源不足时(线程或信号量)降级、运行异常降级等,降级后可以配合降级接口返回托底数据。

  • 缓存支持:提供了请求缓存、请求合并实现。

  • 通过近实时的统计/监控/报警功能,来提高故障发现的速度。

  • 通过近实时的属性和配置热修改功能,来提高故障处理和恢复的速度。

Config

介绍


Spring Cloud Config 是一个解决分布式系统的配置管理方案。微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统 中会出现大量的服务。由于每个服务都需要必要的配置信息才能运行,所以一套集中式的、 动态的配置管理设施是必不可少的。Spring Cloud 提供了 ConfigServer 来解决这个问题,我们每一个微服务自 己带着一个 application.yml 上百个配置文件的管理。


应用场景


  • 不方便维护,多人同时对配置文件进行修改,冲突不断,很难维护

  • 配置内容安全和权限,主要是针对线上的配置来说,一般不对开发公开,只有运维有权限所以需要将配置文件隔离,不放到项目代码里

  • 更新配置项目需要重启,每次更新配置文件都需要重启项目,很耗时。使用了配置中心后,即可实现配置实时更新 congfig Server 和 Config Client 结合 Spring Cloud Bus 实现配置自动刷新。


原理


  • 配置文件存储在远端 Git(比如 GitHub,Gitee 等仓库),config-server 从远端 Git 拉取配置文件,并保存到本地 Git。

  • 本地 Git 和 config-server 的交互是双向的,因为当远端 Git 无法访问时,会从本地 Git 获取配置文件。

  • config-client(即各个微服务),从 config-server 拉取配置文件。


角色


  • Config Server:提供配置文件的存储、以接口的形式将配置文件的内容提供出去。

  • Config Client:通过接口获取数据、并依据此数据初始化自己的应用。

总结如下


总结

互联网大厂比较喜欢的人才特点:对技术有热情,强硬的技术基础实力;主动,善于团队协作,善于总结思考。无论是哪家公司,都很重视高并发高可用技术,重视基础,所以千万别小看任何知识。面试是一个双向选择的过程,不要抱着畏惧的心态去面试,不利于自己的发挥。同时看中的应该不止薪资,还要看你是不是真的喜欢这家公司,是不是能真的得到锻炼。其实我写了这么多,只是我自己的总结,并不一定适用于所有人,相信经过一些面试,大家都会有这些感触。


**另外本人还整理收藏了 2021 年多家公司面试知识点以及各种技术点整理 **


下面有部分截图希望能对大家有所帮助。



本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

用户头像

极客开源

关注

还未添加个人签名 2021.03.18 加入

还未添加个人简介

评论

发布
暂无评论
你不知道这份超详细JVM内存结构,京东校招Java面试题