Java 系统稳定性进阶之路:策略、实践与优化

news/2024/12/18 18:30:26/

前言

最近在做系统的稳定性治理,有一点心得和感悟,分享、记录和输出一下,走几步要回头看看,沉淀一下。

稳定性建设-八股文

  • H-热点(Hotkey)
  • R-限流(RateLimiter)
  • A-授权(Authorize)
  • B-隔离(BulkHead)
  • C-熔断(CircuitBreaker)(服务熔断+服务降级)

之前一个阿里师兄分享过上面的一个关键词,不过稳定性建设无时无刻不存在,本文以自己遇到且落地的案例为例,讲解一下系统的稳定性建设。

稳定性建设-充分利用机器资源

简单粗暴的说,穷则加并发,富则加机器。本文主要讨论加并发。

案例场景

在电商平台购物场景中,当出现非预期场景时最开始直接与买家或者卖家沟通的客服,比如退货不退款、假货投诉等等,客服的回答与服务直接影响用户的心智,影响用户的服务体验。因此监测客服与用户的聊天记录中是否存在违规行为就显得尤为重要。

举几个常见的场景:

  • 禁止辱骂用户
  • 禁止长时间不回复用户
  • 要求给客户推荐某商品

针对以上三个场景,其实是三个不同的算法模型去处理识别,当然生产模型有更多。

案例问题

从业务角度来说,识别一次聊天会话是否存在违规行为。
从开发角度来说,入参是一个聊天记录明细和模型集合(多租户),出参是有哪些违规行为。

伪代码如下

java">    /*** @param chatList    聊天明细* @param modelIdList 模型集合* @return*/public Object chatCheck(List<String> chatList, List<Integer> modelIdList) {for (Integer modelId : modelIdList) {List<String> deepCopyChatList = new ArrayList<>(chatList);//处理业务逻辑doChatCheck(deepCopyChatList, modelId);}return "demo";}public Object doChatCheck(List<String> chatList, Integer modelId) {//处理业务逻辑return null;}

整个接口的RT超时时间竟然是秒级,完全不符合一个中台的毫秒的要求。接口超时严重。

解决方案

穷则加并发,富则加机器。本文选择穷办法。

修改后的代码如下。当然不推荐使用parallelStream做并发哈,想偷懒写了。

java">  /*** @param chatList    聊天明细* @param modelIdList 模型集合* @return*/public Object chatCheck(List<String> chatList, List<Integer> modelIdList) {modelIdList.parallelStream() //多线程.forEach(modelId -> {List<String> deepCopyChatList = new ArrayList<>(chatList);//处理业务逻辑doChatCheck(deepCopyChatList, modelId);});return "demo";}public Object doChatCheck(List<String> chatList, Integer modelId) {//处理业务逻辑return null;}
收益

接口的RT从秒级降低为毫秒级,接口失败数量降低到单位数(反正贼夸张)。

稳定性建设-灰度能力

找人做小白鼠,跑跑看

案例场景

在开发中常常会因为下游接口要升级需要你配合改接口,以这种场景为例。直接切肯定是有问题的,肯定要做灰度。比如这一批人走新接口,剩下的还是走老接口。

解决方案

假设每一次请求都会携带用户的ID,即userId,那么我的灰度规则为userId%100<1,即圈选1/100的用户当小白鼠。

java">public class SpelUtils {/*** 根据用户ID进行取模运算的SPEL工具方法** @param spel SPEL表达式* @param userId 用户ID* @param modulo 取模的数值(除数)* @return 取模后的结果*/public static boolean grayMatchAbility(String spel,long userId, int modulo) {// 创建SPEL表达式解析器ExpressionParser parser = new SpelExpressionParser();// 构建SPEL表达式,这里表示对传入的变量进行取模操作Expression expression = parser.parseExpression("(#userId % #modulo) < 1");// 创建求值上下文,用于设置表达式中的变量值EvaluationContext context = new StandardEvaluationContext();context.setVariable("userId", userId);context.setVariable("modulo", modulo);// 对表达式求值并返回取模结果(这里强制转换为int类型,根据实际情况可能需要调整)return (boolean) expression.getValue(context);}public static void main(String[] args) {long userId = 123456L;int modulo = 10;//从配置文件读取String spel ="(#userId % #modulo) < 1";boolean result = grayMatchAbility(spel, userId, modulo);System.out.println("用户ID " + userId + " 取模 " + modulo + " 的结果是: " + result);}
}
收益

少出线上问题,就这一条足以。

稳定性建设-隔离

不要把鸡蛋放一个篮子里

场景&解决方案
  • 服务隔离:https://cbeann.blog.csdn.net/article/details/134362757
  • DB隔离:https://cbeann.blog.csdn.net/article/details/134362757
  • 消息隔离:https://cbeann.blog.csdn.net/article/details/134362757
收益
  • 个性化限流,集群级别的限流基本都是支持的,如果在参数级别限流,其实不好搞
  • 收费透明,现在都是云服务,不同租户用自己的会更清晰一些。
  • 数据安全,如果量级较大其实会存在托库的链路(MySQL同步到Hive),大家在一个库你把我数据拿走不安全。

稳定性建设-热点数据

加缓存,前提是能接受短期不一致

案例场景

没用过的叉出去,略。

定位问题

正常情况下是不加缓存,因为有别人触发你(告诉你接口慢等等)你才会优化,加缓存。那你如何知道是哪里慢从而加的缓存呢?

  • IO密集型:通过arthas的trace命令查看接口慢的地方
  • CPU密集型:每一个方法都很短,但是量大,火焰图无敌。如下图所示:长度越长,执行时间越长
    在这里插入图片描述

