This is an automated email from the ASF dual-hosted git repository.
morrySnow pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new ca30be14a5f [opt](audit) Compress audit log stream load payloads
(#68083)
ca30be14a5f is described below
commit ca30be14a5fa32ef837ead479a05f5c5e0b98489
Author: morrySnow <[email protected]>
AuthorDate: Thu Sep 17 11:05:57 2026 +0800
[opt](audit) Compress audit log stream load payloads (#68083)
### What problem does this PR solve?
Problem Summary:
The built-in audit loader currently sends every Stream Load batch as
uncompressed text. This PR gzip-compresses the request body and adds the
`compress_type: gz` Stream Load header, reducing network traffic for
audit batches. The optional external audit loader plugin is unchanged.
### Release note
Enable gzip compression for built-in audit log Stream Load requests.
---
.../doris/plugin/audit/AuditStreamLoader.java | 19 ++++--
.../doris/plugin/audit/AuditStreamLoaderTest.java | 67 ++++++++++++++++++++++
2 files changed, 82 insertions(+), 4 deletions(-)
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/plugin/audit/AuditStreamLoader.java
b/fe/fe-core/src/main/java/org/apache/doris/plugin/audit/AuditStreamLoader.java
index 73a78e7356e..ea8560a7653 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/plugin/audit/AuditStreamLoader.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/plugin/audit/AuditStreamLoader.java
@@ -33,16 +33,20 @@ import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
+import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
+import java.nio.charset.StandardCharsets;
import java.util.Calendar;
import java.util.stream.Collectors;
+import java.util.zip.GZIPOutputStream;
import javax.net.ssl.HttpsURLConnection;
public class AuditStreamLoader {
private static final Logger LOG =
LogManager.getLogger(AuditStreamLoader.class);
// timeout for both connection and read. 10 seconds is long enough.
private static final int HTTP_TIMEOUT_MS = 10000;
+ private static final String COMPRESS_TYPE = "gz";
private String db;
private String auditLogTbl;
private String auditLogLoadUrlStr;
@@ -58,7 +62,8 @@ public class AuditStreamLoader {
this.feIdentity =
Env.getCurrentEnv().getSelfNode().getIdent().replaceAll("\\.",
"_").replaceAll(":", "_");
}
- private HttpURLConnection getConnection(String urlStr, String label,
String clusterToken) throws IOException {
+ private static HttpURLConnection getConnection(
+ String urlStr, String label, String clusterToken) throws
IOException {
URL url = new URL(urlStr);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
if (conn instanceof HttpsURLConnection && Config.enable_https) {
@@ -73,6 +78,7 @@ public class AuditStreamLoader {
conn.addRequestProperty("Expect", "100-continue");
conn.addRequestProperty("Content-Type", "text/plain; charset=UTF-8");
conn.addRequestProperty("label", label);
+ conn.addRequestProperty("compress_type", COMPRESS_TYPE);
conn.setConnectTimeout(HTTP_TIMEOUT_MS);
conn.setReadTimeout(HTTP_TIMEOUT_MS);
conn.setRequestProperty("timeout",
String.valueOf(GlobalVariable.auditPluginLoadTimeoutS));
@@ -96,6 +102,7 @@ public class AuditStreamLoader {
sb.append("-H \"").append("Expect\":").append("\"100-continue\" \\\n
");
sb.append("-H \"").append("Content-Type\":").append("\"text/plain;
charset=UTF-8\" \\\n ");
sb.append("-H \"").append("max_filter_ratio\":").append("\"1.0\" \\\n
");
+ sb.append("-H
\"").append("compress_type\":").append("\"").append(COMPRESS_TYPE).append("\"
\\\n ");
sb.append("-H \"").append("columns\":")
.append("\"" + InternalSchema.AUDIT_SCHEMA.stream().map(c ->
c.getName()).collect(
Collectors.joining(",")) + "\" \\\n ");
@@ -124,6 +131,12 @@ public class AuditStreamLoader {
return response.toString();
}
+ private static void writeCompressedBody(OutputStream outputStream,
StringBuilder payload) throws IOException {
+ try (GZIPOutputStream gzipOutputStream = new GZIPOutputStream(new
BufferedOutputStream(outputStream))) {
+
gzipOutputStream.write(payload.toString().getBytes(StandardCharsets.UTF_8));
+ }
+ }
+
public LoadResponse loadBatch(StringBuilder sb, String clusterToken) {
String label = genLabel();
@@ -146,9 +159,7 @@ public class AuditStreamLoader {
// build request and send to new be location
beConn = getConnection(location, label, clusterToken);
// send data to be
- try (BufferedOutputStream bos = new
BufferedOutputStream(beConn.getOutputStream())) {
- bos.write(sb.toString().getBytes());
- }
+ writeCompressedBody(beConn.getOutputStream(), sb);
// get respond
status = beConn.getResponseCode();
diff --git
a/fe/fe-core/src/test/java/org/apache/doris/plugin/audit/AuditStreamLoaderTest.java
b/fe/fe-core/src/test/java/org/apache/doris/plugin/audit/AuditStreamLoaderTest.java
new file mode 100644
index 00000000000..1776906aee7
--- /dev/null
+++
b/fe/fe-core/src/test/java/org/apache/doris/plugin/audit/AuditStreamLoaderTest.java
@@ -0,0 +1,67 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+package org.apache.doris.plugin.audit;
+
+import org.apache.doris.common.jmockit.Deencapsulation;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.nio.charset.StandardCharsets;
+import java.util.zip.GZIPInputStream;
+
+public class AuditStreamLoaderTest {
+
+ @Test
+ public void testConnectionUsesGzipCompression() throws Exception {
+ HttpURLConnection connection =
Deencapsulation.invoke(AuditStreamLoader.class, "getConnection",
+ "http://127.0.0.1:8030/api/db/table/_stream_load?", "label",
"token");
+
+ Assertions.assertEquals("gz",
connection.getRequestProperty("compress_type"));
+ }
+
+ @Test
+ public void testWriteCompressedBody() throws Exception {
+ String payload = "audit row 中文\u001fselect 1\u001e";
+ ByteArrayOutputStream compressed = new ByteArrayOutputStream();
+
+ Deencapsulation.invoke(AuditStreamLoader.class, "writeCompressedBody",
+ compressed, new StringBuilder(payload));
+
+ byte[] bytes = compressed.toByteArray();
+ Assertions.assertEquals(0x1f, bytes[0] & 0xff);
+ Assertions.assertEquals(0x8b, bytes[1] & 0xff);
+ Assertions.assertEquals(payload, decompress(bytes));
+ }
+
+ private static String decompress(byte[] compressed) throws IOException {
+ try (GZIPInputStream gzipInputStream = new GZIPInputStream(new
ByteArrayInputStream(compressed));
+ ByteArrayOutputStream output = new ByteArrayOutputStream()) {
+ byte[] buffer = new byte[1024];
+ int bytesRead;
+ while ((bytesRead = gzipInputStream.read(buffer)) != -1) {
+ output.write(buffer, 0, bytesRead);
+ }
+ return new String(output.toByteArray(), StandardCharsets.UTF_8);
+ }
+ }
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]