本文最后更新于199 天前,其中的信息可能已经过时,如有错误请发送邮件到[email protected]
什么是云原生
我个人认为云原生就是指使用容器化、持续交付等技术来保证应用的可用性、拓展性和弹性。这个题毕竟面的是JAVA,这里还是要结合JAVA体系,Springcloud上云应该要保证的是如下
- 应用容器化,使用Docker或者K8S来部署。
- 服务注册发现,要保证有注册中心比如nacos、eureka这些,确保服务能够正常通讯。
- 配置管理,需要通过springcloud config或者nacos等实现配置的集中管理。
- 负载均衡 :在云环境中,负载均衡是关键。Spring Cloud提供了Ribbon等工具,以实现高效的流量分发。
- 监控与日志,云平台需要通过使用Spring Boot Actuator或者Prometheus等工具进行监控,结合云平台的日志服务,确保应用的健康状态和性能。
- 服务的降级熔断:必须有服务之间的调用必须要有对应的熔断和降级方案,否则严重时会导致服务雪崩。
- 弹性与容错 :云原生应用需要具备弹性,能够在故障发生时自动恢复。
- 持续集成与持续部署(CI/CD) :使用Jenkins、GitLab CI等工具进行持续集成和持续部署,来保证自动化将代码进行部署。
说一说完整的上云步骤
这个比较复杂。我只能说一个大概的过程
- 首先我们的代码提交到生产环境中。
- 手动或者自动触发Jenkins、GitLab CI等工具的流水线作业,将我们的应用编译、打包、构建成docker镜像、上传到私服(可能会有权限验证等操作),通知K8S进行重新的拉取最新镜像,重新启动POD。
分布式锁
为什么需要分布式锁
资源互斥访问,保证数据的一致性
在分布式环境中,多个节点可能同时访问和修改共享资源,如数据库记录、文件、缓存等。如果没有适当的同步机制,可能会导致数据不一致、资源冲突或竞态条件(Race Condition)。分布式锁通过确保同一时间只有一个节点能够访问和修改共享资源,从而避免了这些问题。
- 基于数据库的分布式锁 :
- 使用数据库的唯一索引或行级锁来实现分布式锁。例如,通过插入一条唯一记录来获取锁,删除记录来释放锁。
- 优点:实现简单,依赖现有的数据库系统。
- 缺点:性能受限于数据库的性能,可能存在单点故障。
- 基于缓存的分布式锁 :
- 使用分布式缓存系统(如Redis、Memcached)来实现分布式锁。例如,通过设置一个键值对来获取锁,删除键值对来释放锁。
- 优点:性能较高,支持分布式环境。
- 缺点:需要依赖缓存系统,可能存在缓存一致性问题。
- 基于ZooKeeper的分布式锁 :
- 使用ZooKeeper的临时顺序节点来实现分布式锁。通过创建临时顺序节点来获取锁,删除节点来释放锁。
- 优点:高可用性,支持分布式环境,避免死锁。
- 缺点:实现相对复杂,依赖ZooKeeper集群。
SpringCloud的熔断和降级
熔断和降级我认为是一个包含关系,微服务之间调用一般都有重试机制,但是如果出现了错误那么就会一直重试调用直到成功然而如果被调用服务本身出现了问题如宕机或者程序错误,那么就可能会导致调用服务花费很多资源来处理调用逻辑,导致正常业务受影响,久而久之会导致连锁反应,集群的服务都有可能出现问题,形成雪崩效应。另一种情况是超时,这样同样也会造成这个结果,大量的请求堆积导致正常业务的受阻,直到调用服务的资源完全耗尽形成雪崩。
这样就需要引用到降级功能,当被调用服务出现错误或者超时的时候,定义一个fallback方法,来展示自定义的返回结果。当降级触发到一个阈值后,直接熔断,当有请求调用被调用者,直接返回fallback方法,不再去调用。
比较常见的降级熔断框架有Hystrix、Resilience4j,Resilience4j目前是最新版的springcloud采用的技术,但是目前还是hystrix用的多,我这里提供一下代码示例
# 详细的hystrix可以看https://www.cnblogs.com/throwable/p/11961016.html
hystrix:
# 启用请求属性传播功能,让 Hystrix 命令在执行时可以访问当前请求的上下文信息
propagate:
request-attribute:
enabled: true # 开启请求属性传播
# Hystrix 命令的默认配置
command:
# 全局配置
default:
# 执行超时相关的配置
execution:
timeout:
enabled: true # 开启执行超时功能,如果命令执行时间超过设定的超时时间,Hystrix 会中断命令的执行
# 隔离策略相关的配置
isolation:
strategy: THREAD # 使用线程隔离策略,Hystrix 命令会在独立的线程中执行,避免对主线程的影响
# 线程隔离策略的详细配置
thread:
timeoutInMilliseconds: 1000 # 设置命令执行的超时时间为 1000 毫秒(即 1 秒)
interruptOnTimeout: true # 当命令执行超时时,中断命令的执行
interruptOnCancel: false # 当命令被取消时,不中断命令的执行
# 断路器相关的配置
circuitBreaker:
enabled: true # 开启断路器功能,当请求失败率达到一定阈值时,断路器会打开,阻止后续请求
requestVolumeThreshold: 20 # 触发断路器的最小请求数,即在统计时间窗口内,至少有 20 个请求才会触发断路器
sleepWindowInMilliseconds: 5000 # 断路器打开后,尝试恢复的时间窗口,即 5000 毫秒(5 秒)后,断路器会尝试关闭
errorThresholdPercentage: 50 # 错误百分比阈值,当请求失败率达到 50% 时,断路器会打开
## 下面是Resilience4j默认的配置,如果想要进行更细致的配置,看这个https://docs.spring.io/spring-cloud-circuitbreaker/docs/3.0.4/reference/html/#default-configuration
resilience4j.circuitbreaker:
configs:
default:
registerHealthIndicator: true #注册一个健康指示器,以便可以通过 Actuator 的健康端点监控熔断器的状态
failureRateThreshold: 50 #设置50%的调用失败时打开断路器,超过失败请求百分⽐CircuitBreaker变为OPEN状态。
slidingWindowType: TIME_BASED # 计数型(COUNT_BASED):基于请求数量的滑动窗口,窗口的滑动是基于请求的数量。每当一个请求到达时,窗口会滑动并记录请求 ##时间型(TIME_BASED):基于时间的滑动窗口,窗口的滑动是基于时间的。例如,窗口每隔一分钟滑动一次,并统计在该时间段内的请求数量。
slidingWindowSize: 10 #滑动窗口的大小,配置TIME_BASED表示10秒,配置COUNT_BASED表示10个请求
minimumNumberOfCalls: 5 #断路器计算失败率或慢调用率之前所需的最小样本(每个滑动窗口周期)。如果minimumNumberOfCalls为10,则必须最少记录10个样本,然后才能计算失败率。如果只记录了9次调用,即使所有9次调用都失败,断路器也不会开启。
automaticTransitionFromOpenToHalfOpenEnabled: true #是否启用自动从开启状态过渡到半开状态,默认值为true。如果启用,CircuitBreaker将自动从开启状态过渡到半开状态,并允许一些请求通过以测试服务是否恢复正常
waitDurationInOpenState: 20s #从OPEN到HALF_OPEN状态需要等待的时间
permittedNumberOfCallsInHalfOpenState: 3 #半开状态允许的最大请求数,默认值为10。在半开状态下,CircuitBreaker将允许最多permittedNumberOfCallsInHalfOpenState个请求通过,如果这些请求调用的失败率等于或高于50%,CircuitBreaker将重新进入开启状态。
eventConsumerBufferSize: 10 #事件消费者的缓冲区大小,表示事件消费者最多可以缓存 10 个事件。
recordExceptions: #记录哪些异常为失败
- org.springframework.web.client.HttpServerErrorException
- java.io.IOException
- feign.FeignException
- java.util.concurrent.TimeoutException
resilience4j.timelimiter:
configs:
default:
timeoutDuration: 5s
cancelRunningFuture: true


