当前所在位置: 主页 > 耀世新闻 > 公司新闻

?并发系统如何做性能优化?

本文旨在深入探讨性能优化的重要性,并提供一套全面的性能优化方案。我们将从硬件、软件和网络三个方面进行分析,以帮助您提高系统的整体性能。通过遵循这些建议,您将能够显著提高系统的响应速度、降低延迟,以及提升用户体验。

1、分而冶之(“分”字诀)

业务分层、系统分级、服务分布、数据库分库/表、动静分离、同步拆分成异步、单线程分解成多线程、原数据缓存分离、单表分多表、单库分多库、分流等等。。。。 在系统性能优化中,"分而治之"是一种常用的策略,通过将问题分解为更小、更可管理的子问题,然后分别解决每个子问题,最终得到整体的优化效果。以下是一些常见的"分而治之"技术和方法:

  1. 任务并行化:将大任务分解为多个子任务,并使用并行计算的方式同时处理这些子任务,以提高系统的整体处理能力。例如,将大型数据处理任务分割成多个并行任务,并使用多线程或分布式计算来同时处理这些任务。
  2. 模块化设计:将复杂的系统拆分成模块,每个模块负责特定的功能或任务。每个模块可以独立开发、测试和优化,以提高整体系统的可维护性和性能。
  3. 算法分解:对复杂的算法进行分解,将其拆分为更简单、可复用的子算法。通过优化每个子算法的性能,可以改善整体算法的执行效率。
  4. 数据分区:对大规模数据集进行分区,将数据划分为多个子集,并在每个子集上执行并行操作。这种方法常用于大数据处理和分布式系统中,以提高数据处理和查询的效率。
  5. 资源分配:将系统的资源进行分配和管理,例如将任务分配给最适合的处理单元或节点,以实现更好的负载均衡和资源利用率。
  6. 问题拆解:将复杂的问题拆解成多个简单的子问题,并使用递归或迭代的方式分别解决每个子问题。最终将子问题的解合并起来,得到整体问题的解决方案。
  7. 网络优化:包括协议优化、负载均衡、缓存策略等。
  8. 系统架构优化:包括分布式架构、微服务架构、容器化部署等。
  9. 任务拆分:把任务切分为多个子任务,分开执行,利用并行或分布式的方式来提高效率和可扩展性。
  10. 异步处理:对于耗时较长或依赖外部资源的任务,可以采用异步的方式来执行,避免阻塞主线程或影响用户体验。常见的异步处理机制有消息队列、回调函数、事件监听器等。

2、合而为一(“合”字诀)

微服务粒度不可太细该合则合、数据库大表减少联合查询该冗余则合并冗余数据。直观的表述就是:从前端用的CDN、动静分离,到后台服务拆分成微服务、分布式、负载均衡、缓存、池化、多线程、IO、分库表、搜索引擎等等。都是强调一个“分”字。 在系统性能优化中,"合而为一"是一种策略,强调整体性能的最大化,而不仅仅是局部问题的解决。以下是一些常见的"合而为一"技术和方法:

  1. 系统级优化:综合考虑整个系统的性能瓶颈和热点,通过全局性能分析和优化策略,针对系统整体进行优化。这包括综合考虑各个组件和模块之间的相互影响,以达到整体性能的最大化。
  2. 资源管理和优化:通过综合管理和优化系统资源,如内存、CPU、网络等,以实现整体性能的提升。这包括资源分配策略的优化、负载均衡的实现、资源利用率的最大化等。
  3. 综合并发和并行优化:考虑整个系统的并发和并行操作,通过综合优化并发控制、资源共享、同步机制等,以提高整体系统的并发性能和效率。
  4. 数据流和数据处理优化:优化数据在系统中的流动和处理,通过综合考虑数据传输、转换、处理的各个环节,以最大程度地提高整体数据处理的效率和性能。
  5. 系统架构设计优化:在系统设计阶段就考虑性能需求,选择合适的架构和技术,以确保系统整体性能的最优化。这包括合理划分模块、减少组件之间的耦合、选择高效的通信协议和数据格式等。
  6. 整体系统调优和配置:通过调整整个系统的配置和参数,使其最适合特定的工作负载和性能要求。这包括调整系统缓冲区大小、优化网络连接数、配置线程池参数等。
  7. 综合性能监测和调优工具:使用综合性能监测工具和分析器,全面监测和分析系统性能,以识别整体性能瓶颈和优化机会。这包括综合考虑各个组件和模块的性能指标,以制定综合的优化策略。

