什么是服务网格?回答重点服务网格是一个专门用于处理服务间通信的基础设施层,它通过部署在每个服务旁边的Sidecar 代理,拦截服务间的网络流量,实现诸如流量管理、故障恢复、服务发现等功能。常见的服务网格解决方案包括 Istio、Linkerd 等。
它的核心就是通过 Sidecar 模式,将复杂的网络通信逻辑从微服务中分离出来,应用开发者只需关注业务逻辑,无需处理服务间的通信管理。这种方式能...
Sentinel 是怎么实现限流的?回答重点首先需要定义具体需要限流的资源,然后指定一定的规则(基于QPS(每秒查询数)、线程数等维度),限制资源的访问频次。
然后根据一定的限流算法(固定窗口、滑动窗口、令牌桶和漏桶),对指定的资源进行访问的流量控制。
具体流程如下:
当一个请求进入系统时,Sentinel 会首先对请求进行统计(如当前的 QPS、并发数)
接着 Sentinel 检查配置...
什么是服务降级?回答重点服务降级是一种在分布式系统和微服务架构中常用的容错机制,用于在系统压力过大或部分服务出现故障时,暂时减少或关闭某些不必要的功能,从而确保核心功能的正常运行,避免系统崩溃。通过降级,可以提高系统的容错性和可用性。
扩展知识服务降级的触发场景服务调用超时或失败:
当某个服务的调用时间超过了设定的阈值,或者服务多次调用失败时,可以触发降级机制,返回预设的降级响应,避免长时...
什么是微服务网关?为什么需要服务网关?回答重点微服务网关是一个用于代理客户端请求并将其分发到后端微服务的服务器。它接收来自不同客户端的请求,根据配置的路由规则将请求转发到相应的服务,并可以对请求进行验证、转换、聚合等操作。
其可以实现服务调用入口与出口的统一管理,从而简化服务的调用和管理。
使用微服务网关主要有以下几个方面的好处:
1)提高性能:通过服务网关,由于其可以通过缓存一些静态资源的...
什么是灰度发布、金丝雀部署以及蓝绿部署?回答重点灰度发布、金丝雀部署和蓝绿部署是三种常见的软件发布策略,它们用于在系统升级时降低风险,确保在新版本上线过程中服务的稳定性和可控性。
灰度发布灰度发布是一种渐进式的发布方式,它通过将新版本逐步推送给部分用户进行试用,逐步扩大使用范围,直到新版本完全替换旧版本。其目的是通过小范围的用户测试,验证新版本的稳定性,降低发布新版本的风险。
实现方式:通...
让你设计一个分布式 ID 发号器,怎么设计?一般在分库分表场景,就会有分布式 ID 的需求,因为需要有一个唯一标识来标记一个订单或者其他类似的数据等。
全局唯一 ID 有很多种实现,例如 UUID ,优势就是本地生成,很简单。但它是无序的,如果需要将唯一 ID 作为主键,则 UUID 不合适,首先是太长了,其次无序插入会导致数据页频繁分裂,性能不好。
在回答这个面试题的时候可以先提下 UUI...
什么是限流?限流算法有哪些?怎么实现的?限流是什么?首先来解释下什么是限流?
在日常生活中限流很常见,例如去有些景区玩,每天售卖的门票数是有限的,例如 2000 张,即每天最多只有 2000 个人能进去游玩。
那在我们工程上限流是什么呢?限制的是 「流」,在不同场景下「流」的定义不同,可以是每秒请求数、每秒事务处理数、网络流量等等。
而通常我们说的限流指代的是 限制到达系统的并发请求数,使得...
让你设计一个文件上传系统,怎么设计?这种题目都是开放性的,面试过程中也不奢望聊出所有的设计细节,仅仅需要抛出一些大致的设计需求与要点,然后简单的方案实现思路即可。
关于文件上传系统有几个最主要的核心点需要解决:
1)如何支持超大文件上传2)避免重复文件存储,节省空间3)限流问题
大文件上传假设有个 10 G 的文件需要上传,正常情况下是将文件转成流传到后端,如果不做任何处理,前端一直传,后端...
即时通讯项目中怎么实现历史消息的下拉分页加载?业务场景一般在即时通讯项目(比如聊天室)中,我们会采用下拉分页的方式让用户加载历史消息记录。
区别于标准分页每次只展示当前页面的数据,下拉分页加载是 增量加载 的模式,每次下拉时会请求加载一小部分新数据,并放到已加载的数据列表中,从而形成无限滚动的效果,确保用户体验流畅。
比如用户有 10 条消息记录,以 5 条为单位进行分页,刚进入房间时只会加...
让你设计一个消息队列,怎么设计?设计类题目要先从大局上讲出需要设计的东西的重点,然后再等待面试官的继续提问,深挖。
回答:
首先我们需要明确地提出消息中间件的几个重要角色,分别是生产者、消费者、Broker、注册中心。
简述下消息中间件数据流转过程,无非就是生产者生成消息,发送至 Broker,Broker 可以暂缓消息,然后消费者再从 Broker 获取消息,用于消费。
而注册中心用于服务...
让你设计一个线程池,怎么设计?这种设计类问题还是一样,先说下理解,表明你是知道这个东西的用处和原理的,然后开始 阐述。
基本上就是按照现有的设计来说,再添加一些个人见解。
线程池讲白了就是存储线程的一个容器,池内保存之前建立过的线程来重复执行任务,减少创建和销毁线程的开销,提高任务的响应速度,并便于线程的管理。
我个人觉得如果要设计一个线程池的话得考虑池内工作线程的管理、任务编排执行、线程池...
让你设计一个 HashMap ,怎么设计?这个问题我觉得可以从 HashMap 的一些关键点入手,例如 hash函数、如何处理冲突、如何扩容。
可以先说下你对 HashMap 的理解。
比如:HashMap 无非就是一个存储 <key,value> 格式的集合,用于通过 key 就能快速查找到 value。
基本原理就是将 key 经过 hash 函数进行散列得到散列值,然后通过...
让你实现一个订单超时取消功能,怎么设计?一般会通过定时任务或者消息队列的延迟消息来实现订单超时取消功能。
定时任务定时任务的逻辑就是扫描已创建未支付的订单,判断订单的创建时间与当前时间的差值,如果已经超过了预设的超时时间,比如 10 分钟,那么就将订单状态更新为已取消。
比如可以每 1 分钟扫描一次表,直接根据当前时间和超时时间得到筛选的时间,比如当前是 14:00,那么 13:50 分之前...
让你实现一个分布式单例对象,如何实现?所谓的单例一般指的是一个进程中一个类对应只有一个实例对象,也就是进程唯一。
而分布式,不过是一个机器部署多个服务,还是多个机器部署,本质上就是多进程,所以所谓的分布式单例指的是这个实例对应需要在多进程中保持唯一。
按照这个思路,我们仅需控制同一时刻,只会有一个进程使用这个单例对象即可,而分布式场景下的分布式锁就很容易实现这个功能。
多个进程竞争分布式锁,...
商家想要知道自己店铺卖的最好的 top 50 商品,如何实现这个功能?根据问题推断这个排行榜是一个动态的排行榜,店铺内商品一直在售卖,因此排行榜也会一直在变,所以如果利用数据库来排行计算效率会非常低,总不能每卖一单就利用数据库排序计算得到排行榜吧?
所以排除数据库这个方案。
应对数据库效率差的情况,我们常用的替代方案就是缓存,而 Redis 内有个 zset 可以实现排行榜的功能。
每个商家...
如果让你统计每个接口每分钟调用次数怎么统计?最简单的可以使用 ConcurrentHashMap + AtomicInteger + 定时任务实现内存中的统计。
ConcurrentHashMap 的 key 为方法的名称、value 为 AtomicInteger 类型,记录调用次数,可以通过 aop 切面实现每个方法调用都记录到 ConcurrentHashMap 中,然后利用定时任务每...
朋友圈点赞功能如何实现,简单说说?首先我们要理清朋友圈点赞具体需要涉及哪几个功能点:
1)存储点赞信息
需要存储哪些用户点赞了这条朋友圈,具体需要存储用户ID、点赞时间即可。
2)取消点赞
需要快速找到这名用户,将其移除点赞列表。
3)获取点赞列表
朋友圈需要展示点赞的用户头像列表信息.
核心就是这么三点,其实就是增删查,那用什么来实现比较合适呢?
实现快速存储和删除,Set 就挺合适,而且...
HashMap 是不是线程安全的?如果让你来实现一个线程安全的 HashMap 你要怎么设计?如果不用加锁你要怎么设计?回答重点HashMap 是 非线程安全 的。因为 HashMap 的内部实现并没有加锁,多个线程同时访问和修改时可能会引发数据竞争,导致数据不一致或陷入死循环等问题。
如何实现一个线程安全的 HashMap要实现一个线程安全的 HashMap,有多种设计方案,下面是几种常见...
Go 语言中如何访问私有成员?重点回答在 Go 语言中,以小写字母开头的标识符是私有成员,私有成员(字段、方法、函数等)遵循语言的可见性规则,仅在定义它的包内可见,包外无法访问这些私有成员。如果想要访问私有成员,主要包括以下三种方式:
在同一个包内,可以直接访问小写字母开头的私有成员。
在其他包中,无法直接访问私有成员,但可以通过公开的接口来间接访问私有成员。
使用反射来绕过 Go 语言的...
Go 语言的接口是怎么实现的?回答重点在 Go 语言中,接口(interface)是一种动态类型,允许定义对象的行为,而不需要指定具体的实现。
它本质上是一个动态类型和动态值的组合:
动态类型:接口持有的具体数据的类型。
动态值:接口持有的具体数据的值或引用。
接口通过这两部分,实现对不同类型的统一操作。
Go 采用鸭子类型的设计哲学,不需要显式声明实现关系。只要一个类型的方法集满足接口...
Go 语言使用断言时会发生拷贝吗?回答重点在 Go 语言中,类型断言是否发生拷贝取决于接口内部持有的数据类型:
值类型:当接口持有的是值类型(例如 int、float、struct 等),进行类型断言时会发生拷贝,因为接口存储的是这个值的副本,断言后得到的是该值的拷贝。
引用类型:当接口持有的是引用类型(例如指针、切片、映射、通道等),进行类型断言时不会发生拷贝,因为接口存储的是一个引用,...
Go 语言中通过指针变量 p 访问其成员变量 title,有哪几种方式?回答重点在 Go 语言中,通过指针变量 p 访问其成员变量 title 主要有以下两种方式:
1)使用 (*p).title 访问成员变量。
2)由于 Go 提供了指针的简写支持,还可以直接使用 p.title 来访问成员变量。
这两种方式其实是等价的,Go 编译器会帮你处理其中的细节。
有 4 种情况可以使用简洁支持:...
Go 语言中怎么实现闭包?闭包的主要应用场景是什么?回答重点在 Go 语言中,闭包(Closure)是一个函数值,它可以引用其外部作用域中的变量。在 Go 中实现闭包的方法非常简单,我们可以通过在一个函数内部定义另一个函数,并让其访问外部函数的变量来实现。
即函数可以访问被引用的变量并对其赋值,函数被“绑定”到变量上。
下面是一个简单的 Go 语言闭包示例:
12345678910111...
Go 语言中触发异常的场景有哪些?重点回答在 Go 语言中,使用 error 类型来处理错误,并通过 panic 和 recover 来处理程序的异常情况。以下是一些可能触发 panic(即异常)的场景:
数组或切片越界
空指针解引用
调用 panic 函数
非法类型断言
数学错误
内存越界或非法操作
运行时错误
使用不安全的库或代码
在上述1、2、4和5是在写代码中最常遇见的异常场景。...
不分配内存的指针类型能在 Go 语言中使用吗?回答重点在 Go 语言中,不分配内存的指针类型可以使用,但是只能用该指针本身,不可以用*去解引用出具体的值,会导致 panic 。这是因为 Go 允许声明指针变量,但如果不分配内存(没有指向有效的地址),该指针会是 nil。访问 nil 指针会导致运行时错误。
简单的说,Go 中声明一个指针变量是非常直接的,你可以使用 *Type 来声明一个指针...
Go 语言中 defer 的变量快照在什么情况下会失效?重点回答在 Go 语言中,defer 的变量快照是指在 defer 语句定义时所捕获的变量的状态。但有些情况下,defer 语句中的变量快照可能会失效,导致不如预期那样行为,如下:
1)匿名函数闭包:当 defer 语句中使用的匿名函数捕获了外部变量时。如果变量的值在 defer 语句定义后发生变化,defer 执行时会使用变化后的值。...
Go 语言中 init() 函数在什么时候执行?回答重点init() 函数在 Go 程序执行之前自动调用,会在 main() 函数执行之前。
它用于初始化包级别的变量,用来设置初始状态或者执行一次性初始化操作(它不能有参数,也不能返回值)。每个包中的 init() 函数在该包的其他代码执行之前运行,每个包可以有多个 init() 函数。
执行顺序:
包的初始化顺序:如果一个包被多个包依赖,...
Go 语言中的局部变量是分配在栈上还是堆上?回答重点Go 语言中的局部变量既可能分配在栈上,也可能分配在堆上
如果变量的生命周期局限于函数作用域,并且不会逃逸到函数外,则分配在栈上。
如果局部变量的生命周期超出函数作用域(如通过指针返回给外部使用),编译器会将变量分配在堆上,确保变量在作用域外仍然有效,这种机制称为“逃逸分析”。
扩展知识栈和堆的区别栈分配:
栈是线程私有的,分配和释放内存...
GO语言中非接口的任意类型T都能调用*T的方法么?反过来呢?回答重点都可以的。在Go语言中,对于非接口的任意类型T,确实可以调用 * T(指向T的指针)的方法。这是因为当你尝试在一个T类型的值上调用一个 * T 方法时,Go编译器会隐式地获取该值的地址,然后调用相应的方法。这种行为被称为指针接收者的方法调用的自动解引用。
示例代码1234567891011121314151617181920...
Go 语言切片的容量是如何增长的?回答重点在 Go 语言中,切片的容量是一种动态增长的机制。当切片的长度达到或超过容量时,Go 语言会自动扩展其底层数组的容量,一般由append触发。切片容量增长(growslice)的具体规则在不同版本的规则不同。
对于 go1.18 之前来说:
如果期望容量大于当前容量的两倍就会使用期望容量;
如果当前切片的长度小于 1024 的话, growslic...