首页 文章 精选 留言 我的

精选列表

搜索[服务],共10000篇文章
优秀的个人博客,低调大师

如何提升springboot服务吞吐量

背景 生产环境偶尔会有一些慢请求导致系统性能下降,吞吐量下降,下面介绍几种优化建议。 方案 1、undertow替换tomcat 电子商务类型网站大多都是短请求,一般响应时间都在100ms,这时可以将web容器从tomcat替换为undertow,下面介绍下步骤: 1、增加pom配置 <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> <exclusions> <exclusion> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-tomcat</artifactid> </exclusion> </exclusions> </dependency> <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-undertow</artifactid> </dependency> 2、增加相关配置 server: undertow: direct-buffers: true io-threads: 4 worker-threads: 160 重新启动可以在控制台看到容器已经切换为undertow了 2、缓存 将部分热点数据或者静态数据放到本地缓存或者redis中,如果有需要可以定时更新缓存数据 3、异步 在代码过程中我们很多代码都不需要等返回结果,也就是部分代码是可以并行执行,这个时候可以使用异步,最简单的方案是使用springboot提供的@Async注解,当然也可以通过线程池来实现,下面简单介绍下异步步骤。 1、pom依赖 一般springboot引入web相关依赖就行 <dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> </dependency> 2、在启动类中增加@EnableAsync注解 @EnableAsync @SpringBootApplication public class AppApplication { public static void main(String[] args) { SpringApplication.run(AppApplication.class, args); } } 3、需要时在指定方法中增加@Async注解,如果是需要等待返回值,则demo如下 @Async public Future<string> doReturn(int i){ try { // 这个方法需要调用500毫秒 Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } // 消息汇总 return new AsyncResult&lt;&gt;("异步调用"); } 4、如果有线程变量或者logback中的mdc,可以增加传递 import org.slf4j.MDC; import org.springframework.context.annotation.Configuration; import org.springframework.core.task.TaskDecorator; import org.springframework.scheduling.annotation.AsyncConfigurerSupport; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.Map; import java.util.concurrent.Executor; /** * @Description: */ @EnableAsync @Configuration public class AsyncConfig extends AsyncConfigurerSupport { @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setTaskDecorator(new MdcTaskDecorator()); executor.initialize(); return executor; } } class MdcTaskDecorator implements TaskDecorator { @Override public Runnable decorate(Runnable runnable) { Map<string, string> contextMap = MDC.getCopyOfContextMap(); return () -&gt; { try { MDC.setContextMap(contextMap); runnable.run(); } finally { MDC.clear(); } }; } } 5、有时候异步需要增加阻塞 import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.Executor; import java.util.concurrent.ThreadPoolExecutor; @Configuration @Slf4j public class TaskExecutorConfig { @Bean("localDbThreadPoolTaskExecutor") public Executor threadPoolTaskExecutor() { ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); taskExecutor.setCorePoolSize(5); taskExecutor.setMaxPoolSize(200); taskExecutor.setQueueCapacity(200); taskExecutor.setKeepAliveSeconds(100); taskExecutor.setThreadNamePrefix("LocalDbTaskThreadPool"); taskExecutor.setRejectedExecutionHandler((Runnable r, ThreadPoolExecutor executor) -&gt; { if (!executor.isShutdown()) { try { Thread.sleep(300); executor.getQueue().put(r); } catch (InterruptedException e) { log.error(e.toString(), e); Thread.currentThread().interrupt(); } } } ); taskExecutor.initialize(); return taskExecutor; } } 4、业务拆分 可以将比较耗时或者不同的业务拆分出来提供单节点的吞吐量 5、集成消息队列 有很多场景对数据实时性要求不那么强的,或者对业务进行业务容错处理时可以将消息发送到kafka,然后延时消费。举个例子,根据条件查询指定用户发送推送消息,这里可以时按时、按天、按月等等,这时就 </string,></string>

优秀的个人博客,低调大师

服务业务日志收集方案

背景 日志内容复杂多样,如何去收集有价值的日志是我们重点关注的。日志的价值其实是取决于业务操作的,不同的业务场景下相同类型的日志的价值会截然不同。 根据以往的业务实践,结合企业级的一些业务需求,我们选定关注以下几类日志。 • 跟踪日志【trace.log】 Server引擎的调试日志,用于系统维护人员定位系统运行问题使用。 • 系统日志【system.log】 大粒度的引擎运行的入口、出口的日志,用于调用栈分析,可以进行性能分析使用。 • 部署日志【deploy.log】 记录系统启动、停止、构件包部署、集群通知等信息的日志。 • 引擎日志【engine.log】 细粒度的引擎运行日志,可以打印上下文数据,用于定位业务问题。 • 构件包日志【contribution.log】 构件包记录的业务日志(使用基础构件库的日志输出API写日志) 这里我们专门针对系统日志收集讨论几种收集方案 方案一:通过日志组件来收集 这里是指通过logback、log4j等日志组件来输出文件,然后再通过文件输出到logstash、kibana等日志组件中,通过这些日志组件来进行可视化统计与分析,这里需要统一关键日志输出格式方便日后统计搜索。 优点 操作简单,收集方便 减少业务依赖 粒度细 缺点 依赖于logstash、kibana 只能满足简单的日志操作,详细点或者个性化需求操作起来比较复杂 方案二:使用aop来拦截controller 拦截controller层,通过controller中的方法名是否包含insert、update、delete等关键字来记录业务日志。 优点 操作简单,收集方便 缺点 只能记录简单日志 不同的人命名习惯不一样,日志可能不准确 方案三:使用注解来,进行稍微精准的业务日志记录 这个方案粒度可大可小,代码侵入性也比较小,可操作性比较强,如果需要获取参数信息或者返回值信息,可以通过注解配置获取到,可以集合fastjson中的jpath来获取参数值下面有几个伪代码供参考 @Slf4j @Aspect public class SysLogAspect { @Around("@annotation(sysLog)") @SneakyThrows public Object around(ProceedingJoinPoint point, SysLog sysLog) { // 根据系统上下文获取相关数据 Operation logVo = SysLogUtils.getOperationModel(); Object obj=null; try{ // 操作方式 logVo.setOperationName(sysLog.value()); // 操作时间 logVo.setOperationTime(new Date()); logVo.setObjectType(sysLog.objectType().name()); logVo.setAppName(StringUtils.defaultString(sysLog.appName(),"TSP")); // 发送异步日志事件 obj = point.proceed(); if(StringUtils.isNotBlank(sysLog.objectIdKey())&&StringUtils.isNotBlank(sysLog.objectNameKey())){ Map<String,Object> params=Maps.newHashMap(); params.put("args",point.getArgs()); params.put("response",obj); logVo.setObjectId(getKeyValue(sysLog.objectIdKey(),params)); logVo.setObjectName(getKeyValue(sysLog.objectNameKey(),params)); } }catch (BusinessException e){ logVo.setException(e.getMessage()); throw new Exception(e); }catch (RuntimeException e){ logVo.setException(e.getMessage()); throw new Exception(e); }catch (Exception e){ logVo.setException(e.getMessage()); throw new Exception(e); }finally { ApplicationContextUtils.publishEvent(new OperationEvent(logVo)); } return obj; } private String getKeyValue(String key,Map<String,Object> params){ try{ Object mm= JSONPath.eval(params,key); if(mm!=null){ return mm.toString(); } }catch (Exception e){ log.error("JSONPath.eval:",e); } return null; } } `` @SysLog(value = "xxxxxx",objectType = LogObjectType.OFFLINE_THRONG, objectIdKey = "$['args'][0][0]['id']",objectNameKey = "$['response'][0][0]['throngName']") 优点 操作简单 较灵活,粒度可大可小 缺点 有代码侵入 个性化需求不满足 方案四:针对复杂场景或者审计需求手动记录,侵入性强 如果有些业务公用了方法,需要更小的粒度,或者需要记录业务数据变更记录,这时就只能选择侵入式较强的方式来记录日志了,直接再业务代码中记录日志 logClient.logObject(LogObjectType.XXX,id,UserContext.getUserName(),"编辑xxx","xxx变更为xxxxx"); 方案五:记录sql日志 则可以使用mybatis拦截器来进行,如果没有使用mybatis,则可以做一个通用的preparestatement以及statement代理。 当然现在已经有很对监控组件可以满足这个需求,比如说jeager、javamelody、druid等 一般情况下我们会采用多种方式来记录业务日志,这个都是根据具体需求来进行评估用哪几种方式可以更好的达到产品需求。

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册