当前位置: 首页 > news >正文

Aws S3上传优化

上传大约 3.4GB 的 JSON 文件,zip算法压缩后约为 395MB,上传至 S3 效率优化,有一些优化方案可以提高上传速率。下面是几种可能的优化方式,包括选择压缩算法、调整上传方式、以及其他可能的方案。

方案

1. 选择更好的压缩算法

压缩算法直接影响压缩比率和压缩/解压速度。对于你的数据,考虑到是 JSON 文件,可以尝试以下几种压缩算法:

a. Zstandard (zstd)
  • 特点:Zstandard 是一种高效的压缩算法,提供 更高的压缩比率更快的压缩/解压速度。它是目前最受欢迎的压缩算法之一,尤其适用于需要平衡压缩比和速度的场景。
  • 优势
    • 高压缩比:相比于 gzip 或 bzip2,Zstd 可以提供更高的压缩比。
    • 压缩速度:Zstd 提供了非常快的压缩速度,甚至在高压缩比时也能保持较快速度。
    • 支持字典压缩:Zstd 可以针对特定类型的数据(如 JSON)使用预训练的字典,以进一步提高压缩比。
  • 如何使用
    • 使用 zstd 工具压缩 JSON 文件,或者使用如 java-zstd 之类的 Java 库。
    • zstd 中,你可以通过调整压缩级别来平衡压缩率与速度,通常 level 19 以上会提供最优的压缩比。
b. Brotli
  • 特点:Brotli 是 Google 开发的压缩算法,通常压缩比率较高,但速度稍慢于 Zstd。
  • 优势
    • 高压缩比:Brotli 提供非常高的压缩比,尤其适合文本类文件(如 JSON)。
    • 支持 HTTP 压缩:在 web 应用中,Brotli 是一种推荐的压缩算法,适用于 HTTP 传输压缩。
  • 如何使用
    • 如果你关注最大压缩比,可以使用 Brotli,但可能会牺牲一定的速度。
    • Java 可以通过 brotli-java 库进行压缩。
c. Gzip
  • 特点:Gzip 是最常用的压缩格式,虽然压缩比和速度比 Zstd 和 Brotli 稍逊,但仍然是一个广泛应用的标准。
  • 优势
    • 高度兼容:几乎所有的工具和平台都支持 Gzip。
    • 较快的压缩速度,适合流式处理。
  • 如何使用
    • Gzip 可以通过 Java 的 java.util.zip.GZIPOutputStream 进行压缩,通常选择适中级别的压缩。
d. LZ4
  • 特点:LZ4 是一个超高速的压缩算法,压缩比不如 Zstd 或 Brotli 高,但它提供了极快的压缩和解压速度,适用于需要高吞吐量的场景。
  • 优势
    • 非常快的压缩/解压速度。
    • 适用于实时数据传输或非常频繁的压缩操作。

如何使用

- 适用于流式处理,如果你对上传时间有非常高的要求,可以考虑使用 LZ4。

2. 上传优化方案

压缩文件的上传到 S3,除了压缩算法外,上传方式也会影响性能。以下是一些优化上传速率的建议:

a. 分块上传(Multipart Upload)

对于大文件(如你 395MB 的压缩包),使用 S3 的 Multipart Upload 可以显著提高上传速度。

  • 分块上传:将大文件分割成多个较小的块(如 5MB 或更大的块),每个块并行上传,然后在服务器端合并。这种方式可以显著提高上传速率,尤其是网络带宽受限时。
  • 并行上传:上传多个文件或文件块时,确保使用多线程或并行任务来提升上传速率。
b. 优化 S3 配置
  • 选择合适的 S3 存储类型:对于频繁访问的文件,选择 S3 Standard 存储类型;对于长期存储不频繁访问的数据,可以选择 S3 GlacierS3 Intelligent-Tiering,这样能进一步优化成本。
  • 上传的区域选择:确保将文件上传至与用户或服务最接近的 AWS 区域。不同区域的网络带宽不同,选择一个低延迟、高带宽的区域将有助于提升上传速度。
c. 使用 AWS SDK 或 AWS CLI 上传
  • AWS SDK:使用 AWS 提供的 SDK(如 AWS SDK for Java)进行分块上传可以帮助管理并发任务,提升上传效率。
  • AWS CLI:如果使用命令行,aws s3 cpaws s3 sync 命令本身就支持分块上传,并且能自动优化上传过程。
aws s3 cp largefile.zip s3://yourbucket/ --storage-class STANDARD_IA --sse AES256 --multipart-chunk-size-mb 10
d. 压缩时减少冗余

在压缩时,尽量去除 JSON 文件中的冗余数据(如空格、换行符等),以便达到更高的压缩比。你可以在压缩前通过工具(如 jq)将 JSON 格式化处理为一个最小的单行格式。

cat *.json | jq -c . > compressed.json

3. 硬件和网络优化

  • 网络带宽:上传文件的速度受限于你服务器或本地网络的上传带宽。如果可能,尝试优化网络连接(例如使用更快的上传链路、避免网络瓶颈)。
  • 硬盘读写速度:确保压缩文件时,硬盘读写性能足够好,特别是使用 SSD 而非机械硬盘,以避免磁盘 I/O 成为瓶颈。

4. 云端优化

如果你通过中间服务器上传至 S3,考虑使用 AWS Direct Connect 或与 AWS 区域直接连接的高速网络线路,以避免互联网带宽限制。

5. 总结

  • 压缩算法选择:Zstandard(zstd)在提供高压缩比和高速压缩性能之间有很好的平衡,适合用于此类文件压缩。
  • 分块上传:通过 S3 的 Multipart Upload 功能,并行上传大文件,能显著提高上传速率。
  • 工具和网络优化:使用 AWS SDK、CLI,或者在压缩文件时去除冗余,进一步提升效率。

根据这些方案,你可以显著提升文件上传至 S3 的速度和效率。

实践

Apache Commons Compress

依赖

  • Maven:
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-compress</artifactId><version>1.21</version>
</dependency>

压缩文件

首先,我们通过 CompressorStreamFactory 来根据指定的压缩算法(如 Brotli)压缩文件。