通过采用以上的"合而为一"技术,可以在整体上提升系统性能,通过综合考虑各个组件和模块的相互关系和相互影响,达到全局性能的最大化。这种方法强调整体性能的提升,使系统在各个层面和维度上获得最佳的性能和效率。 一、引言 随着科技的发展,高性能计算已经成为了许多行业的关键需求。无论是游戏、金融、医疗还是其他领域,高性能计算都扮演着举足轻重的角色。然而,实现高性能并非易事。为了满足用户对速度和效率的需求,我们需要不断地进行性能优化。在这篇文章中,我们将为您介绍一套全面的性能优化方案,帮助您提高系统的整体性能。 1、性能优化的定义 性能优化是指对计算机硬件、操作系统和应用程序有相当深入的了解,调节三者之间的关系,实现整个系统(包括硬件、操作系统、应用)的性能最大化,并能不断的满足现有的业务需求。通过对系统进行调整、改进和优化,以提高其执行速度、响应时间、吞吐量、资源利用率或其他性能指标的过程。性能优化旨在通过减少延迟、提高吞吐量、降低资源消耗等手段,使系统能够更高效地满足用户需求,提供更好的用户体验。 性能优化可以应用于各个领域,包括软件开发、数据库管理、网络通信、算法设计、系统架构等。 性能优化是一个持续的过程,需要综合考虑系统的需求、资源限制和用户体验,通过实时监测、分析和优化来不断改进系统的性能。它涉及到细致的性能分析、实验、调整和验证,以确保系统在实际运行中能够达到最佳的性能表现。 2、性能优化的目标 性能优化的目标是提高系统、应用程序或算法的性能,以满足用户需求,并提供更好的用户体验。以下是性能优化的主要目标:

  1. 响应时间优化:减少系统的响应时间,使用户能够更快地获取结果或执行操作。快速响应时间可以增强用户满意度、提高用户参与度,并增加系统的可用性。
  2. 吞吐量优化:提高系统的处理能力和并发性,以使系统能够处理更多的请求或事务。增加吞吐量可以提高系统的扩展性、适应高并发负载,并支持更多的用户同时访问。
  3. 资源利用率优化:通过合理的资源管理和利用,最大程度地减少资源的浪费和闲置,提高系统的效率和性能。优化资源利用率可以减少硬件资源成本,提高系统的可伸缩性和经济性。
  4. 稳定性和可靠性优化:通过优化系统的稳定性和可靠性,确保系统在长时间运行和高负载条件下的稳定性,减少系统崩溃和错误的风险。
  5. 能耗优化:减少系统或设备的能耗,以提高能源效率、降低运行成本,并对环境产生更小的影响。
  6. 用户体验优化:提升用户体验,包括界面流畅性、交互响应速度和操作的顺畅性。优化用户体验可以增加用户的满意度、降低用户的流失率,并提高用户的忠诚度。
  7. 可维护性优化:通过优化系统的设计、代码质量和架构,使系统易于维护和扩展,降低维护成本,并提高开发团队的生产力。

性能优化的目标是使系统在给定的资源和约束条件下,尽可能地达到最佳的性能水平。综合考虑用户需求、系统要求和资源限制,以实现性能和可用性的最佳平衡。 3、性能优化的重要性 性能优化在现代应用开发和系统设计中具有重要性,以下是性能优化的几个关键方面和其重要性:

  1. 提升用户体验:良好的性能可以显著提高用户体验,使用户更快地获得响应和结果。快速的响应时间和高吞吐量能够增强用户满意度,降低用户的等待时间和不良体验,提高用户参与度和留存率。
  2. 增强系统可扩展性:性能优化可以提高系统的处理能力和并发性,使其能够处理更多的请求或事务。通过增加吞吐量和提高资源利用率,系统能够更好地适应高并发负载和大规模用户的需求,保持稳定性和高性能。
  3. 节约资源和成本:性能优化可以减少资源的消耗和浪费,提高资源的利用效率。通过优化内存、CPU、网络等资源的使用,系统可以在相同的硬件配置下处理更多的工作,降低硬件资源成本和运行成本。
  4. 提高可靠性和稳定性:性能优化有助于提高系统的稳定性和可靠性。通过减少延迟和优化并发操作,可以减少系统错误和崩溃的风险,提高系统的稳定性和可用性。
  5. 增强竞争优势:在竞争激烈的市场中,性能优化可以成为企业和产品的竞争优势。快速响应时间、高吞吐量和出色的用户体验可以吸引更多的用户,提高市场份额和品牌声誉。
  6. 节能环保:通过性能优化减少系统或设备的能耗,可以提高能源效率,降低能源消耗和对环境的影响。这对于可持续发展和企业的社会责任意义重大。
  7. 提高开发效率:性能优化可以促使开发团队关注代码的质量、设计的优化和系统的可维护性。这有助于提高开发效率、减少维护成本,并使开发者具备更好的代码和系统设计能力。

性能优化不仅是满足用户期望的基本要求,还是保持竞争力、提高效率和节约资源的关键因素。通过投入适当的时间和资源进行性能优化,可以实现系统的卓越性能和用户体验,从而为个人用户、企业和组织带来巨大的利益。 4、性能优化的原则 性能优化需要遵循一些基本的原则:

5、性能优化的方法 1、硬件层面的性能优化

2、软件层面的性能优化

3、网络层面的性能优化

二、内存管理优化 1、了解Java内存相关基础 1.1、Java内存模型 JMM(Java Memory Model)是Java虚拟机规范中定义的一种内存模型,它描述了Java程序如何在多线程环境下访问共享内存。JMM主要是为了屏蔽各种硬件和操作系统对内存访问的差异而定义出来的内存模型。JMM定义了一个抽象的计算机内存模型,包括主内存和工作内存两部分。

