今天被问微服务,这几点,让面试官刮目相看

本文涉及的产品
云原生网关 MSE Higress,422元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
注册配置 MSE Nacos/ZooKeeper,118元/月
简介: 今天分享的是微服务的高并发情形,在微服务高并发下有几点需要考虑:微服务的划分、高并发、数据DB、中间件或缓存问题、IO性能瓶颈问题、监控问题、自动化部署问题等。

一、微服务的划分

微服务的划分:前面说过了,服务的划分,可以从水平的功能划分,也可从垂直的业务划分,粒度的大小,可以根据当前的产品需求来定位,最关键的是要做到:高内聚、低耦合。

听到高内聚、低耦合这六个字,面试官也许会觉得这小伙子不错,有一定的技术设计的基础。那么接下来,问题来了。什么是高内聚,什么是低耦合呢?所谓高内聚:就是说每个服务处于同一个网络或网域下,而且相对于外部,整个的是一个封闭的、安全的盒子,宛如一朵玫瑰花。

盒子对外的接口是不变的,盒子内部各模块之间的接口也是不变的,但是各模块内部的内容可以更改。模块只对外暴露最小限度的接口,避免强依赖关系。增删一个模块,应该只会影响有依赖关系的相关模块,无关的不应该受影响。

所谓低耦合:从小的角度来看,就是要每个Java类之间的耦合性降低,多用接口,利用Java面向对象编程思想的封装、继承、多态,隐藏实现细节。从模块之间来讲,就是要每个模块之间的关系降低,减少冗余、重复、交叉的复杂度,模块功能划分尽可能单一。

二、高并发

一个公司一旦做大了,就需要考虑兼容、扩展、压力等问题。高并发是一个常见的词语。然后如何才能保证高并发,这是一个问题。

高并发从以下几个方面来讲:

  1. 幂等性
  2. 接口代码的规范性
  3. 操作 DB 的性能
  4. 读写分离操作
  5. 服务的横向扩展
  6. 服务的健壮性(缓存、限流、熔灾)

幂等性:所谓幂等性,就是说一次和多次请求某一个资源时对于资源本身应该具有同样的结果(网络超时等问题除外)。也就是说,其任意次执行所产生的效果和返回的结果都是一样的。这种场景是一个很有效的实现高并发的情景,设想,用户充值某个会员,在并发情况下,用户由于误操作,或者由于网络、时间等问题导致重试机制的发生时,可能会触发触发多次交易的扣费,这样给用户一个很不好的体验。此时,就需要接口幂等性来解决这类问题。

幂等性解决方案有以下几种:

(1) token机制

(2) 接口逻辑实现幂等性

(3) 数据库层处理实现幂等性

token机制:数据提交时携带token,token放到redis,token有效时间,提交后台后校验token,同时删除token,生成新的token并返回。

接口的幂等性:常见的接口幂等性,是定义接口时,加上参数序列号、来源等,序列号与请求来源联合唯一索引,这样可以有效判断本次请求方与请求的序列号,防止重复的请求。

数据库处理:DB层处理有多种方式,1. 悲观锁,2. 乐观锁,3. 唯一索引、组合唯一索引,4. 分布式锁

悲观锁:所谓悲观锁,是指存在危机意识,事先(查询时)加锁处理,防止事情发生。如:

select * from xxx where id= 1 for update

乐观锁:是指存在乐观心理,只在更新时加锁,乐观锁通常用 version 版本号来控制如:

update xxx set name=#name#,version=version+1 where version=#version#

也可以通过条件限制,这里就使用了组合唯一索引来处理,如:

update xxx set name=#name#,version=version+1 where id=#id# and version=#version#

分布式锁:通过 redis、zookeeper 来设置分布式锁,当插入或更新数据时,获取分布式锁,然后做操作,之后释放锁。

接口的规范性:接口的性能如何,最终还是跟接口的实现逻辑有关,比如代码规范,逻辑实现等,尤其是业务逻辑复杂的情况下,这点需要注意的。