import org.apache.commons.compress.compressors.CompressorStreamFactory;
import org.apache.commons.compress.compressors.CompressorOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;public class CompressionExample {public static void main(String[] args) {String inputData = "This is some sample text to be compressed using Brotli.";String outputFile = "output.br";  // 输出为 Brotli 压缩文件try {// 创建输出流OutputStream fileOutputStream = new FileOutputStream(outputFile);CompressorStreamFactory factory = new CompressorStreamFactory();// 动态选择压缩算法(Brotli)try (CompressorOutputStream compressorOutputStream = factory.createCompressorOutputStream("brotli", fileOutputStream)) {compressorOutputStream.write(inputData.getBytes());// 文件流之间复制// 使用 IOUtils 工具类将输入流的数据写入到压缩输出流// IOUtils.copy(fileInputStream, lz4OutputStream);}System.out.println("File compressed to: " + outputFile);} catch (IOException | org.apache.commons.compress.compressors.CompressorException e) {e.printStackTrace();}}
}

解压缩文件

对于解压缩操作,我们使用 CompressorStreamFactory 来自动选择与压缩时相同的解压缩算法,并解压文件。

import org.apache.commons.compress.compressors.CompressorStreamFactory;
import org.apache.commons.compress.compressors.CompressorInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;public class DecompressionExample {public static void main(String[] args) {String inputFile = "output.br";  // 输入为 Brotli 压缩文件String outputFile = "decompressed.txt";  // 解压后的文件try {// 创建输入流InputStream fileInputStream = new FileInputStream(inputFile);CompressorStreamFactory factory = new CompressorStreamFactory();// 动态选择解压缩算法(Brotli)try (CompressorInputStream compressorInputStream = factory.createCompressorInputStream("brotli", fileInputStream)) {int byteRead;StringBuilder decompressedData = new StringBuilder();// 读取解压缩后的数据while ((byteRead = compressorInputStream.read()) != -1) {decompressedData.append((char) byteRead);}// 输出解压缩数据System.out.println("Decompressed data: " + decompressedData.toString());}} catch (IOException | org.apache.commons.compress.compressors.CompressorException e) {e.printStackTrace();}}
}

其他类库

zstd

要在 Java 中使用 Zstandard (zstd) 进行压缩和解压缩,你可以使用第三方库,例如 zstd-jni,它是一个基于 JNI 的 Java 实现,允许你在 Java 中高效地使用 Zstandard 算法。

1. 添加依赖

如果你使用的是 Maven,可以在 pom.xml 中添加以下依赖:

<dependency><groupId>com.github.luben</groupId><artifactId>zstd-jni</artifactId><version>1.5.2-1</version>
</dependency>

2. Zstandard 压缩与解压缩案例

以下是一个简单的 Java 示例,展示如何使用 zstd-jni 进行文件的压缩和解压缩。

a. 压缩文件
import com.github.luben.zstd.ZstdOutputStream;import java.io.*;
import java.nio.file.Files;public class ZstdCompressExample {public static void main(String[] args) throws IOException {String inputFile = "input.json";String outputFile = "output.zst";// 创建输入文件流try (InputStream in = new FileInputStream(inputFile);OutputStream out = new FileOutputStream(outputFile);ZstdOutputStream zstdOut = new ZstdOutputStream(out)) {// 进行压缩byte[] buffer = new byte[8192];int bytesRead;while ((bytesRead = in.read(buffer)) != -1) {zstdOut.write(buffer, 0, bytesRead);}}System.out.println("File compressed successfully: " + outputFile);}
}
  • 解释
    • 通过 ZstdOutputStream 将输入文件流压缩后写入到输出文件中。
    • 使用 8KB 缓冲区来提高处理效率。
b. 解压缩文件
import com.github.luben.zstd.ZstdInputStream;import java.io.*;public class ZstdDecompressExample {public static void main(String[] args) throws IOException {String inputFile = "output.zst";String outputFile = "decompressed.json";// 创建输入文件流try (InputStream in = new FileInputStream(inputFile);ZstdInputStream zstdIn = new ZstdInputStream(in);OutputStream out = new FileOutputStream(outputFile)) {// 进行解压缩byte[] buffer = new byte[8192];int bytesRead;while ((bytesRead = zstdIn.read(buffer)) != -1) {out.write(buffer, 0, bytesRead);}}System.out.println("File decompressed successfully: " + outputFile);}
}
  • 解释
    • 通过 ZstdInputStream 读取压缩文件并解压,然后将解压后的数据写入输出文件中。

3. 压缩和解压缩字节数组(内存中的数据)

如果你不想直接操作文件,也可以对字节数组进行压缩和解压缩。

a. 压缩字节数组
import com.github.luben.zstd.Zstd;import java.io.IOException;
import java.util.Arrays;public class ZstdByteArrayCompressExample {public static void main(String[] args) throws IOException {byte[] inputData = "This is a sample data to be compressed.".getBytes();// 使用 Zstandard 压缩字节数组byte[] compressedData = Zstd.compress(inputData);System.out.println("Original size: " + inputData.length);System.out.println("Compressed size: " + compressedData.length);}
}
b. 解压缩字节数组
import com.github.luben.zstd.Zstd;import java.io.IOException;public class ZstdByteArrayDecompressExample {public static void main(String[] args) throws IOException {byte[] compressedData = "This is a sample data to be compressed.".getBytes(); // 假设这已经是压缩过的数据// 使用 Zstandard 解压字节数组byte[] decompressedData = Zstd.decompress(compressedData, 1000);  // 1000 是最大预期大小System.out.println("Decompressed data: " + new String(decompressedData));}
}

4. 优化压缩级别

你还可以通过设置压缩级别来平衡压缩率和压缩速度。Zstandard 提供了多个级别(1 到 22),数字越大,压缩比越高,但速度较慢。

import com.github.luben.zstd.Zstd;import java.io.IOException;public class ZstdCompressExample {public static void main(String[] args) throws IOException {byte[] inputData = "This is a sample data to be compressed.".getBytes();// 使用级别 3 进行压缩byte[] compressedData = Zstd.compress(inputData, 3);System.out.println("Original size: " + inputData.length);System.out.println("Compressed size: " + compressedData.length);}
}

5. 总结

  • zstd-jni 是一个高效的 Zstandard 实现,适用于压缩和解压大文件或字节数组。
  • 压缩和解压过程支持文件和内存中的数据,灵活性较高。
  • 通过设置压缩级别,可以在压缩比和压缩速度之间找到平衡。
  • 你可以结合压缩和多线程来提升上传速度,尤其是在上传到 S3 这类云存储时。

通过这些方法,你可以在 Java 项目中高效地使用 Zstandard 来处理压缩和解压缩,提升数据传输效率。

Brotli

Google 的 Brotli Java 绑定可以通过 Brotli 官方提供的 Java 库来使用,它是由 Google 维护的,具有更活跃的社区支持和更多的更新。这个库是直接通过 com.google 包提供的,你可以使用它来进行 Brotli 压缩和解压缩。

下面是如何使用 Google 的 Brotli Java 绑定 来进行压缩和解压缩操作的示例。

1. 添加依赖

你可以通过以下方式将 Brotli 添加到你的项目中。

Maven

pom.xml 中添加依赖:

<dependency><groupId>com.google.code.findbugs</groupId><artifactId>jsr305</artifactId><version>3.0.2</version>
</dependency>
<dependency><groupId>com.google.brotli</groupId><artifactId>brotli</artifactId><version>1.7.0</version>
</dependency>

2. 使用 Brotli 进行压缩和解压缩

以下是压缩和解压缩文件的示例。

压缩数据
import com.google.brotli.encoder.BrotliOutputStream;import java.io.*;public class BrotliCompressExample {public static void main(String[] args) {String inputFilePath = "input.txt";  // 输入文件路径String outputFilePath = "output.br"; // 输出压缩文件路径try {// 读取输入文件File inputFile = new File(inputFilePath);byte[] inputData = readFile(inputFile);// 压缩数据byte[] compressedData = compress(inputData);// 将压缩数据写入输出文件writeFile(outputFilePath, compressedData);System.out.println("Compression complete: " + outputFilePath);} catch (IOException e) {e.printStackTrace();}}// 读取文件内容为字节数组public static byte[] readFile(File file) throws IOException {try (InputStream is = new FileInputStream(file);ByteArrayOutputStream buffer = new ByteArrayOutputStream()) {byte[] chunk = new byte[1024];int bytesRead;while ((bytesRead = is.read(chunk)) != -1) {buffer.write(chunk, 0, bytesRead);}return buffer.toByteArray();}}// 使用 Brotli 压缩数据public static byte[] compress(byte[] input) throws IOException {try (ByteArrayOutputStream baos = new ByteArrayOutputStream();BrotliOutputStream brotliOut = new BrotliOutputStream(baos)) {brotliOut.write(input);brotliOut.flush();return baos.toByteArray();}}// 写数据到文件public static void writeFile(String filePath, byte[] data) throws IOException {try (FileOutputStream fos = new FileOutputStream(filePath)) {fos.write(data);}}
}
解压缩数据
import com.google.brotli.decoder.BrotliInputStream;import java.io.*;public class BrotliDecompressExample {public static void main(String[] args) {String inputFilePath = "output.br";  // 输入文件路径(压缩文件)String outputFilePath = "decompressed.txt"; // 输出解压文件路径try {// 解压缩数据byte[] decompressedData = decompress(new File(inputFilePath));// 将解压缩的数据写入文件writeFile(outputFilePath, decompressedData);System.out.println("Decompression complete: " + outputFilePath);} catch (IOException e) {e.printStackTrace();}}// 使用 Brotli 解压缩数据public static byte[] decompress(File inputFile) throws IOException {try (InputStream is = new FileInputStream(inputFile);BrotliInputStream brotliIn = new BrotliInputStream(is);ByteArrayOutputStream baos = new ByteArrayOutputStream()) {byte[] buffer = new byte[1024];int bytesRead;while ((bytesRead = brotliIn.read(buffer)) != -1) {baos.write(buffer, 0, bytesRead);}return baos.toByteArray();}}// 写数据到文件public static void writeFile(String filePath, byte[] data) throws IOException {try (FileOutputStream fos = new FileOutputStream(filePath)) {fos.write(data);}}
}

3. 代码解析

  • 压缩BrotliOutputStream 用于压缩数据。你只需要通过 write() 将数据写入流中,然后使用 flush() 提交压缩的数据。
  • 解压缩BrotliInputStream 用于读取压缩数据并解压。数据通过 read() 方法被读取并解压到输出流中,最终可以通过 ByteArrayOutputStream 获取解压后的数据。
  • 文件操作:我们使用 FileInputStreamFileOutputStream 来处理文件的读取和写入。

4. 性能与配置

Brotli 算法提供了非常高效的压缩率,尤其适合用于 Web 内容压缩,但其压缩速度相对较慢。你可以调整压缩级别来平衡压缩率与性能:

  • 压缩级别:通过 BrotliOutputStream 构造函数的第二个参数设置压缩级别,范围是 0 到 11,0 表示最快但压缩率低,11 表示最慢但压缩率高。

示例:设置压缩级别为 5:

BrotliOutputStream brotliOut = new BrotliOutputStream(baos, 5);

5. 总结

Google 的 Brotli Java 绑定提供了 BrotliInputStreamBrotliOutputStream 类,分别用于解压和压缩 Brotli 格式的文件。这个库比 Brotli4j 更活跃,且得到了 Google 官方的支持。通过调整压缩级别,你可以在压缩率和速度之间找到合适的平衡。

LZ4

在 Java 中使用 LZ4 压缩算法,可以通过 lz4-java 库,它是一个对 LZ4 算法的 Java 实现。LZ4 以其超高速压缩和解压速度著称,适用于需要高吞吐量的场景。以下是如何在 Java 中使用 LZ4 来压缩和解压数据的完整示例。

1. 添加依赖

首先,确保将 lz4-java 添加到你的项目依赖中。

Maven

pom.xml 中添加以下依赖:

<dependency><groupId>net.jpountz.lz4</groupId><artifactId>lz4</artifactId><version>1.8.0</version>
</dependency>

2. 使用 LZ4 压缩和解压缩

以下是一个基本的示例,展示了如何使用 LZ4 压缩和解压缩文件内容。

压缩数据
import net.jpountz.lz4.LZ4BlockOutputStream;
import net.jpountz.lz4.LZ4Factory;import java.io.*;public class LZ4CompressExample {public static void main(String[] args) {String inputFilePath = "input.txt";  // 输入文件路径String outputFilePath = "output.lz4"; // 输出压缩文件路径try {// 读取输入文件File inputFile = new File(inputFilePath);byte[] inputData = readFile(inputFile);// 压缩数据byte[] compressedData = compress(inputData);// 将压缩数据写入输出文件writeFile(outputFilePath, compressedData);System.out.println("Compression complete: " + outputFilePath);} catch (IOException e) {e.printStackTrace();}}// 读取文件内容为字节数组public static byte[] readFile(File file) throws IOException {try (InputStream is = new FileInputStream(file);ByteArrayOutputStream buffer = new ByteArrayOutputStream()) {byte[] chunk = new byte[1024];int bytesRead;while ((bytesRead = is.read(chunk)) != -1) {buffer.write(chunk, 0, bytesRead);}return buffer.toByteArray();}}// 使用 LZ4 压缩数据public static byte[] compress(byte[] input) throws IOException {LZ4Factory factory = LZ4Factory.fastestInstance();ByteArrayOutputStream baos = new ByteArrayOutputStream();try (LZ4BlockOutputStream lz4Out = new LZ4BlockOutputStream(baos, factory.fastestCompressor())) {lz4Out.write(input);lz4Out.flush();}return baos.toByteArray();}// 写数据到文件public static void writeFile(String filePath, byte[] data) throws IOException {try (FileOutputStream fos = new FileOutputStream(filePath)) {fos.write(data);}}
}
解压缩数据
import net.jpountz.lz4.LZ4BlockInputStream;
import net.jpountz.lz4.LZ4Factory;import java.io.*;public class LZ4DecompressExample {public static void main(String[] args) {String inputFilePath = "output.lz4";  // 输入文件路径(压缩文件)String outputFilePath = "decompressed.txt"; // 输出解压文件路径try {// 解压缩数据byte[] decompressedData = decompress(new File(inputFilePath));// 将解压缩的数据写入文件writeFile(outputFilePath, decompressedData);System.out.println("Decompression complete: " + outputFilePath);} catch (IOException e) {e.printStackTrace();}}// 使用 LZ4 解压缩数据public static byte[] decompress(File inputFile) throws IOException {try (InputStream is = new FileInputStream(inputFile);LZ4BlockInputStream lz4In = new LZ4BlockInputStream(is)) {ByteArrayOutputStream baos = new ByteArrayOutputStream();byte[] buffer = new byte[1024];int bytesRead;while ((bytesRead = lz4In.read(buffer)) != -1) {baos.write(buffer, 0, bytesRead);}return baos.toByteArray();}}// 写数据到文件public static void writeFile(String filePath, byte[] data) throws IOException {try (FileOutputStream fos = new FileOutputStream(filePath)) {fos.write(data);}}
}

3. 代码解析

  • 压缩LZ4BlockOutputStream 用于将数据写入压缩流。你可以通过传入 LZ4Factory.fastestCompressor() 来选择最快的压缩器。压缩后的字节数据可以被写入到 ByteArrayOutputStream,并最终得到压缩后的数据。
  • 解压缩LZ4BlockInputStream 用于从压缩流中读取数据并进行解压。读取后,数据会被写入到 ByteArrayOutputStream,最终得到解压后的字节数据。
  • 性能:LZ4 是一种非常快速的压缩算法,它优化了 CPU 使用率,并且能够在压缩速度和压缩比之间取得较好的平衡。fastestCompressor() 是最快的压缩方法,适用于需要快速压缩的场景。

4. 压缩级别

LZ4 并不像其他压缩算法(如 Zstd)那样支持多个压缩级别。它的设计重点是压缩速度,因此它的压缩速度相对较快,但压缩比没有像 Zstd 那么高。如果你需要更高的压缩比,Zstd 或 Brotli 可能更适合。不过,对于需要极快压缩/解压速度的场景,LZ4 是一个非常好的选择。

5. 总结

  • LZ4 的特点:LZ4 是一个高性能、低延迟的压缩算法,适合处理对速度要求较高的场景,尤其是流式数据和大数据处理。
  • 压缩方式:Java 中通过 LZ4BlockOutputStreamLZ4BlockInputStream 来处理文件压缩与解压缩。对于内存中的字节数组,可以使用 LZ4CompressorLZ4FastDecompressor
  • 性能:LZ4 提供了非常快的压缩和解压缩速度,虽然压缩比相对较低,但仍适合用于大部分实时应用场景。

通过这种方式,你可以在 Java 中高效地使用 LZ4 压缩和解压缩数据,提升数据传输和存储的效率。

S3分块上传

分块上传(Multipart Upload)是 Amazon S3 的一个功能,允许将大文件分为多个部分进行上传,从而提高上传效率,并支持在上传过程中断点续传。在 AWS SDK for Java 中,你可以使用 TransferManager 来实现分块上传,或者使用 AmazonS3 提供的原生 initiateMultipartUpload 方法进行自定义实现。

分块上传的步骤

  1. 初始化上传:调用 initiateMultipartUpload 方法开始一个分块上传操作。
  2. 上传各个部分:将文件分割成多个块并上传。
  3. 完成上传:调用 completeMultipartUpload 来完成上传。

使用 AWS SDK for Java 实现分块上传的示例

1. Maven 依赖

确保你的 Maven 项目中包含了 AWS SDK for Java 的相关依赖:

<dependency><groupId>com.amazonaws</groupId><artifactId>aws-java-sdk-s3</artifactId><version>2.20.1</version> <!-- 请使用最新版本 -->
</dependency>

2. 分块上传代码示例

下面是一个分块上传的代码示例,使用 AmazonS3TransferManager 进行分块上传。

import com.amazonaws.AmazonServiceException;
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.*;import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;public class S3MultipartUpload {private static final String BUCKET_NAME = "your-bucket-name"; // 目标S3桶名private static final String OBJECT_KEY = "your-object-key"; // 目标文件在S3的键(路径)public static void main(String[] args) throws IOException {// 初始化AmazonS3客户端AmazonS3 s3Client = AmazonS3ClientBuilder.standard().withCredentials(new ProfileCredentialsProvider()) // 使用配置文件中的凭证.build();// 文件路径File file = new File("path-to-large-file");// 分块大小,5MB是最小的分块大小long partSize = 5 * 1024 * 1024; // 获取文件大小long fileSize = file.length();// 初始化分块上传InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(BUCKET_NAME, OBJECT_KEY);InitiateMultipartUploadResult initResponse = s3Client.initiateMultipartUpload(initRequest);String uploadId = initResponse.getUploadId();// 按照分块大小分割文件并上传List<PartETag> partETags = new ArrayList<>();try {// 分块上传for (long i = 0; i < fileSize; i += partSize) {long size = Math.min(partSize, fileSize - i);UploadPartRequest uploadRequest = new UploadPartRequest().withBucketName(BUCKET_NAME).withKey(OBJECT_KEY).withUploadId(uploadId).withPartNumber((int) (i / partSize) + 1).withFileOffset(i).withFile(file).withPartSize(size);// 上传分块UploadPartResult uploadPartResult = s3Client.uploadPart(uploadRequest);partETags.add(uploadPartResult.getPartETag());System.out.println("Uploaded part " + (i / partSize + 1));}// 完成上传CompleteMultipartUploadRequest completeRequest = new CompleteMultipartUploadRequest(BUCKET_NAME, OBJECT_KEY, uploadId, partETags);s3Client.completeMultipartUpload(completeRequest);System.out.println("File uploaded successfully!");} catch (AmazonServiceException e) {// 如果上传失败,取消上传s3Client.abortMultipartUpload(new AbortMultipartUploadRequest(BUCKET_NAME, OBJECT_KEY, uploadId));e.printStackTrace();}}
}

3. 代码说明

  • 初始化上传(**initiateMultipartUpload**:通过 InitiateMultipartUploadRequest 创建一个新的上传任务,并返回一个 uploadId,这个 ID 用于后续分块上传和完成上传。
  • 分块上传(**uploadPart**:通过 UploadPartRequest 来上传每个文件块。withFileOffset 表示文件上传的起始偏移位置,withPartSize 用于指定每个块的大小。
  • 完成上传(**completeMultipartUpload**:所有部分上传成功后,使用 CompleteMultipartUploadRequest 来完成分块上传,所有上传的部分会被合并成一个完整的文件。
  • 错误处理(**abortMultipartUpload**:在上传过程中如果发生异常(例如服务端错误),我们调用 abortMultipartUpload 来取消上传,并清理资源。

4. 注意事项

  • 分块大小:AWS 对分块上传有一定的要求。每个部分必须至少为 5MB,最后一个部分可以小于 5MB。可以根据文件的大小选择合理的分块大小。
  • 上传过程中的错误:如果上传失败,记得调用 abortMultipartUpload 来中止上传,避免留下未完成的部分。
  • 凭证管理:本示例使用了 ProfileCredentialsProvider,你也可以选择其他凭证提供方式,例如环境变量或硬编码凭证,但不推荐硬编码。

5. **更高效的方式:使用 ****TransferManager**

对于一些应用场景,你可以使用 TransferManager 进行更加高效和便捷的分块上传。TransferManager 是 AWS SDK 提供的高级 API,自动处理分块上传和下载、进度报告等功能。以下是使用 TransferManager 实现分块上传的示例:

使用 TransferManager 实现分块上传
import com.amazonaws.auth.profile.ProfileCredentialsProvider;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.*;
import com.amazonaws.services.s3.transfer.TransferManager;
import com.amazonaws.services.s3.transfer.Upload;import java.io.File;public class TransferManagerExample {private static final String BUCKET_NAME = "your-bucket-name";private static final String OBJECT_KEY = "your-object-key";public static void main(String[] args) {// 初始化S3客户端和TransferManagerAmazonS3 s3Client = AmazonS3ClientBuilder.standard().withCredentials(new ProfileCredentialsProvider()).build();TransferManager transferManager = TransferManagerBuilder.standard().s3Client(s3Client).build();// 创建文件对象File file = new File("path-to-large-file");// 开始分块上传Upload upload = transferManager.upload(BUCKET_NAME, OBJECT_KEY, file);try {// 等待上传完成upload.waitForCompletion();System.out.println("Upload completed!");} catch (Exception e) {e.printStackTrace();}}
}

在这个示例中,TransferManager 会自动处理文件分割、上传和合并的工作,你不需要手动拆分文件和上传每一部分。

6. 总结

  • 分块上传:AWS S3 提供了分块上传功能,适用于上传大文件。你可以使用 AmazonS3 的原生方法或者 TransferManager 来简化这个过程。
  • **TransferManager**:是 AWS SDK 提供的更高层次的 API,简化了分块上传的过程,自动处理了上传任务和块的管理。
  • 错误处理:上传过程中如果发生异常,记得调用 abortMultipartUpload 来清理未完成的上传任务。

选择哪种方式取决于你的需求,如果你需要更多控制和自定义分块上传的行为,可以使用 AmazonS3 的原生方法;如果你希望快速实现且自动处理所有细节,TransferManager 是一个更方便的选择。

API选择建议

文件大小

  • 小文件(<100MB):S3 SDK 原生 API。
  • 中型文件(100MB~500MB):S3 Transfer Manager,享受分块传输的性能优化。
  • 大文件(>500MB):Transfer Manager 或者 AWS CLI。

性能对比

工具适用范围优势劣势
S3 Transfer Manager100MB~GB+并发传输、分块优化、高效、异步支持需要更多依赖,初始化稍复杂
原生 S3 API小于 500MB简单直接,无需额外配置无分块传输,性能有限
AWS CLI小型/大型文件易用,后台优化传输性能需要使用命令行,无法嵌入 Java 项目

相关文章:

Aws S3上传优化

上传大约 3.4GB 的 JSON 文件&#xff0c;zip算法压缩后约为 395MB&#xff0c;上传至 S3 效率优化&#xff0c;有一些优化方案可以提高上传速率。下面是几种可能的优化方式&#xff0c;包括选择压缩算法、调整上传方式、以及其他可能的方案。 方案 1. 选择更好的压缩算法 压…...

Python 数据智能实战 (8):基于LLM的个性化营销文案

写在前面 —— 告别群发轰炸,拥抱精准沟通:用 LLM 为你的用户量身定制营销信息 在前面的篇章中,我们学习了如何利用 LLM 增强用户理解(智能分群)、挖掘商品关联(语义购物篮)、提升预测精度(融合文本特征的流失预警)。我们不断地从数据中提取更深层次的洞察。 然而,…...

html:table表格

表格代码示例&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title> </head> <body><!-- 标准表格。 --><table border"5"cellspacing&qu…...

2.maven 手动安装 jar包

1.背景 有的时候&#xff0c;maven仓库无法下载&#xff0c;可以手动安装。本文以pentaho-aggdesigner-algorithm-5.1.5-jhyde.jar为例。 2.预先准备 下载文件到本地指定位置。 2.1.安装pom mvn install:install-file \-Dfile/home/wind/tmp/pentaho-aggdesigner-5.1.5-jh…...

C++ unordered_set unordered_map

上篇文章我们讲解了哈希表的实现&#xff0c;这节尝试使用哈希表来封装unordered_set/map 1. unordered_set/map的框架 封装的过程实际上与set/map类似&#xff0c;在unordered_set/map层传递一个仿函数&#xff0c;用于取出key值 由于我们平常使用的都是unordered_set/map&…...

第37课 绘制原理图——放置离页连接符

什么是离页连接符&#xff1f; 前边我们介绍了网络标签&#xff08;Net Lable&#xff09;&#xff0c;可以让两根导线“隔空相连”&#xff0c;使原理图更加清爽简洁。 但是网络标签的使用也具有一定的局限性&#xff0c;对于两张不同Sheet上的导线&#xff0c;网络标签就不…...

< 自用文 Texas style Smoker > 美式德克萨斯烟熏炉 从设计到实现 (第一部分:烹饪室与燃烧室)

原因&#xff1a; 没钱还馋&#xff01; 但有手艺。 预计目标&#xff1a; 常见的两种偏置式烟熏炉&#xff08;Offset Smoker&#xff09; 左边边是标准偏置式&#xff08;Standard Offset&#xff09;&#xff0c;右边是反向流动式&#xff08;Reverse Flow Offset&#x…...

【现代深度学习技术】现代循环神经网络03:深度循环神经网络

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈PyTorch深度学习 ⌋ ⌋ ⌋ 深度学习 (DL, Deep Learning) 特指基于深层神经网络模型和方法的机器学习。它是在统计机器学习、人工神经网络等算法模型基础上&#xff0c;结合当代大数据和大算力的发展而发展出来的。深度学习最重…...

AimRT从入门到精通 - 03Channel发布者和订阅者

刚接触AimRT的小伙伴可能会疑惑&#xff0c;这个Channel和RPC&#xff08;后面讲的&#xff09;到底是什么呢&#xff1f; 但是当我们接触了之后&#xff0c;就会发现&#xff0c;其本质类似ROS的Topic通信&#xff01;&#xff08;其本质基于发布订阅模型&#xff09; 接下来…...

MySQL初阶:数据库基础,数据库和表操作,数据库中的数据类型

1.数据库基础 数据库是一个客户端——服务器结构的程序。 服务器是真正的主体&#xff0c;负责保存和管理数据&#xff0c;数据都存储在硬盘上 数据库处理的主要内容是数据的存储&#xff0c;查找&#xff0c;修改&#xff0c;排序&#xff0c;统计等。 关系型数据库&#…...

AI 驱动的智能交通系统:从拥堵到流畅的未来出行

最近研学过程中发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击链接跳转到网站人工智能及编程语言学习教程。读者们可以通过里面的文章详细了解一下人工智能及其编程等教程和学习方法。下面开始对正文内容的…...

Python清空Word段落样式的方法

在 Python 中&#xff0c;你可以使用 python-docx 库来操作 Word 文档&#xff0c;包括清空段落样式。以下是几种清空段落样式的方法&#xff1a; 方法一&#xff1a;直接设置段落样式为"Normal" from docx import Documentdoc Document(your_document.docx) # 打…...

[javaEE]网络编程

目录 socket对tcp ServerSocket ServerSocket 构造方法&#xff1a; ServerSocket 方法&#xff1a; socket 实现回显服务器和客户端 由于我们之前已经写多了socket对udq的实现&#xff0c;所以我们这节&#xff0c;主要将重心放在Tcp之上 socket对tcp ServerS…...

组件通信-mitt

mitt&#xff1a;与消息订阅与发布&#xff08;pubsub&#xff09;功能类似&#xff0c;可以实现任意组件间通信。 第一步&#xff1a;安装mitt npm i mitt 第二步&#xff1a;新建文件&#xff1a;src\utils\emitter.ts // 引入mitt import mitt from "mitt"; //调…...

微软发布了最新的开源推理模型套件“Phi-4-Reasoning

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…...

Socat 用法详解:网络安全中的瑞士军刀

Socat 用法详解&#xff1a;网络安全中的强大工具 引言 socat&#xff08;SOcket CAT&#xff09;是一款功能强大的命令行工具&#xff0c;被誉为“网络瑞士军刀”&#xff0c;广泛应用于数据传输、端口转发和网络调试等场景。它支持多种协议和数据通道&#xff08;如文件、管…...

精益数据分析(36/126):SaaS商业模式的指标动态与实践案例

精益数据分析&#xff08;36/126&#xff09;&#xff1a;SaaS商业模式的指标动态与实践案例 在创业与数据分析的学习道路上&#xff0c;我们不断探索各种商业模式的核心要点。今天&#xff0c;依旧怀揣着和大家共同进步的想法&#xff0c;深入研读《精益数据分析》中SaaS商业…...

2.LED灯的控制和按键检测

目录 STM32F103的GPIO口 GPIO口的作用 GPIO口的工作模式 input输入检测 -- 向内检测 output控制输出 -- 向外输出 寄存器 寄存器地址的确定 配置GPIO口的工作模式 时钟的开启和关闭 软件编程驱动 LED 灯 硬件 软件 软件编程驱动 KEY 按键 硬件 软件 按键消抖 代码 STM32F…...

架构师面试(三十八):注册中心架构模式

题目 在微服务系统中&#xff0c;当服务达到一定数量时&#xff0c;通常需要引入【注册中心】组件&#xff0c;以方便服务发现。 大家有没有思考过&#xff0c;注册中心存在的最根本的原因是什么呢&#xff1f;注册中心在企业中的最佳实践是怎样的&#xff1f;注册中心的服务…...

Go-web开发之帖子功能

帖子功能 route.go r.Use(middleware.JWTAuthMiddleware()){r.POST("/post", controller.CreatePostHandler)r.GET("/post/:id", controller.GetPostDetailHandler)}post.go 定义帖子结构 type Post struct {Id int64 json:"id" …...

MYSQL-设计表

一.范式 数据库的范式是⼀组规则。在设计关系数据库时&#xff0c;遵从不同的规范要求&#xff0c;设计出合理的关系型数 据库&#xff0c;这些不同的规范要求被称为不同的范式。 关系数据库有六种范式&#xff1a;第⼀范式&#xff08;1NF&#xff09;、第⼆范式&#xff08;…...

动态思维——AI与思维模型【91】

一、定义 动态思维思维模型是一种强调在思考问题和分析情况时&#xff0c;充分考虑到事物的变化性、发展性和相互关联性&#xff0c;不局限于静态的、孤立的视角&#xff0c;而是以发展变化的眼光看待事物&#xff0c;能够根据不同时间、环境和条件的变化&#xff0c;灵活调整…...

文献阅读篇#7:5月一区好文阅读,BFA-YOLO,用于建筑信息建模!(下)

期刊简介&#xff1a;《Advanced Engineering Informatics》创刊于2002年&#xff0c;由Elsevier Ltd出版商出版&#xff0c;出版周期Quarterly。该刊已被SCIE数据库收录&#xff0c;在中科院最新升级版分区表中&#xff0c;该刊分区信息为大类学科工程技术1区&#xff0c;2023…...

【Linux网络编程】http协议的状态码,常见请求方法以及cookie-session

本文专栏&#xff1a;Linux网络编程 目录 一&#xff0c;状态码 重定向状态码 1&#xff0c;永久重定向&#xff08;301 Moved Permanently&#xff09; 2&#xff0c;临时重定向&#xff08;302 Found&#xff09; 二&#xff0c;常见请求方法 1&#xff0c;HTTP常见Hea…...

ARM 指令集(ubuntu环境学习)第六章:ARM 编程技巧与优化策略

在本章中,我们将介绍一些在 ARM 架构上编写高效代码的技巧和常见优化策略,帮助您在嵌入式系统中获得更低延迟、更高吞吐和更低功耗。 6.1 寄存器利用与最小化内存访问 多用寄存器 ARM 通用寄存器(r0–r12)数量充足,尽量将临时变量保留在寄存器中,减少对内存的读写。 避免…...

柔性超声耦合剂的选择与设计-可穿戴式柔性超声耦合剂面临的难题

柔性PZT压电薄膜&#xff1a;破解可穿戴式超声耦合剂难题的关键材料&#xff01; 随着可穿戴技术的快速发展&#xff0c;超声设备正朝着轻量化、柔性化和高集成度方向演进。在医学诊断、健康监测和智能穿戴领域&#xff0c;可穿戴式超声设备因其无创、实时、动态成像等优势受到…...

XCTF-pwn(二)

guess_num 看一下文件信息 利用gets函数将seed[0]给覆盖掉 距离0x20 我们需要输入十次随机数产生的值 写一个c程序先预判当seed是a的时候产生的随机数分别是多少 payload from pwn import* from ctypes import* context.log_leveldebugrremote("61.147.171.105", 6…...

AI外挂RAG:大模型时代的检索增强生成技术

目录 引言 一、RAG是什么&#xff1f; 二、RAG为什么会出现&#xff1f; 三、RAG的工作原理 四、RAG的技术优势 五、RAG的应用场景 六、RAG对AI行业的影响 七、RAG面临的挑战 引言 在人工智能领域&#xff0c;大型语言模型&#xff08;LLM&#xff09;如ChatGPT、DeepSe…...

SpringTask

Spring Task是Spring框架提供的任务调度工具&#xff0c;可以按照约定的时间自动执行某个代码逻辑 应用场景&#xff1a;信用卡每月还款提醒、火车票售票系统处理未支付订单 fixedDelay&#xff1a;上一次任务执行完成后多长时间&#xff08;ms&#xff09;执行下一次任务 fixe…...

Sphinx 文档图片点击放大

文章目录 问题描述解决方案步骤 1&#xff1a;创建 JavaScript 文件步骤 2&#xff1a;编写 JavaScript 代码步骤 3&#xff1a;更新 Sphinx 配置 高级定制为所有图片添加点击功能添加缩放控制 总结 在使用 Sphinx 生成技术文档时&#xff0c;我们经常需要在文档中嵌入截图和示…...

菜鸟之路Day29一一MySQL之DDL

菜鸟之路Day29一一MySQL之DDL 作者&#xff1a;blue 时间&#xff1a;2025.5.2 文章目录 菜鸟之路Day29一一MySQL之DDL0.概述1.DDL之数据库操作1.1查询1.2创建1.3使用1.4删除 2.DDL之表操作2.1创建表2.2数据类型2.3查询表2.4修改表结构2.5删除表 0.概述 文章内容学习自黑马程…...

架构师面试(三十七):监控系统架构模式

题目 监控是在产品生命周期的运维环节&#xff0c;能对产品的关键指标数据进行【实时跟踪】并对异常数据进行【实时报警】。 一句话描述&#xff0c;监控系统可以帮我们【主动预防和发现】业务系统中的问题。 我们常说&#xff0c;监控系统是 “粮草”&#xff0c;业务系统是…...

【Redis】Hash哈希

文章目录 注意个问题hset命令&#xff08;核心&#xff09;hget命令&#xff08;核心&#xff09;hexists命令hdel命令hkeys和hvals命令hgetall和hmget命令hlen命令hsetnx命令hincrby命令哈希命令小结哈希编码方式使用场景1.关系型数据表保存用户的信息Redis三种缓存方式对比1.…...

【SpringBoot】Spring中事务的实现:声明式事务@Transactional、编程式事务

1. 准备工作 1.1 在MySQL数据库中创建相应的表 用户注册的例子进行演示事务操作&#xff0c;索引需要一个用户信息表 &#xff08;1&#xff09;创建数据库 -- 创建数据库 DROP DATABASE IF EXISTS trans_test; CREATE DATABASE trans_test DEFAULT CHARACTER SET utf8mb4;…...

从零开始讲DDR(9)——AXI 接口MIG 使用(2)

一、前言 在之前的文章中&#xff0c;我们介绍了官方DDR MIG AXI接口的例程的整体框架&#xff0c;在本文中&#xff0c;我们将着重介绍例程中关于数据产生&#xff0c;及驱动到AXI接口的相关逻辑实现。 二、data_gen 在例程中&#xff0c;有ddr4_v2_2_8_data_gen这样一个文件…...

组件通信-props

props 是使用频率最高的一种通信方式&#xff0c;父>子 子>父 父传子&#xff1a;属性值 是非函数子传父&#xff1a;属性值 是函数 父组件 <script setup lang"ts"> import { ref } from vue import Child from ./Child.vue const car ref(奥迪) c…...

纯原生Java实现:获取整个项目中指定接口所有的实现类

不使用第三方&#xff0c;不使用属性文件,不指定包名&#xff0c;获取整个系统中某一个接口所有的实现类&#xff0c;纯Java实现 /*** 类查找器&#xff0c;用于扫描类路径中的所有类&#xff0c;并找出指定类的实现类。* 该类通过递归扫描类路径下的所有 .class 文件&#xf…...

反射机制补充

不同对象实例的地址不同 在 Java 里&#xff0c;每当使用 new 关键字创建一个对象时&#xff0c;JVM 会在堆内存中为该对象分配一块新的内存空间&#xff0c;每个对象实例都有自己独立的内存地址。所以不同的对象实例&#xff0c;其内存地址是不同的。 以下是一个简单示例&am…...

计算机视觉的未来发展趋势

计算机视觉的未来发展趋势主要集中在以下几个方面&#xff1a; 1. 自监督学习与少样本学习 自监督学习&#xff1a;通过从无标签的数据中提取有用特征&#xff0c;克服对大量标注数据的依赖。2025年&#xff0c;基于大规模图像数据的自监督预训练模型将更加成熟&#xff0c;能…...

轻量级网页版视频播放器

用deepseek开发的轻量级&#xff0c;网页版视频播放器 可以选择本地文件 可以播放、暂停、全屏、有进度条和时间进度 代码如下&#xff1a; 新建.txt文本文档&#xff0c;把代码复制粘贴进去&#xff0c;把.txt文档后缀名改为.html&#xff0c;用浏览器打开即可使用 <!DO…...

18. LangChain分布式任务调度:大规模应用的性能优化

引言&#xff1a;从单机到万级并发的进化 2025年某全球客服系统通过LangChain分布式改造&#xff0c;成功应对黑五期间每秒12,000次的咨询请求。本文将基于LangChain的分布式架构&#xff0c;详解如何实现AI任务的自动扩缩容与智能调度。 一、分布式系统核心指标 1.1 性能基准…...

C/C++工程师使用 DeepSeek

一、使用 DeepSeek 生成 C/C 代码 在 C/C 开发中&#xff0c;很多时候需要编写一些常见功能的代码&#xff0c;如排序算法、文件读写操作、数据结构的实现等。借助 DeepSeek&#xff0c;工程师只需用自然语言清晰描述需求&#xff0c;它就能依据大量的代码数据和深度学习算法&a…...

数据结构-线性结构(链表、栈、队列)实现

公共头文件common.h #define TRUE 1 #define FALSE 0// 定义节点数据类型 #define DATA_TYPE int单链表C语言实现 SingleList.h #pragma once#include "common.h"typedef struct Node {DATA_TYPE data;struct Node *next; } Node;Node *initList();void headInser…...

第 7 篇:跳表 (Skip List):简单务实的概率性选手

前面几篇我们都在探讨各种基于“树”结构的有序表实现&#xff0c;它们通过精巧的平衡策略&#xff08;高度、颜色、大小&#xff09;和核心的“旋转”操作来保证 O(log N) 的性能。今天&#xff0c;我们要介绍一位画风完全不同的选手——跳表 (Skip List)。它不依赖树形结构&a…...

sys目录介绍

文章目录 1. 前言2. 目录层次3. 目录介绍3.1 devices 目录3.2 block 目录3.3 bus 目录3.4 class 目录3.5 dev 目录3.6 firmware目录3.7 fs 目录3.8 kernel目录3.9 module 目录3.10 power 目录 sys目录介绍 1. 前言 linux 下一切皆文件&#xff0c;文件的类型也很多&#xff0c;…...

基于DQN的自动驾驶小车绕圈任务

1.任务介绍 任务来源: DQN: Deep Q Learning &#xff5c;自动驾驶入门&#xff08;&#xff1f;&#xff09; &#xff5c;算法与实现 任务原始代码: self-driving car 最终效果&#xff1a; 以下所有内容&#xff0c;都是对上面DQN代码的改进&#…...

源码安装SRS4

Ubuntu20安装好SRS后&#xff0c;&#xff08;源码安装&#xff09; 注意&#xff1a;在trunk目录SRS ./objs/srs -c conf/srs.conf 以上为启动srs命令&#xff0c;-c 为指定配置文件&#xff0c; 查看SRS进程 ps aux | grep srs 查看端口&#xff1a; netstat -ano | gre…...

OrbitControls

OrbitControls 3D虚拟工厂在线体验 描述 Orbit controls&#xff08;轨道控制器&#xff09;可以使得相机围绕目标进行轨道运动。 Constructor OrbitControls( object : Camera, domElement : HTMLDOMElement ) 参数类型描述objectCamera&#xff08;必须&#xff09;将要…...

【数据库】四种连表查询:内连接,外连接,左连接,右连接

在数据库操作中&#xff0c;连表查询是处理多表关联的核心技术。以下是四种主要连接方式的详细介绍、快速掌握方法及实际应用指南&#xff1a; 目录 **一、四种连表查询详解****1. 内连接&#xff08;INNER JOIN&#xff09;****2. 左连接&#xff08;LEFT JOIN / LEFT OUTER J…...

Redis怎么避免热点数据问题

使用 RedisTemplate 避免热点数据问题的解决方案、场景及示例&#xff1a; 1. 数据分片&#xff08;Sharding&#xff09; 场景&#xff1a;高频读写的计数器&#xff08;如文章阅读量统计&#xff09; ​原理​&#xff1a;将数据分散到多个子键&#xff0c;降低单个 Key 的压…...