1.2、运行时数据区 JVM运行时数据区是Java虚拟机在执行Java程序时所使用的内存区域。这些区域包括了以下几个部分:

  1. 程序计数器(Program Counter Register):程序计数器是一块较小的内存区域,它可以看作是当前线程所执行的字节码的行号指示器。每一个线程都有自己独立的程序计数器,用于记录该线程需要执行的指令地址。
  2. Java虚拟机栈:Java虚拟机栈是由一个个栈帧(Stack Frame)组成的,每个栈帧对应着Java方法的调用。当一个方法被调用时,就会在Java虚拟机栈中生成一个对应的栈帧,并将其入栈。当方法执行完成后,栈帧就会出栈。Java虚拟机栈用于存储局部变量、方法参数、返回值和操作数等信息。
  3. 本地方法栈:本地方法栈与Java虚拟机栈类似,但是它用于执行本地方法(Native Method)。本地方法是用C、C++等语言实现的方法,它们不同于Java代码,需要直接访问操作系统资源。
  4. Java堆:Java堆是Java虚拟机中最大的一块内存区域,也是程序运行时唯一一个被所有线程共享的内存区域。Java堆用于存放Java对象实例和数组等数据结构。Java堆可以动态地扩展和缩减,它的大小可以通过命令行参数进行控制。
  5. 方法区(Method Area):方法区用于存储类信息、常量、静态变量、即时编译器编译后的代码等数据,它是Java虚拟机中永久存储区域之一。方法区在Java 8之前称为永久代(PermGen),从Java 8开始逐步替换为Metaspace。
  6. 运行时常量池:运行时常量池是每个类或接口的常量池表的运行时表示形式。它包含了编译时期生成的字面量和符号引用,以及运行时生成的字符串字面量等。运行时常量池属于方法区的一部分。

以上就是Java虚拟机运行时数据区的主要组成部分。不同的区域在内存大小和使用方式上有所不同,但它们都是支撑Java程序正常执行的重要组成部分。理解Java虚拟机的运行时数据区,对于编写高效、稳定的Java程序非常重要。

1.3、Java垃圾回收机制 Java的垃圾回收(Garbage Collection,GC)机制是Java虚拟机(JVM)负责自动回收不再使用的对象所占用的内存空间的一种机制。垃圾回收机制大大减轻了开发人员手动管理内存的负担,并帮助预防内存泄漏和提高应用程序的性能。 1、回收过程

1)先判断对象是否存活(是否是垃圾) 可以通过引用计数算法和可达性分析算法来判断,由于引用计数算法无法解决循环引用的问题,所以目前使用的都是可达性分析算法 2)再遍历并回收对象(回收垃圾) 可以通过垃圾收集器(Serial/Parallel/CMS/G1)来回收垃圾,垃圾收集器使用的算法标记清除算法、标记整理算法、复制回收算法和分代回收算法。 2、GC种类

3、GC原理

2、选择合适的垃圾收集器


收集器CMSG1
回收算法标记清除标记整理
回收区域老年代新生代+老年代
内存布局传统将新生代、老年代切一起分成一个个Region
内存碎片产生碎片空间碎片空间小
并发并发并发
JDK使用JDK8默认(Parallel)JDK9默认
停顿时间最短停顿时间可预测停顿时间


  1. Java 8:默认的垃圾收集器是Parallel收集器。它使用并行线程进行垃圾回收,适用于多核处理器的情况,目标是在最短的时间内获得最高吞吐量。
  2. Java 11:默认的垃圾收集器是G1(Garbage-First)收集器。它是一种低延迟垃圾收集器,旨在实现较低的停顿时间和高吞吐量。
  3. Java 14:默认的垃圾收集器仍然是G1收集器。
  4. Java 15:默认的垃圾收集器仍然是G1收集器。
  5. Java 16:默认的垃圾收集器仍然是G1收集器。

Java虚拟机还提供了许多参数用于调整垃圾收集器的行为和性能。可以使用这些参数来指定特定的垃圾收集器,调整堆大小、停顿时间、吞吐量等。根据应用程序的需求和特性,可以通过这些参数来优化垃圾收集器的性能。 3、内存分析工具 1)jstat:用于监控JVM内存使用情况和垃圾回收信息。 2)jmap:用于生成JVM堆转储文件,以便分析内存使用情况。 3)jconsole:用于监控JVM性能指标、线程数量等信息。

4)VisualVM:一个功能强大的性能分析工具,可以统计CPU、内存、GC等各种指标,并提供图形化界面。

5)阿里Arthas:应用程序的性能分析、内存泄漏检测、线程问题排查、方法调用追踪等操作。

6)Apache JMeter:用于进行压力测试和性能测试。可测试出系统的性能拐点。

7)Eclipse MAT:Mat是Eclipse的一个插件, 也可以独立运行, 所以即使你使用IDEA也可以独立使用Mat。MAT主要的功能就是分析dump文件。

8)XRebel:一款轻量级的Java性能分析工具,提供实时的代码级性能分析和优化建议。 页面操作后,会在xrebel控制台看到每个http请求的耗时

把每个被调用或执行的类的方法耗时都显示出来,同时不同颜色标明耗时情况。

三、多线程并发优化 1、线程池(池化技术)

