当前位置:首页 > 科技  > 软件

一篇文章告诉你真实场景下服务端接口性能问题是如何解决的

来源: 责编: 时间:2024-04-07 17:05:05 94观看
导读作为Java后端开发者,我们创作的许多代码直接影响着用户的使用体验。如果后端代码性能不佳,用户在访问网站时就必须花费更多时间等待服务器响应。这可能引发用户投诉甚至用户流失问题。性能优化是一个广泛而重要的话题。

作为Java后端开发者,我们创作的许多代码直接影响着用户的使用体验。如果后端代码性能不佳,用户在访问网站时就必须花费更多时间等待服务器响应。这可能引发用户投诉甚至用户流失问题。Tow28资讯网——每日最新资讯28at.com

性能优化是一个广泛而重要的话题。《Java程序性能优化》提到性能优化可分为五个层次:设计优化、代码优化、JVM优化、数据库优化、操作系统优化等。每个层次都涵盖许多方法论和最佳实践。本文无意进行全面详尽的概述,只是列举几个常用的Java代码优化方案,希望读者阅读后能实际应用到自己的代码中。Tow28资讯网——每日最新资讯28at.com

单例层面

在处理IO操作、数据库连接、配置文件解析加载等耗费大量系统资源的任务时,我们必须限制这些实例的创建,或者始终使用一个共享的实例,以节约系统资源。这种情况下就需要使用单例模式。Tow28资讯网——每日最新资讯28at.com

批量操作

若有100个请求,逐个执行显然效率较低。将这100个请求合并为一个请求进行批量操作,则能大幅提升效率。Tow28资讯网——每日最新资讯28at.com

特别是在数据库操作中,批量处理不仅比逐条执行效率更高,还能有效降低数据库连接数,提升应用的QPS上限。Tow28资讯网——每日最新资讯28at.com

Future模式处理

假设某项任务需花费一定时间执行,为避免无谓的等待,可先获取一个“提货单”——即Future,随后继续处理其他任务,直至“货物”抵达,即任务执行完成并获得结果。这时便可凭借“提货单”提取物品,即通过Future对象获取返回值。Tow28资讯网——每日最新资讯28at.com

伪代码Tow28资讯网——每日最新资讯28at.com

public class RealData implements Callable<String> {    protected String data;    public RealData(String data) {        this.data = data;    }    @Override    public String call() throws Exception {        // 通过sleep方法演示业务是缓慢的        try {            Thread.sleep(1000);        } catch (InterruptedException e) {            e.printStackTrace();        }        return data;    }}public class Application {    public static void main(String[] args) throws Exception {        FutureTask<String> futureTask =                new FutureTask<>(new RealData("name"));        ExecutorService executor =                Executors.newFixedThreadPool(1); // 使用线程池        // 执行FutureTask,相当于上例中的client.request("name")发送请求        executor.submit(futureTask);        // 这里可以用一个sleep代替对其他业务逻辑的处理        // 在处理这些业务逻辑的同时,RealData也在创建,充分利用等待时间        Thread.sleep(2000);        // 使用真实数据        // 如果call()没有执行完成,仍会等待        System.out.println("数据=" + futureTask.get());    }}

线程池思路

合理运用线程池带来三大益处。首先,降低资源消耗:通过重复利用已创建的线程,降低线程的创建与销毁成本。其次,提高响应速度:任务到达时,无需等待线程创建即可立即执行。第三,提升线程可管理性:线程是珍贵资源,无节制地创建会消耗系统资源,降低系统稳定性;线程池能实现统一分配、优化和监控。Tow28资讯网——每日最新资讯28at.com

自 Java 5 开始,引入了并发编程新API,如Executor框架,内部采用线程池机制,位于java.util.concurrent包中。通过该框架控制线程的启动、执行和关闭,可简化并发编程操作。Tow28资讯网——每日最新资讯28at.com

伪代码Tow28资讯网——每日最新资讯28at.com

public class MultiThreadTest {    public static void main(String[] args) {        ThreadFactory threadFactory = new ThreadFactoryBuilder().setNameFormat("thread-%d").build();        ExecutorService executor = new ThreadPoolExecutor(2, 5, 60L, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), threadFactory);        executor.execute(new Runnable() {            @Override            public void run() {               System.out.println("Hello, world!");            }        });        System.out.println(" ===> Main Thread! ");    }}

NIO处理

JDK自1.4版本起引入了新的I/O编程类库,即NIO。NIO不仅带来了高效的Buffer和Channel,还引入了基于Selector的非阻塞I/O机制,可以将多个异步I/O操作集中到一个或少数几个线程中进行处理。使用NIO替代阻塞I/O能够提高程序的并发吞吐能力,降低系统开销。Tow28资讯网——每日最新资讯28at.com

针对每个请求,如果为其单独开启一个线程来处理逻辑,当客户端数据传输是间歇性的而非连续的时,相应线程会处于I/O等待状态,并频繁进行上下文切换。利用NIO引入的Selector机制,可以提升程序的并发效率,改善这种状况。Tow28资讯网——每日最新资讯28at.com

伪代码Tow28资讯网——每日最新资讯28at.com

public class NioTest {      static public void main( String args[] ) throws Exception {          FileInputStream fin = new FileInputStream("D://test.txt");          // 获取通道          FileChannel fc = fin.getChannel();          // 创建缓冲区          ByteBuffer buffer = ByteBuffer.allocate(1024);          // 读取数据到缓冲区          fc.read(buffer);          buffer.flip();          while (buffer.remaining()>0) {              byte b = buffer.get();              System.out.print(((char)b));          }          fin.close();      }  }

优化锁层面

在并发场景中,频繁使用锁是很常见的情况。然而,锁引发竞争,而竞争又会耗费大量资源。那么,在Java代码中,如何优化锁呢?我们可以考虑以下几个方面:Tow28资讯网——每日最新资讯28at.com