操作DB:对于业务的持久层,用的比较多的就是mybatis、hibernate,还有可能是JPA,无论是哪个,最终都是通过工厂类注入 bean,最后执行 SQL 来操作 DB。所以这里尤为重要的是 SQL 的写法,SQL的优化决定着操作DB的时间以及效果,如果写得不好的话,则会导致死循环,或死锁,或内存溢出。另外测试时,使用真实、规范的数据进行测试,并在测试时不要局限于相同的数据,最后就是并发压测了。

读写分离:当服务足够多,数据足够多时,有可能读与写的占比为:10:1,此时读写应该分离,这样可以有效减少因为读的频繁操作导致的写的性能下降。常见的读写分离的方法有:采用mycat中间件方式、amoeba直接实现读写分离、手动修改mysql操作类直接实现读写分离和随机实现的负载均衡,权限独立分配、mysql-proxy(还是测试版本,时间消耗有点高)。

服务的横向扩展:对于服务的请求越来越多时,此时需要对服务进行多节点部署,这样减少单机带来的服务负载压力。

服务的健壮性:服务的健壮性包括缓存、限流、熔灾。

对于缓存,大家都知道,有常见的许多中间件如:redis、kafka、RabbitMq、zookeeper。对于一些session等常用redis来缓存、共享。对于一些大一点的数据如果嫌弃加载慢,也可以采用缓存机制来解决。

什么叫限流呢?很好理解,就是限制节点的流量,限制服务的请求数。那么如何做到限流呢?常用的限流算法比如有计数器算法、令牌桶算法、漏桶算法。有几种方式:利用 springcloud 组件 zuul 来对请求进行限流,主要是通过谷歌提供的 RateLimiter 结合一些限流算法来限流比较常用。利用 redis 同样可以做限流算法的,甚至可以利用 nginx 直接作计数限流,可以对请求速率进行限制、对每个 ip 连接数量进行限制、对每个服务的连接数量进行限制。如:

#对请求速率进行限制
limit_req_zone $binary_remote_addr zone=req_one:20m rate=12r/s;
limit_conn_zone $binary_remote_addr zone=addr:10m;
#对每个ip连接数量进行限制
limit_conn_zone $server_name zone=perserver:20m;
#对每个服务的连接数量进行限制
server{
  listen 80;
  location / {
    proxy_pass http://ip:port;
    limit_req zone=req_one burst= 80 nodelay;
    limit_conn addr 20;
  }
}

其实在Springboot2.x中,推出自己的Spring-Cloud-Gateway来作网关,同时Spring-Cloud-Gateway中提供了基于Redis的实现来达到限流的目的。

对于熔灾,或者说熔断,这个在实际的业务当中是很有必要的。比如:用户在某一商城秒杀某一件物品,或在某米商城上抢购某一部手机,在准点抢购时,发现人很多,请求很多,这时,主要是需要有限流机制,同时也需要有熔灾(熔断),给用户留下一个很好的体验的感觉。当用户在点击抢购按钮后,如果当前的请求数很多,需要用户等待,这是需要给一个友好的界面让用户去等待,而不是直接给用户提示请求失败,或者报异常,这样的红色抛出是一个非常不好的事情,用户可能会骂街的,下次也不会逛了。

Spring-Cloud-Gateway作网关时,过滤器时使用 HystrixGatewayFilterFactory 来创建一个 Filter 实现基于 Route 级别的熔断功能。

三、中间件或缓存问题

随着用户的越来愈多,所有的服务压力也会指数型递增,这时候缓存是一个很好的减轻服务压力的方式。这样可以有效缓冲请求对服务的负载压力。常见的缓存可能是Redis、MQ(RabbitMQ、RocketMQ)、Kafka、ZooKeeper等。

Redis 一般主要做 session 或用户信息的缓存,实现多机中 session 的共享。也会用来作分布式锁,在分布式高并发下实现锁的功能,例如实现秒杀、抢单等功能。还会被用作一些订单信息的缓存,防止大量的订单信息被积压而导致服务器的负载很高。总之,Redis 常被用来作为一种缓冲剂使用。