Oracle 官方并没有给出线程池 corePoolSize 的具体参考值,因为这个值的大小应该根据实际业务场景和系统资源情况来进行优化调整。不同的业务场景和系统资源状况可能需要不同的 corePoolSize 设置。 在《Java并发编程实战》一书中,作者 Brian Goetz 等人指出,线程池的规模应该根据任务类型和计算密集度来确定,对于 CPU 密集型任务,应该将核心线程数设置为处理器核心数加 1 或者 2;对于 I/O 密集型任务,可以适当增加核心线程数以利用空闲的 CPU 时间。 这个建议是基于以下考虑:对于 CPU 密集型任务,线程需要大量计算,因此需要足够多的 CPU 资源,而处理器核心数加 1 或者 2 的数量可以充分利用 CPU 资源,避免线程之间的竞争和阻塞;而对于 I/O 密集型任务,由于线程大部分时间都处于等待 I/O 操作的状态,因此可以适当增加核心线程数以利用空闲的 CPU 时间,从而提高系统效率。 虽然这个建议并非官方标准,但在实际应用中已经得到广泛的认可和应用,并取得了不错的效果。 2、锁竞争和粒度(锁优化技术) 性能优化中减少锁竞争和使用细粒度锁是常用的策略,可以有效提高并发程序的性能。以下是一些减少锁竞争和使用细粒度锁的策略: 2.1、减少锁粒度 通过分解大锁为多个小锁,减小锁的粒度,从而降低锁竞争的程度。例如,将一个大的同步代码块拆分成多个小的同步代码块,可以使并发执行的线程之间的竞争减少。 2.2、使用读写锁 对于读多写少的场景,可以使用读写锁(ReentrantReadWriteLock)来提高并发性能。读写锁允许多个线程同时获取读锁,但只有一个线程可以获取写锁,从而提供更高的并发性。 2.3、使用并发集合 Java提供了一些并发集合类,如ConcurrentHashMap、ConcurrentLinkedQueue等。这些并发集合类使用了内部的细粒度锁机制,可以在多线程环境下提供高效的并发操作。 2.4、使用CAS操作 CAS(Compare and Swap)是一种乐观锁机制,通过比较并交换的方式进行原子操作,避免了使用传统的互斥锁带来的性能开销和线程阻塞。Java中的Atomic类和AtomicReference类提供了CAS操作的支持。

具体来说,多线程CAS操作包括以下几个步骤:

  1. 获取当前共享变量的值和期望值。
  2. 比较共享变量的当前值和期望值是否相等,如果相等则将共享变量的值更新为要写入的新值。
  3. 如果共享变量的当前值与期望值不相等,则说明此时有其他线程已经修改了共享变量的值,那么当前线程需要重新获取共享变量的最新值,并重复执行步骤b。

在并发环境下,多线程CAS操作可以保证共享变量的原子性操作,同时也避免了传统锁机制所带来的线程阻塞和上下文切换的开销。因此,多线程CAS操作被广泛应用于各种高并发场景中,如数据库事务、分布式系统等。 2.5、读写分离锁 将数据结构中的只读操作和写操作分离,分别使用读锁和写锁。这样可以允许多个线程同时读取数据,而只有在写操作时才需要加锁,减少了读操作之间的竞争。 2.6、使用无锁算法 无锁算法(Lock-Free)是一种不使用互斥锁的并发算法。它通常基于CAS操作和其他原子操作,通过无阻塞的方式实现并发访问,避免了锁竞争带来的性能损失。 2.7、避免过度同步 合理评估同步代码块的范围,避免不必要的同步,减少锁竞争的范围,提高并发性能。 需要根据具体的应用场景和需求选择适合的策略。同时,性能优化是一个综合考虑的过程,还需综合其他因素,如资源利用、算法优化等,以获得最佳的性能提升效果。 四、代码优化 代码优化是性能优化的基础,它可以通过减少代码中的冗余和重复操作来提高程序的执行效率。以下是一些常见的代码优化技巧: 1、数据结构 选择合适的数据结构可以显著提高代码的性能。通过分析问题的特点,选择更高效的算法来解决问题,如使用快速排序替代冒泡排序等。 2、避免重复计算 将重复计算的结果存储起来,避免在程序中多次计算相同的结果。例如,可以将一个数字的平方存储在一个变量中,然后在需要的时候直接使用这个变量。 3、内存管理 合理管理内存资源可以减少内存分配和释放的开销,如避免频繁的对象创建和销毁,使用对象池、缓存等技术进行优化。 4、使用位运算 位运算比算术运算更快,因为它们可以直接操作二进制位。例如,可以使用按位与操作符(&)来检查一个整数是否为偶数。 5、减少函数调用 函数调用会产生额外的开销,因此应该尽量减少函数调用的次数。例如,可以将一些常用的计算结果存储在全局变量中,然后在需要的时候直接使用这些变量。 关于代码优化可以选择一份编码规范或形成一定的代码库。官方下载地址:《Java开发手册(黄山版).pdf

6、流技术 性能优化之stream技术是指使用Java 8中的Stream API来对集合进行高效的遍历和操作。Stream API可以提供一种声明式的编程风格,利用Lambda表达式对集合进行各种聚合操作和批量数据操作,例如排序、过滤、映射等。Stream API还可以支持并行处理,利用多核CPU的优势,提高数据的处理速度。 Stream API的实现原理主要涉及以下几个方面:

7、Reactive技术 性能优化之reactive技术是指一种面向数据流和事件的异步编程范式,可以提高程序的响应速度和资源利用率。reactive技术可以分为reactive编程和reactive架构两个方面。 reactive编程是指使用一些库或框架,如RxJava、Reactor、Redux等,来实现数据流和事件的响应式处理,可以简化异步编程的复杂度,提高代码的可读性和可维护性。 reactive架构是指使用一些设计原则和模式,如响应式宣言、微服务、消息驱动等,来构建高可用、高伸缩、高弹性的分布式系统,可以应对不断变化的需求和负载。 五、数据库访问优化 1、MySQL 1.1、MySQL调优维度

1)SQL及索引优化:SQL查询语句的优化是提高MySQL性能的关键。优化查询语句可以采用各种方法,如使用合适的索引、避免在WHERE子句中使用函数操作符、减少子查询等。 2)表结构优化:表的设计和结构也会影响MySQL的性能。适当的表设计可以提高查询性能和数据处理速度。例如,使用分区表可以加速查询,而垂直拆分表可以降低数据库的负载。 3)系统配置优化:MySQL及服务器的参数设置对于性能也非常重要。调整配置可以让MySQL更好地利用硬件资源。例如,增加缓存区大小、调整连接超时时间或者优化排序缓存等都可以提高系统性能。 4)硬件优化:除了软件方面的优化,还可以通过硬件来优化MySQL性能。例如,使用更快的磁盘、增加内存以及升级CPU等都可以提高MySQL的负载能力。 1.2、MySQL调优分解