  • 缩短锁持有时间
  • 尝试使用同步代码块替代同步方法,从而减少锁的占用时间。
  • 降低锁粒度
  • 在并发环境中使用Map时,最好选用ConcurrentHashMap替代HashTable和HashMap(ConcurrentHashMap采用分段锁,锁的粒度更细)。Tow28资讯网——每日最新资讯28at.com

  • 分离锁Tow28资讯网——每日最新资讯28at.com

  • 普通锁(例如synchronized)可能导致读写互相阻塞,可以尝试将读操作和写操作分开。Tow28资讯网——每日最新资讯28at.com

  • 锁粗化Tow28资讯网——每日最新资讯28at.com

  • 有时我们希望将多次锁的请求合并成一个,以减少频繁加锁、同步和解锁所带来的性能损失。Tow28资讯网——每日最新资讯28at.com

  • 锁消除Tow28资讯网——每日最新资讯28at.com

  • 锁消除是指Java虚拟机在JIT编译时,经过运行上下文的扫描,去除那些不会产生共享资源竞争的锁。通过锁消除,可以减少无谓的锁请求时间。Tow28资讯网——每日最新资讯28at.com

数据传输压缩

在数据传输之前,压缩数据是一种优化方式,可以减少网络传输的数据量,提升传输速度。接收端可解压数据,还原传输内容。压缩后的数据能节省存储介质(如磁盘或内存)空间和网络带宽,从而降低成本。然而,压缩并非无成本之举。数据压缩需要大量CPU计算,并且根据压缩算法的不同,计算复杂度和压缩比都有显著差异。通常需要根据业务情景选择合适的压缩算法。Tow28资讯网——每日最新资讯28at.com

缓存计算结果

对于相同的用户请求,若每次都重复查询数据库、重复计算,将浪费大量时间和资源。将计算结果缓存至本地内存或使用分布式缓存,可节约宝贵的CPU计算资源,减少数据库重复查询或磁盘I/O。将原本需要磁头物理转动的操作转化为内存中的电子运动,提高响应速度。同时,快速释放线程也提升了应用的吞吐能力。Tow28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-81731-0.html一篇文章告诉你真实场景下服务端接口性能问题是如何解决的

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 京东一面:如何在SpringBoot启动时执行特定代码?

下一篇: 详解WebSocketMessageBrokerConfigurer在SpringBoot中应用与实践

标签:
  • 热门焦点
Top