ZooKeeper 也是经常会存储海量数据,例如 Hadoop 中,在使用 YARN 作资源调度时,采用 ZooKeeper 来存储海量的状态机状态以及任务的信息(包括历史信息)。

四、IO性能瓶颈问题

每个行业的业务也许不同,但是大部分行业是存在存储的,说到最直接的数据库,其他的包括电商、物流、AI算法等。电商的存储在于页面的数据与后端存储的交互;物流的存储在于物流信息、物品信息的存储;AI算法在于数据集、模型、镜像文件、训练代码等的存储。整的来说,不管是什么存储,只要跟磁盘、硬盘有关系,就会涉及到IO的问题。

对于IO,在阻塞模式下,经常有线程不够用,就算使用线程池复用线程也无济于事;阻塞I/O模式下,会有大量的线程被阻塞,一直在等待数据,这个时候的线程被挂起,只能干等,CPU利用率很低,即导致系统的吞吐量差,内存占用很高,甚至导致内存溢出。如果网络I/O堵塞或者有网络抖动或者网络故障等,线程的阻塞时间可能很长。整个系统也变的不可靠。

什么是NIO?java.nio 是指JDK 1.4 及以上版本里提供的新api(New IO) ,为所有的原始类型(boolean类型除外)提供缓存支持的数据容器,使用它可以提供非阻塞式的高伸缩性网络。NIO核心API:Channel、Buffer、Selector。

Channel:NIO的通道类似于流,但有些区别:1. 通道可以同时进行读写,而流只能读或者只能写,2. 通道可以实现异步读写数据,3. 通道可以从缓冲读数据,也可以写数据到缓冲。

缓存Buffer:缓冲区本质上是一个可以写入数据的内存块,然后可以再次读取,该对象提供了一组方法,可以更轻松地使用内存块,使用缓冲区读取和写入数据通常有这四个步骤:

  1. 写数据到缓冲区;
  2. 调用buffer.flip()方法;
  3. 从缓冲区中读取数据;
  4. 调用buffer.clear()或buffer.compat()方法

当向Buffer写入数据时,Buffer会记录下写了多少数据,一旦要读取数据,需要通过flip()方法将Buffer从 write 模式切到 read 模式,在 read 模式下可以读取之前写入到Buffer的所有数据,一旦读完了所有的数据,就需要清空缓冲区,让它可再被写入。

Selector:一个组件,可以检测多个NIO channel,看看读或者写事件是否就绪。多个Channel以事件的方式可以注册到同一个Selector,从而可以用一个线程处理多个请求。

当你调用Selector的select()或者 selectNow() 方法时它只会返回有数据读取的SelectableChannel的实例。

另外,就是利用NIO实现大文件的分片处理。

五、监控问题

随着业务规模的不断扩大,面临着服务数量不断增加、线上环境日益复杂、服务依赖错综复杂等运维痛点,服务依赖自动梳理、调用实时追踪、异常明细分析、调用链路追踪、实时容量规划、问题根因分析等基本的运维诉求及解决方案就尤其重要。

监控的目的主要包括性能监控、服务的健壮性、运维管理、问题自动分析、动态扩容等,监控的方式也有很多,比如Springcloud自己提供的Dashboard,实现服务的链路跟踪。

K8S的Dashboard,可以追踪看到每个服务pod的状态以及各项服务的系统指标。除了k8s的基本监控外(pod运行状况、占用内存、cpu)。为了对微服务项目中的各种参数线程池、TPS、QPS、RT、系统负载、thread、mem、class、tomcat、gc、等jvm指标进行监控。可以采用基于 K8S 的 promethus job 对业务的metrics指标采取收集。同时由于 promethus 支持 grafana前端UI界面。

六、自动化部署问题

随着服务的越来越多,服务的运维管理也是一个麻烦事,如果有一套自动化部署的机制,则可以一键触发自动部署所有微服务,那绝壁是很好的一件事。这块可以参考文章:微服务自动化部署CI/CD 一文,很详细的介绍了自动化部署的实战。