2、缓存技术 缓存技术是性能优化中常用的一种策略,它通过存储计算结果、数据或资源的副本,以减少对原始数据源的访问次数,从而提高数据访问的速度和性能。 2.1、常见的缓存技术:

  1. 数据缓存:将经常访问的数据存储在内存或其他高速存储介质中,以避免频繁的磁盘或网络访问。常见的数据缓存包括内存缓存、分布式缓存(如Redis、Memcached)等。
  2. 查询缓存:对于数据库查询结果,可以将查询语句及其结果缓存起来,下次查询时可以直接从缓存中获取,减少数据库查询的次数。数据库自带的查询缓存或使用外部缓存工具(如Ehcache)可以实现查询缓存。
  3. 对象缓存:将经常使用的对象存储在内存中,以避免频繁的对象创建和初始化。对象缓存可以提高对象的访问速度和复用性。
  4. 页面缓存:将动态生成的页面内容缓存起来,下次请求时直接返回缓存的页面,避免重复的页面渲染和数据库查询等操作。常见的页面缓存技术包括浏览器缓存、CDN缓存等。
  5. 资源缓存:对于耗时的资源加载操作,如图片、CSS、JavaScript等文件的加载,可以将其缓存到本地或CDN,减少网络请求和提高加载速度。
  6. 缓存预热:在应用程序启动或请求开始之前,提前加载和初始化缓存数据,以避免首次访问的冷启动延迟。

需要根据具体的应用场景和需求选择合适的缓存技术,并综合考虑缓存的一致性、容量、更新机制等因素。同时,缓存的设计和管理也需要谨慎,避免缓存膨胀、数据一致性问题和过期缓存的影响。 2.2、缓存分类

1)本地缓存: 将缓存数据存储在单个应用程序进程内部的内存中,通常是使用Java集合类如HashMap、ConcurrentHashMap等进行实现。本地缓存的优点是速度快、易于实现,并且不需要网络传输,但无法跨越多个应用程序进程共享数据。 2)分布式缓存: 将缓存数据存储在多台服务器上,通过网络传输数据实现缓存共享。常见的分布式缓存框架有Redis、Memcached、Ehcache等。分布式缓存的优点是可以扩展性好、支持高并发、容量大,并且能够提高应用程序的可靠性和可用性。 3)多级缓存(本地+分布式): 将缓存数据同时存储在本地缓存和分布式缓存中,以加快访问速度并提高可靠性。常见的多级缓存方案包括EHCache+Redis、Guava Cache+Redis等。多级缓存的优点是兼顾了本地缓存和分布式缓存的优点,使得缓存系统更灵活、性能更强。 六、通信及IO优化 1、非阻塞IO和异步IO模型

2、NIO和多路复用技术

选择器(Selector) 选择器是Java NIO中的一个重要组件,它可以用于同时监控多个通道的读写事件,并在有事件发生时立即做出响应。选择器可以实现单线程监听多个通道的效果,从而提高系统吞吐量和运行效率。 通道(Channel) 通道是一个用于读写数据的对象,类似于Java IO中的流(Stream)。与流不同的是,通道可以进行非阻塞式的读写操作,并且可以同时进行读写操作。通道分为两种类型:FileChannel和SocketChannel,分别用于文件和网络 通信。 缓冲区(Buffer) 在Java NIO中,所有数据都是通过缓冲区对象进行传输的。缓冲区是一段连续的内存块,可以保存需要读写的数据。缓冲区对象包含了一些状态变量,例如容量(capacity)、限制(limit)、位置(position)等,用于控制数据的读写。 3、协议和数据格式


方面http协议rpc协议
传输层基于TCP,有特定的传输格式,包含大量的头部信息,数据传输效率低基于TCP或UDP,自定义数据格式,数据传输效率高
通用性不关心实现细节,跨语言、跨平台,适合部门间或外部服务的调用需要在API层面进行封装,限制了开发的语言环境,适合内部服务的调用
开发难度相对简单,只需遵循REST规范,请求、响应等细节需要自己实现相对复杂,需要考虑server选择、序列化、通信、容错等功能
速度较慢,受到HTTP头部信息和TCP握手的影响较快,数据格式简洁,通信方式可靠


4、Http连接池和连接复用 Http连接池是一种用于管理和复用HTTP连接的技术,可以提高HTTP请求的性能和效率。以下是几种常见的Http连接池实现技术:

以下是一些开源http连接池实现技术:

  1. OkHttp:OkHttp是一个现代化的HTTP客户端库,支持连接池管理。它具有简洁的API和高性能的特点,能够自动管理连接的复用和连接的超时。
  2. Apache HttpClient:Apache HttpClient是一个成熟的Java HTTP客户端库,提供了连接池管理的功能。它具有高度可定制性和灵活性,支持连接复用、连接超时控制、并发请求管理等功能。