稳定性建设-大key问题

Redis有大key,本地缓存也有大key,严重会出现OOM

案例场景

在电商平台购物场景中,当出现非预期场景时最开始直接与买家或者卖家沟通的客服,比如退货不退款、假货投诉等等,客服的回答与服务直接影响用户的心智,影响用户的服务体验。因此监测客服与用户的聊天记录中是否存在违规行为就显得尤为重要。

举几个常见的场景:

  • 禁止辱骂用户
  • 禁止长时间不回复用户
  • 要求给客户推荐某商品

针对以上三个场景,其实是三个不同的算法模型去处理识别,当然生产模型有更多。

其实这个场景是在稳定性建设-充分利用机器资源稳定性建设-热点数据衍生出来的一个场景:加并发且加缓存

案例问题

系统出现了OOM,脱敏代码如下

java">    @Cacheable(value = "user")public Object getUser(List<Object> params) {// dao.update(user);return Object;}
定位原因

上述代码中因为没有设置缓存key,默认是方法名-参数名-参数JSON字符串。如果你的入参中有视频二进制,那么Key贼大。
解决方案:Key做一下MD5,过期时间设置的短一些。

稳定性建设-监控埋点

监控埋点:在SpringBoot自定义指标并集成Prometheus和Grafana监控

稳定性建设-熔断

案例场景

大模型比较火,但是这种接口的RT会贼高。比如下面图片。输入太多就直接给禁掉了,后端同理
在这里插入图片描述

解决方案

对入参做统计,比如超时1W字的直接不处理,直接返回错误码,别把机器打挂。

稳定性建设-批处理

定时任务处理订单下线,需要执行

java">update order set status = 1 where id = 1

此时可修改为

java">update order set status = 1 where id in (1,2,3,...n)

注意:in别太多

总结

稳定性建设非一蹴而就,需要长期观察才能发现问题,短期收益可以搭建监控面板。


http://www.ppmy.cn/news/1556178.html

相关文章

RK3588平台上YOLOv8模型转换与CentOS 7.8 Docker镜像拉取超时问题解决指南

RK3588平台上YOLOv8模型转换与CentOS 7.8 Docker镜像拉取超时问题解决指南 一、RK3588平台上YOLOv8模型从PT转换为RKNN 背景介绍 YOLOv8的原生模型包含了后处理步骤&#xff0c;其中一些形状超出了RK3588的矩阵计算限制&#xff0c;因此需要对输出层进行一些裁剪。本文将详细…

SpringCloud--SpringCloudAlibaba 对应的版本选择

SpringCloud--SpringCloudAlibaba 对应的版本选择 1、进入官网查看 输入Spring Cloud Alibaba官网_基于Springboot的微服务教程-阿里云 网址&#xff0c;选择文档->点击版本&#xff08;2023.x&#xff09; ​ 2、选择版本发布说明&#xff0c;可以看到Spring Cloud Ali…

禁用硬件合成 (Hardware Composer, HWC)

要禁用硬件合成 (Hardware Composer, HWC)&#xff0c;通常需要根据具体的设备平台和系统环境选择适合的方法。以下是通用的解决方案&#xff1a; 1. 修改系统属性 在 Android 系统中&#xff0c;可以通过设置系统属性来禁用 HWC 合成&#xff1a; a. 使用 setprop 命令临时禁…

3.2.1.2 汇编版 原子操作 CAS

基本原理说明 在 x86 和 ARM 架构上&#xff0c;原子操作通常利用硬件提供的原子指令来实现&#xff0c;比如 LOCK 前缀&#xff08;x86&#xff09;或 LDREX/STREX&#xff08;ARM&#xff09;。以下是一些关键的原子操作&#xff08;例如原子递增和比较交换&#xff09;的汇…

云计算HCIP-OpenStack03

书接上回&#xff1a; 云计算HCIP-OpenStack02-CSDN博客 10.KeyStone keystone-Openstack&#xff0c;IAM服务&#xff08;统一身份认证&#xff09;-云服务 建议先去了解Hadoop&#xff08;大数据生态系统&#xff09;中的kerberos&#xff08;LDAPkerberos的鉴权机制&#xf…

YOLOv11改进,YOLOv11添加DLKA-Attention可变形大核注意力,WACV2024 ,二次创新C3k2结构

摘要 作者引入了一种称为可变形大核注意力 (D-LKA Attention) 的新方法来增强医学图像分割。这种方法使用大型卷积内核有效地捕获体积上下文,避免了过多的计算需求。D-LKA Attention 还受益于可变形卷积,以适应不同的数据模式。 理论介绍 大核卷积(Large Kernel Convolu…

微积分复习笔记 Calculus Volume 2 - 4.2 Direction Fields and Numerical Methods

4.2 Direction Fields and Numerical Methods - Calculus Volume 2 | OpenStax

【机器学习】在向量的流光中,揽数理星河为衣,以线性代数为钥,轻启机器学习黎明的瑰丽诗章

文章目录 线性代数入门&#xff1a;机器学习零基础小白指南前言一、向量&#xff1a;数据的基本单元1.1 什么是向量&#xff1f;1.1.1 举个例子&#xff1a; 1.2 向量的表示与维度1.2.1 向量的维度1.2.2 向量的表示方法 1.3 向量的基本运算1.3.1 向量加法1.3.2 向量的数乘1.3.3…