好了,以上所说的,也许对于面试的你会有一定作用的!

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
6月前
|
Java 关系型数据库 数据库连接
BATJ高频面试249道题:微服务+多线程+分布式+MyBatis +Spring
本文收集整理了各大厂常见面试题N道,你想要的这里都有内容涵盖:Java、MyBatis、ZooKeeper、Dubbo、Elasticsearch、Memcached、Redis、MySQL、Spring、Spring Boot、Spring Cloud、RabbitMQ、Kafka、Linux 等技术栈,希望大家都能找到适合自己的公司,开开心心的撸代码。
|
1月前
|
负载均衡 算法 Java
微服务面试篇
微服务面试篇
52 2
|
5月前
|
存储 运维 负载均衡
「微服务」这10道Consul面试题值得一看
Consul 是一个强大的分布式服务发现和配置管理工具,用于服务注册、健康检查、负载均衡、故障恢复等。它支持多数据中心和多种协议,提供服务发现、健康检查、KV 存储和事件通知功能。服务注册与健康检查由 Agent 实现,负载均衡通过 Service Mesh 实现。尽管 Consul 提供诸多优点,如多数据中心支持和高可用性,但其学习和部署成本较高,适合大型项目,对于小型或初学者可能过于复杂。在使用时需根据实际需求和资源考虑。
|
5月前
|
监控 测试技术 数据库
【面试宝藏】微服务架构详解
微服务架构将大型应用拆分成小型、独立的服务,每个服务专注特定业务功能,实现独立部署和扩展。优势包括故障隔离、技术多样性、开发灵活性。挑战包括服务发现、数据一致性及运维复杂性。RESTful用于构建Web API,微服务测试涵盖单元、集成、契约、端到端和性能测试。DDD帮助处理复杂业务逻辑,通过统一语言增强沟通。
53 2
|
6月前
|
监控 Java Nacos
Java微服务框架面试总结(全面,实时更新)
Java微服务框架面试总结(全面,实时更新)
|
6月前
|
微服务 中间件 Nacos
01.【微服务架构】服务注册与发现:AP和CP,你选哪个?-- 面试准备+基本模型
【5月更文挑战第2天】面试准备应涵盖公司所使用的注册中心类型及其优缺点,了解其集群规模、QPS和机器性能。准备故障排查及优化案例。若公司未采用微服务,可熟悉ZooKeeper、Nacos或etcd的基本特性以讨论注册中心概念。面试时,可将话题引导至服务注册与发现,如被问及特定中间件,阐述为何选择它并讨论优缺点。当涉及微服务高可用性时,可强调服务注册与发现的作用。基础模型部分,需解释服务上线和下线流程,提及注册数据和分组功能,并举例说明。最后,简述服务注册与发现的高可用挑战。
139 8
|
6月前
|
运维 网络协议 Linux
2024年最全CentOS8 Consul微服务架构安装(1)_agent(1),Linux运维开发面试
2024年最全CentOS8 Consul微服务架构安装(1)_agent(1),Linux运维开发面试
|
6月前
|
运维 监控 Java
微服务心跳监测机制讲解与实现,与面试过程中如何回答这个问题
微服务心跳监测机制讲解与实现,与面试过程中如何回答这个问题
163 0
|
6月前
|
监控 Java 微服务
微服务面试题
微服务架构是一种架构风格和架构思想,**在传统软件应用架构的基础上,**将系统业务按照功能拆分为更细的服务。**拆分的每一个服务都是一个独立的应用,这些应用对外提供公共的API,可以独立承担对外服务的职责。通过此种思想方式所开发的软件服务实体就是“微服务”,而**围绕着微服务思想构建的一系列结构,都可以称之为“微服务架构”
113 0
微服务面试题
|
Java 关系型数据库 API
Spring Cloud微服务面试题
Spring Cloud微服务面试题
290 0
下一篇
无影云桌面