5、同步变异步 性能优化同步变异步是一种常见的编程模式,可以提高系统的响应速度和吞吐量。同步操作会导致请求一直阻塞,直到失败或者成功的返回结果。异步操作可以支持横向扩容,可以缓解瞬间的请求压力,使得请求变得平滑。 如果一个接口中需要进行多步,而这些业务操作又是各自独立的,传统的依据代码顺序同步执行又比较耗时,传统的优化的空间又比较少,这时就可以考虑使用多线程的方式优化接口,让同步变异步,接口业务操作并行处理,极大提升接口的性能。 七、性能监测 在微服务架构中,系统性能监控通常使用以下工具和技术:

  1. 分布式追踪工具:分布式追踪工具用于跟踪和监控微服务之间的请求链路,帮助发现性能瓶颈和故障点。常见的分布式追踪工具包括Zipkin、Jaeger和SkyWalking等。
  1. 指标监控和时序数据库:指标监控工具用于收集、存储和可视化系统的关键指标和性能数据,帮助用户实时了解系统的状态和性能。常见的指标监控工具包括Prometheus、InfluxDB和Grafana等。
  1. 日志管理和分析工具:日志管理和分析工具用于收集、存储和分析微服务的日志数据,帮助诊断和解决问题。常见的日志管理和分析工具包括ELK Stack(Elasticsearch、Logstash、Kibana)、Splunk和Graylog等。

  2. 容器监控和管理工具:如果微服务部署在容器化平台上,如Docker和Kubernetes,可以使用容器监控和管理工具来监控容器的资源使用情况、网络通信和调度性能等。常见的容器监控和管理工具包括cAdvisor、Prometheus Operator和Kubernetes Dashboard等。
  1. 应用性能管理(APM)工具:APM工具用于实时监控和分析微服务应用程序的性能和健康状况,包括服务响应时间、数据库查询性能、CPU和内存使用等。常见的APM工具包括New Relic、AppDynamics和Dynatrace等。

这些工具和技术可以提供实时的系统性能监控、故障排查和性能优化的能力,帮助开发人员和运维团队监控和管理微服务架构中的性能和可用性。选择合适的工具和技术需要考虑具体的需求、技术栈和可扩展性要求。 八、架构优化 系统性能优化的架构优化是关键的一部分,它包括以下几个方面的技术和策略:

  1. 负载均衡:负载均衡用于将请求分发到多个服务器上,以平衡系统的负载,提高系统的吞吐量和可用性。常见的负载均衡技术包括硬件负载均衡器(如F5)和软件负载均衡器(如Nginx、Gateway)。
  2. 流量漏斗:流量漏斗用于限制系统的请求速率,防止突发流量对系统的冲击。它通过设置请求的速率限制和排队机制,平滑请求的到达,防止系统过载。流量漏斗技术常用于API限流、请求限制等场景。
  3. 集群:集群是将多个服务器组成一个逻辑单元,共同处理请求,提高系统的可扩展性和容错性。通过横向扩展增加服务器节点,可以提高系统的处理能力和并发性能。常见的集群技术包括分布式缓存(如Redis集群)、分布式数据库(如MySQL集群)和分布式文件系统(如Hadoop)等。
  4. 熔断:熔断机制用于在系统出现故障或异常时,对服务进行自动断开,以保护系统的稳定性和可用性。通过设置阈值和时间窗口,当系统的错误率或响应时间超过一定阈值时,触发熔断,停止对服务的请求,避免错误的扩散。
  5. 降级:降级是在系统资源有限或出现异常情况时,临时屏蔽某些功能或服务,以保证核心功能的可用性。通过设定优先级,当系统负载过高或异常时,可以主动关闭或简化某些非核心功能,提高系统的稳定性和响应能力。
  6. 限流:限流机制用于限制系统的最大并发请求数,防止系统被过多请求压垮。通过设置请求的速率限制、并发连接数限制等,可以控制系统的负载,保持系统的稳定性。常见的限流技术包括令牌桶算法、漏桶算法等。

这些架构优化技术和策略可以根据具体的应用需求和系统瓶颈进行选择和应用。通过合理的架构设计和优化,可以提升系统的性能、可伸缩性和可用性,确保系统能够承受高负载和高并发的请求。 九、系统优化 系统优化是对整个系统的优化,它可以通过调整系统的配置和参数来提高系统的性能。以下是一些常见的系统优化技巧:

  1. 空间换时间:利用内存、缓存等存储设备来减少磁盘或网络的读写操作,提高数据访问的速度。
  2. 时间换空间:当空间成为瓶颈时,可以采用分批处理、压缩、分区等方式来减少空间占用,降低数据传输的开销。
  3. 关闭不必要的服务:系统中运行的服务越多,系统的负担就越重,因此应该关闭不必要的服务来减轻系统的负担。例如,可以使用任务管理器来关闭不必要的进程和服务。
  4. 调整进程优先级:进程优先级决定了操作系统分配资源的顺序,因此可以通过调整进程优先级来优化系统性能。例如,可以将重要的进程设置为高优先级,以确保它们能够获得足够的资源。
  5. 使用性能监测工具:性能监测工具可以帮助用户实时监测系统的性能状况,并提供相应的优化建议。例如,可以使用Windows自带的任务管理器或第三方性能监测工具来监控系统的CPU、内存、磁盘等性能指标。
  6. 定期进行系统维护:定期进行系统维护可以清理系统垃圾文件、修复系统错误、更新系统补丁等,从而提高系统的稳定性和性能。例如,可以定期进行磁盘碎片整理、注册表清理、病毒扫描等操作。
玄明Hanko:性能优化中的拆分与合并:你一定想不到这两个操作竟然可以这样玩


作为公司的架构师或者程序员,你是否曾经为公司的系统在面对高并发和性能瓶颈时感到手足无措或者焦头烂额呢?笔者在出道那会为此是吃尽了苦头的,不过也得感谢这段苦,让笔者从头到尾去探索,找寻解决之法。

今天就结合自己的经验,带你踏上一段神奇之旅,探索高并发与性能优化的秘密。我们将一起穿越技术的迷雾,揭示那些隐藏在代码背后的魔法,助你构建稳定可靠的系统应用!

高并发环境下,用户不耐烦的等待时间就像一道坚固的墙。为了突破这道障碍,我们可以施展异步处理的魔法。将耗时的操作转化为异步任务,让系统能同时处理更多请求,提高并发能力。还有神奇的缓存技术,通过减少对后端资源的频繁访问,加速系统的响应速度,像是给应用注入了快进的魔力。

在高并发的战场上,资源的争夺可是一场惨烈的战斗。为了保护宝贵的资源不被耗尽,我们可以借助锁机制、线程池和消息队列等技巧,有效地控制并发访问,防止资源的过度竞争和系统的崩溃。就像是聪明的指挥官,合理调度战力,稳定前线。

在信息的海洋中,数据库常常是一个令人头疼的瓶颈。但是别灰心!我们可以用缓存技术打破这个限制。将常用的数据存储在缓存中,避免频繁访问数据库,就像是给系统搭建了一个高速通道,让数据瞬间传送到用户面前。同时,设置合理的缓存策略,让缓存变得更加智能,提升系统的性能和吞吐量。

当用户涌入你的应用,你是否感到无法承受之重?别害怕!负载均衡技术就是你的救命稻草。通过将请求分发到多个服务器上,平衡系统的负载,提升系统的并发处理能力。就像是魔法师的魔法阵,将能量分散,使系统保持平衡与稳定。

在高并发的舞台上,数据的一致性常常被忽视。但是小心!一不小心,数据的错乱就会引发巨大的灾难。这时,事务机制和锁机制就是你的魔法武器。通过合理使用事务和锁,保证并发操作的数据一致性,让数据变得安全可靠。

在这段神奇的旅程中,我们一起揭开了高并发与性能优化的神秘面纱。从异步处理的加速法术到资源的守护者并发控制技巧,再到缓存奇迹和负载均衡的魔法仪式,最后以数据的魔法魅力作为压轴大结局。希望这些技巧和魔法能够帮助你构建稳定可靠的系统应用,并成为技术的英雄!记住,只要勇敢地迈出第一步,就能够超越困难,成就非凡!


成功的前端工程师很会善用工具,这些年低代码概念开始流行,像国外的 Mendix,国内的 JNPF,这种新型的开发方式,图形化的拖拉拽配置界面,并兼容了自定义的组件、代码扩展,确实在 B 端后台管理类网站建设中很大程度上的提升了效率。

开源地址:JNPF体验中心

代码量少,系统的稳定性和易调整性都会得到一定的保障。基于代码生成器,可一站式开发多端使用 Web、Android、IOS、微信小程序。代码自动生成后可以下载本地,进行二次开发,有效提高整体开发效率。同时,支持多种云环境部署、本地部署给予最大的安全保障,可以快速搭建适合自身应用场景的产品。

系统性能优化,一直是程序员从初级通向高阶的必修课,也是在面试中被重点考查的点。

下图是我基于对性能优化的理解,梳理出来的五大方向和对应的16种策略:

下面我们就来一一进行讲解。

预计算是一种“笨鸟先飞”的思想,与之相对应的是实时计算。

实时计算:当用户请求到来的时候,才进行数据的结果计算。

预计算:在用户请求到来之前,先将结果计算好,并保存在缓存或数据库中。当用户触发请求的时候,直接返回准备好的结果。

预计算的优缺点非常分明,其优点是性能足够高。缺点是,可能数据结果为非实时数据,存在时延性,也可能是技术方案比较复杂。

预计算的另外需要考虑的点是:结果命中率和计算范围,也就是说,我们希望结果命中率越高越好,而计算范围越小越好。因为计算范围越大,计算的周期就越长,对硬件存储的消耗也就越大。

预计算又可以分为全量预计算和存量预计算 + 增量即席计算两种。

全量预计算

假设如下场景,我们计算一张销售报表:

报表中的内容为这家企业季度销售情况,如果用全量预计算的方式,我们按照前图的方式,通过每十分钟跑一次定时任务,将页面上的几十个业务汇总指标全部计算一遍,然后存储到MySQL或Redis中,等待前端请求调用。

这种方式叫全量预计算,代码实现简单,可能一条复杂大SQL就能搞定,但如果数据量特别庞大,可能会出现执行时间很长,甚至跑不出来结果的情况。

存量预计算 + 增量即席计算

还是以上图的销售报表为例,假设今天为12月15日,那么前三个季度的销售额已经是不可变的存量数据了,我们只需要预计算一次,并将它存储到MySQL或Redis中即可,不用每次跑任务都进行计算。

接下来我们再说说第四个季度,其实12月14日及以前的销售额也是不可变的存量数据,我们一样可以将它存储下来以作备用。

这时,当前端的请求发送过来,我们只需要即席计算12月15日的销售额数据,然后再跟12月14日及以前的销售额数据进行累加,即可得出实时的第四季度销售额数据。

另外一个问题是,在什么时间点进行存量数据累加,比较常见的做法是,每天的0点跑定时任务,把前一天的全天销售数据累加进之前存量数据中。

这种方式叫存量预计算 + 增量即席计算,同时兼备高性能和实时性的优点,唯一的缺点就是技术方案相对复杂。

总之,预计算场景非常适合于对数据时延性要求不高的统计分析场景。

与并行计算相对应的是串行计算。

并行计算的所体现的思想是“人多力量大,众人拾柴火焰高”,旨在通过将任务拆解后,以多路并行的方式,将任务执行的总时长进行缩短,以达到提升性能的目的。

其中,并行计算又可以分为:单机多线程并行计算、集群并行计算和集群并行 + 单机多线程并行计算。

单机多线程并行计算

目前Java的JUC包中有很多非常好用的工具类,如:ThreadPoolExecutor、ForkJoinPool、newFixedThreadPool、newCachedThreadPool、CountDownLatch、CyclicBarrier、Phaser、CompletableFuture等。

我们假设给大量用户进行短信发送的场景,newFixedThreadPool示例如下:

package com.example.demo;

import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class MessageSender{
    public static void main(String[]args){

        List<String> userList=List.of("张一", "张二", "张三", "张四", "张五", "张六", "张七", "张八", "张九", "张十",
                "王一", "王二", "王三", "王四", "王五", "王六", "王七", "王八", "王九", "王十");

        ExecutorService executorService=Executors.newFixedThreadPool(5);
        for (String user : userList){
            executorService.execute(new Task(user));
        }
        executorService.shutdown();
    }
}

class Task implements Runnable{

    private String user;

    public Task(String user){
        this.user=user;
    }

    public void run(){
        System.out.println("调用发送短信SDK,给用户" + user + "发短信。");
    }
}

用CompletableFuture电商下单的前置校验场景:

package com.example.demo;

import java.util.concurrent.*;

public class Order{

    public static void main(String[]args) throws ExecutionException, InterruptedException{

        CompletableFuture<String> basicCheck=CompletableFuture.supplyAsync(() ->{
            try{
                Thread.sleep(1000);
            }catch (InterruptedException e){
                throw new RuntimeException(e);
            }
            return "基本信息校验";
        });

        CompletableFuture<String> riskControlCheck=CompletableFuture.supplyAsync(() ->{
            try{
                Thread.sleep(2000);
            }catch (InterruptedException e){
                throw new RuntimeException(e);
            }
            return "风控信息校验";
        });

        CompletableFuture<String> result=CompletableFuture.allOf(basicCheck, riskControlCheck).thenApply(res ->{
            return basicCheck.join() + "和" + riskControlCheck.join();
        });

        System.out.println("订单完成" + result.join() + ",可以正式下单了。");
    }
}

除此之外,Java 1.8的stream中的并行流模式——parallelStream(),也是一种不错的选择。

我们还是假设给大量用户进行短信发送的场景:

import java.util.List;

public class MessageSender{
    public static void main(String[]args){

        List<String> userList=List.of("张一", "张二", "张三", "张四", "张五", "张六", "张七",
                "张八", "张九", "张十", "王一", "王二", "王三", "王四", "王五", "王六", "王七", "王八", "王九", "王十");

        userList.parallelStream().forEach((entry) ->{
            System.out.println("调用发送短信SDK,给用户" + entry + "发短信。");

        });
    }
}


集群并行计算

大家可能不太清楚,单机多线程并行计算和集群并行计算各自的适用场景,我这里先来解释一下。

单机多线程并行计算场景,适用于用户触发请求的短时间执行场景,而集群并行计算场景,则适用于后台定时任务的长时间处理场景。

原因在于,在集群模式下,如果其中的一台服务器,以单机多线程模式长时间处理任务,容易出现硬件资源消耗倾斜的情况,再加上还要处理业务请求,容易使其成为集群中的性能瓶颈点。

集群并行计算模式,可以使用XXL-JOB分布式任务调度平台的分片广播模式进行实现。

其实现核心原理为,通过XXL-JOB的调度器,往执行器集群中的每个节点都发送一个请求,然后各节点通过自己不同的shardIndex来执行不同的任务。

代码如下:

@XxlJob("broadcastJob")
public void broadcastJob(){
    int shardCount=10; // 分片总数
    int shardIndex=XxlJobHelper.getShardIndex(); // 当前分片项

    // 执行任务逻辑
    for (int i=1; i <=全部任务ID; i++){
        if (i % shardCount==shardIndex){
            // 当前分片项需要执行的任务逻辑
            System.out.println("分片 " + shardIndex + "负责执行任务" + i);
        }
    }
}

集群并行 + 单机多线程并行计算

这个不用过多解释,相当于前两种模式的集合,适用于将该集群作为特定的任务服务器,并将计算能力拉满的情况。

常见的大数据框架:Flink、Spark、Storm都是使用的这种方式。

总之,并行计算场景非常适合于,可将一个大任务拆解成若干个小任务,且各任务间没有先后依赖关系的场景。

本期我们介绍了常见的两种性能优化方向,预计算和并行计算,以及对应的五种策略,后面几篇再跟大家介绍异步计算、存储系统优化和其他算法优化。

最后,再给知友们来一波福利

本人在之前看机会的时候,也从网上找遍了各式各类的八股文资料,但总觉得答案还不够准确,深度还有所欠缺,或是内容组织的逻辑性还不够清晰。

于是,我便自己动手,丰衣足食地自己总结了一套博采众家之长的八股文,那可真是字字斟酌,题题验证。

btw:该八股文除了场景题之外,还包括Java基础、Spring生态、MyBatis、MySQL、JVM、Redis、Kafka、RocketMQ、Dubbo、操作系统和网络、Netty、Doris、ClickHouse,以及一些非常高频的场景题,非常全面。

现在,我“大公无私”地把它分享出来,希望更多的同学可以由此受益。

Java技术栈的经典八股文

最后,祝大家工作顺利,纵情向前,人人都能收获自己满意的offer。


平台注册入口