This is an automated email from the ASF dual-hosted git repository.

HTHou pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/master by this push:
     new 4bc2fd5532e Add REST write request size and batch limits (#17481)
4bc2fd5532e is described below

commit 4bc2fd5532e05d43b2e643bd879cc1cf8423160d
Author: Haonan <[email protected]>
AuthorDate: Wed Jul 22 18:13:42 2026 +0800

    Add REST write request size and batch limits (#17481)
---
 .../org/apache/iotdb/rest/i18n/RestMessages.java   |  43 ++++
 .../org/apache/iotdb/rest/i18n/RestMessages.java   |  43 ++++
 .../exception/RequestLimitExceededException.java   |  25 ++
 .../filter/RequestBodyMemoryReleaseFilter.java     |  33 +++
 .../protocol/filter/RequestSizeLimitFilter.java    | 183 +++++++++++++++
 .../filter/RestRequestBodyMemoryManager.java       | 116 +++++++++
 .../rest/protocol/handler/RequestLimitChecker.java |  68 ++++++
 .../table/v1/handler/ExceptionHandler.java         |  10 +-
 .../table/v1/handler/RequestValidationHandler.java |  10 +
 .../protocol/table/v1/impl/RestApiServiceImpl.java |  16 +-
 .../rest/protocol/v1/handler/ExceptionHandler.java |  10 +-
 .../v1/handler/RequestValidationHandler.java       |  29 +++
 .../protocol/v1/impl/GrafanaApiServiceImpl.java    |  12 +-
 .../rest/protocol/v1/impl/RestApiServiceImpl.java  |  12 +-
 .../rest/protocol/v2/handler/ExceptionHandler.java |  10 +-
 .../v2/handler/RequestValidationHandler.java       |  47 ++++
 .../protocol/v2/impl/GrafanaApiServiceImpl.java    |  12 +-
 .../rest/protocol/v2/impl/RestApiServiceImpl.java  |  20 +-
 .../filter/RequestSizeLimitFilterTest.java         | 258 +++++++++++++++++++++
 .../handler/RequestValidationLimitTest.java        | 109 +++++++++
 .../apache/iotdb/db/conf/DataNodeMemoryConfig.java |  67 ++++--
 .../org/apache/iotdb/db/conf/IoTDBDescriptor.java  |   5 +
 .../iotdb/db/conf/rest/IoTDBRestServiceConfig.java |  60 +++++
 .../db/conf/rest/IoTDBRestServiceDescriptor.java   |  83 ++++++-
 .../iotdb/db/conf/DataNodeMemoryConfigTest.java    |  37 ++-
 .../org/apache/iotdb/db/conf/PropertiesTest.java   |  63 +++++
 .../src/test/resources/iotdb-common.properties     |  15 ++
 .../src/test/resources/iotdb-system.properties     |  15 ++
 .../conf/iotdb-system.properties.template          |  27 ++-
 29 files changed, 1391 insertions(+), 47 deletions(-)

diff --git 
a/external-service-impl/rest/src/main/i18n/en/org/apache/iotdb/rest/i18n/RestMessages.java
 
b/external-service-impl/rest/src/main/i18n/en/org/apache/iotdb/rest/i18n/RestMessages.java
index 882bb16c558..5de9a552679 100644
--- 
a/external-service-impl/rest/src/main/i18n/en/org/apache/iotdb/rest/i18n/RestMessages.java
+++ 
b/external-service-impl/rest/src/main/i18n/en/org/apache/iotdb/rest/i18n/RestMessages.java
@@ -77,6 +77,49 @@ public final class RestMessages {
       "The number of values in the %dth row is not equal to the data_types 
size";
   public static final String ERROR_MESSAGE_SEPARATOR = ",";
 
+  // --- RequestSizeLimitFilter ---
+  public static final String
+      
MESSAGE_REST_REQUEST_BODY_EXCEEDS_LIMIT_ARG_BYTES_USE_SET_CONFIGURATION_REST_MAX_REQUEST_BODY_SIZE_IN_BYTES_BYTES_TO_INCREASE_IT_424392C6
 =
+          "REST request body exceeds limit %d bytes. Use SET CONFIGURATION"
+              + " 'rest_max_request_body_size_in_bytes'='<bytes>' to increase 
it.";
+  public static final String
+      
MESSAGE_REST_REQUEST_BODY_MEMORY_QUOTA_EXCEEDS_LIMIT_ARG_BYTES_USE_SET_CONFIGURATION_REST_MAX_TOTAL_CONCURRENT_REQUEST_BODY_SIZE_IN_BYTES_BYTES_TO_INCREASE_IT_F07B9DDD
 =
+          "REST request body memory quota exceeds limit %d bytes. Use SET 
CONFIGURATION"
+              + " 
'rest_max_total_concurrent_request_body_size_in_bytes'='<bytes>' to increase 
it.";
+
+  // --- RequestLimitChecker ---
+  public static final String MESSAGE_INSERTTABLET_REQUEST_8647CA58 = 
"insertTablet request";
+  public static final String MESSAGE_INSERTRECORDS_REQUEST_93E12369 = 
"insertRecords request";
+  public static final String MESSAGE_TABLE_INSERTTABLET_REQUEST_573D371C =
+      "table insertTablet request";
+  public static final String 
EXCEPTION_ARG_ROW_COUNT_ARG_EXCEEDS_LIMIT_ARG_EE427E4B =
+      "%s row count %d exceeds limit %d";
+  public static final String 
EXCEPTION_ARG_COLUMN_COUNT_ARG_EXCEEDS_LIMIT_ARG_DEE9637E =
+      "%s column count %d exceeds limit %d";
+  public static final String 
EXCEPTION_ARG_VALUE_COUNT_ARG_EXCEEDS_LIMIT_ARG_77F95703 =
+      "%s value count %d exceeds limit %d";
+
+  // --- RequestValidationHandler ---
+  public static final String
+      EXCEPTION_MEASUREMENTS_AND_DATATYPES_SHOULD_HAVE_THE_SAME_SIZE_FF715FA9 =
+          "measurements and dataTypes should have the same size";
+  public static final String 
EXCEPTION_VALUES_AND_DATATYPES_SHOULD_HAVE_THE_SAME_SIZE_5BC1D604 =
+      "values and dataTypes should have the same size";
+  public static final String
+      
EXCEPTION_EACH_VALUE_COLUMN_SHOULD_HAVE_THE_SAME_SIZE_AS_TIMESTAMPS_523598BD =
+          "Each value column should have the same size as timestamps";
+  public static final String
+      EXCEPTION_MEASUREMENTS_AND_DATA_TYPES_SHOULD_HAVE_THE_SAME_SIZE_8526F19A 
=
+          "measurements and data_types should have the same size";
+  public static final String 
EXCEPTION_VALUES_AND_DATA_TYPES_SHOULD_HAVE_THE_SAME_SIZE_0BAE701D =
+      "values and data_types should have the same size";
+  public static final String
+      
EXCEPTION_DEVICES_TIMESTAMPS_MEASUREMENTS_LIST_DATA_TYPES_LIST_AND_VALUES_LIST_SHOULD_HAVE_THE_SAME_SIZE_5983AAC2
 =
+          "devices, timestamps, measurements_list, data_types_list and 
values_list should have the same size";
+  public static final String
+      
EXCEPTION_EACH_INSERTRECORDS_ROW_SHOULD_HAVE_THE_SAME_NUMBER_OF_MEASUREMENTS_DATA_TYPES_AND_VALUES_AD58AEF2
 =
+          "Each insertRecords row should have the same number of measurements, 
data types and values";
+
   private RestMessages() {}
   // 
---------------------------------------------------------------------------
   // Additional auto-collected messages
diff --git 
a/external-service-impl/rest/src/main/i18n/zh/org/apache/iotdb/rest/i18n/RestMessages.java
 
b/external-service-impl/rest/src/main/i18n/zh/org/apache/iotdb/rest/i18n/RestMessages.java
index cb443b6ec97..c69db29571f 100644
--- 
a/external-service-impl/rest/src/main/i18n/zh/org/apache/iotdb/rest/i18n/RestMessages.java
+++ 
b/external-service-impl/rest/src/main/i18n/zh/org/apache/iotdb/rest/i18n/RestMessages.java
@@ -75,6 +75,49 @@ public final class RestMessages {
       "第 %d 行的 values 数量与 data_types 数量不相等";
   public static final String ERROR_MESSAGE_SEPARATOR = ",";
 
+  // --- RequestSizeLimitFilter ---
+  public static final String
+      
MESSAGE_REST_REQUEST_BODY_EXCEEDS_LIMIT_ARG_BYTES_USE_SET_CONFIGURATION_REST_MAX_REQUEST_BODY_SIZE_IN_BYTES_BYTES_TO_INCREASE_IT_424392C6
 =
+          "REST 请求体超过限制 %d 字节。请执行 SET CONFIGURATION"
+              + " 'rest_max_request_body_size_in_bytes'='<bytes>' 增大限制。";
+  public static final String
+      
MESSAGE_REST_REQUEST_BODY_MEMORY_QUOTA_EXCEEDS_LIMIT_ARG_BYTES_USE_SET_CONFIGURATION_REST_MAX_TOTAL_CONCURRENT_REQUEST_BODY_SIZE_IN_BYTES_BYTES_TO_INCREASE_IT_F07B9DDD
 =
+          "REST 请求体内存配额超过限制 %d 字节。请执行 SET CONFIGURATION"
+              + " 
'rest_max_total_concurrent_request_body_size_in_bytes'='<bytes>' 增大配额。";
+
+  // --- RequestLimitChecker ---
+  public static final String MESSAGE_INSERTTABLET_REQUEST_8647CA58 = 
"insertTablet 请求";
+  public static final String MESSAGE_INSERTRECORDS_REQUEST_93E12369 = 
"insertRecords 请求";
+  public static final String MESSAGE_TABLE_INSERTTABLET_REQUEST_573D371C =
+      "table insertTablet 请求";
+  public static final String 
EXCEPTION_ARG_ROW_COUNT_ARG_EXCEEDS_LIMIT_ARG_EE427E4B =
+      "%s 行数 %d 超过限制 %d";
+  public static final String 
EXCEPTION_ARG_COLUMN_COUNT_ARG_EXCEEDS_LIMIT_ARG_DEE9637E =
+      "%s 列数 %d 超过限制 %d";
+  public static final String 
EXCEPTION_ARG_VALUE_COUNT_ARG_EXCEEDS_LIMIT_ARG_77F95703 =
+      "%s value 数 %d 超过限制 %d";
+
+  // --- RequestValidationHandler ---
+  public static final String
+      EXCEPTION_MEASUREMENTS_AND_DATATYPES_SHOULD_HAVE_THE_SAME_SIZE_FF715FA9 =
+          "measurements 和 dataTypes 的数量应相同";
+  public static final String 
EXCEPTION_VALUES_AND_DATATYPES_SHOULD_HAVE_THE_SAME_SIZE_5BC1D604 =
+      "values 和 dataTypes 的数量应相同";
+  public static final String
+      
EXCEPTION_EACH_VALUE_COLUMN_SHOULD_HAVE_THE_SAME_SIZE_AS_TIMESTAMPS_523598BD =
+          "每个 value 列的数量应与 timestamps 数量相同";
+  public static final String
+      EXCEPTION_MEASUREMENTS_AND_DATA_TYPES_SHOULD_HAVE_THE_SAME_SIZE_8526F19A 
=
+          "measurements 和 data_types 的数量应相同";
+  public static final String 
EXCEPTION_VALUES_AND_DATA_TYPES_SHOULD_HAVE_THE_SAME_SIZE_0BAE701D =
+      "values 和 data_types 的数量应相同";
+  public static final String
+      
EXCEPTION_DEVICES_TIMESTAMPS_MEASUREMENTS_LIST_DATA_TYPES_LIST_AND_VALUES_LIST_SHOULD_HAVE_THE_SAME_SIZE_5983AAC2
 =
+          "devices、timestamps、measurements_list、data_types_list 和 values_list 
的数量应相同";
+  public static final String
+      
EXCEPTION_EACH_INSERTRECORDS_ROW_SHOULD_HAVE_THE_SAME_NUMBER_OF_MEASUREMENTS_DATA_TYPES_AND_VALUES_AD58AEF2
 =
+          "每个 insertRecords 行中的 measurements、data types 和 values 数量应相同";
+
   private RestMessages() {}
   // 
---------------------------------------------------------------------------
   // Additional auto-collected messages
diff --git 
a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/exception/RequestLimitExceededException.java
 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/exception/RequestLimitExceededException.java
new file mode 100644
index 00000000000..ab56ec4bb03
--- /dev/null
+++ 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/exception/RequestLimitExceededException.java
@@ -0,0 +1,25 @@
+/*
+ * 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.iotdb.rest.protocol.exception;
+
+public class RequestLimitExceededException extends IllegalArgumentException {
+
+  public RequestLimitExceededException(String message) {
+    super(message);
+  }
+}
diff --git 
a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/filter/RequestBodyMemoryReleaseFilter.java
 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/filter/RequestBodyMemoryReleaseFilter.java
new file mode 100644
index 00000000000..301de4f3b1c
--- /dev/null
+++ 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/filter/RequestBodyMemoryReleaseFilter.java
@@ -0,0 +1,33 @@
+/*
+ * 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.iotdb.rest.protocol.filter;
+
+import jakarta.ws.rs.container.ContainerRequestContext;
+import jakarta.ws.rs.container.ContainerResponseContext;
+import jakarta.ws.rs.container.ContainerResponseFilter;
+import jakarta.ws.rs.ext.Provider;
+
+@Provider
+public class RequestBodyMemoryReleaseFilter implements ContainerResponseFilter 
{
+
+  @Override
+  public void filter(
+      ContainerRequestContext requestContext, ContainerResponseContext 
responseContext) {
+    RestRequestBodyMemoryManager.releaseReservation(requestContext);
+  }
+}
diff --git 
a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/filter/RequestSizeLimitFilter.java
 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/filter/RequestSizeLimitFilter.java
new file mode 100644
index 00000000000..e16d8ab0c6b
--- /dev/null
+++ 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/filter/RequestSizeLimitFilter.java
@@ -0,0 +1,183 @@
+/*
+ * 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.iotdb.rest.protocol.filter;
+
+import org.apache.iotdb.db.conf.rest.IoTDBRestServiceDescriptor;
+import org.apache.iotdb.rest.i18n.RestMessages;
+import org.apache.iotdb.rest.protocol.model.ExecutionStatus;
+
+import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.container.ContainerRequestContext;
+import jakarta.ws.rs.container.ContainerRequestFilter;
+import jakarta.ws.rs.container.PreMatching;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.ext.Provider;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+@Provider
+@PreMatching
+public class RequestSizeLimitFilter implements ContainerRequestFilter {
+
+  private static final int PAYLOAD_TOO_LARGE_STATUS_CODE = 413;
+  private static final int SERVICE_UNAVAILABLE_STATUS_CODE = 503;
+
+  @Override
+  public void filter(ContainerRequestContext requestContext) {
+    long maxBodySize =
+        
IoTDBRestServiceDescriptor.getInstance().getConfig().getRestMaxRequestBodySizeInBytes();
+    long memoryLimit =
+        IoTDBRestServiceDescriptor.getInstance()
+            .getConfig()
+            .getRestMaxTotalConcurrentRequestBodySizeInBytes();
+    if (maxBodySize <= 0 && memoryLimit <= 0) {
+      return;
+    }
+
+    int contentLength = requestContext.getLength();
+    if (maxBodySize > 0 && contentLength > maxBodySize) {
+      requestContext.abortWith(buildPayloadTooLargeResponse(maxBodySize));
+      return;
+    }
+
+    RestRequestBodyMemoryManager.Reservation memoryReservation =
+        RestRequestBodyMemoryManager.newReservation(memoryLimit);
+    long memoryReservedByContentLength = 0;
+    if (contentLength > 0 && memoryReservation.isEnabled()) {
+      if (!memoryReservation.reserve(contentLength)) {
+        memoryReservation.close();
+        
requestContext.abortWith(buildMemoryQuotaExceededResponse(memoryLimit));
+        return;
+      }
+      memoryReservedByContentLength = contentLength;
+      RestRequestBodyMemoryManager.registerReservation(requestContext, 
memoryReservation);
+    }
+
+    requestContext.setEntityStream(
+        new LimitedInputStream(
+            requestContext.getEntityStream(),
+            maxBodySize,
+            memoryLimit,
+            memoryReservation,
+            memoryReservedByContentLength));
+    if (memoryReservation.isEnabled() && memoryReservedByContentLength == 0) {
+      RestRequestBodyMemoryManager.registerReservation(requestContext, 
memoryReservation);
+    }
+  }
+
+  private static Response buildPayloadTooLargeResponse(long maxBodySize) {
+    return Response.status(PAYLOAD_TOO_LARGE_STATUS_CODE)
+        .type(MediaType.APPLICATION_JSON_TYPE)
+        .entity(
+            new ExecutionStatus()
+                .code(PAYLOAD_TOO_LARGE_STATUS_CODE)
+                .message(
+                    String.format(
+                        RestMessages
+                            
.MESSAGE_REST_REQUEST_BODY_EXCEEDS_LIMIT_ARG_BYTES_USE_SET_CONFIGURATION_REST_MAX_REQUEST_BODY_SIZE_IN_BYTES_BYTES_TO_INCREASE_IT_424392C6,
+                        maxBodySize)))
+        .build();
+  }
+
+  private static Response buildMemoryQuotaExceededResponse(long memoryLimit) {
+    return Response.status(SERVICE_UNAVAILABLE_STATUS_CODE)
+        .type(MediaType.APPLICATION_JSON_TYPE)
+        .entity(
+            new ExecutionStatus()
+                .code(SERVICE_UNAVAILABLE_STATUS_CODE)
+                .message(
+                    String.format(
+                        RestMessages
+                            
.MESSAGE_REST_REQUEST_BODY_MEMORY_QUOTA_EXCEEDS_LIMIT_ARG_BYTES_USE_SET_CONFIGURATION_REST_MAX_TOTAL_CONCURRENT_REQUEST_BODY_SIZE_IN_BYTES_BYTES_TO_INCREASE_IT_F07B9DDD,
+                        memoryLimit)))
+        .build();
+  }
+
+  private static class LimitedInputStream extends FilterInputStream {
+
+    private final long maxBodySize;
+    private final long memoryLimit;
+    private final RestRequestBodyMemoryManager.Reservation memoryReservation;
+    private long memoryCoveredBytes;
+    private long bytesRead;
+
+    private LimitedInputStream(
+        InputStream in,
+        long maxBodySize,
+        long memoryLimit,
+        RestRequestBodyMemoryManager.Reservation memoryReservation,
+        long memoryCoveredBytes) {
+      super(in);
+      this.maxBodySize = maxBodySize;
+      this.memoryLimit = memoryLimit;
+      this.memoryReservation = memoryReservation;
+      this.memoryCoveredBytes = memoryCoveredBytes;
+    }
+
+    @Override
+    public int read() throws IOException {
+      int result = super.read();
+      if (result != -1) {
+        incrementBytesRead(1);
+      }
+      return result;
+    }
+
+    @Override
+    public int read(byte[] b, int off, int len) throws IOException {
+      int result = super.read(b, off, len);
+      if (result > 0) {
+        incrementBytesRead(result);
+      }
+      return result;
+    }
+
+    private void incrementBytesRead(int increment) {
+      bytesRead += increment;
+      if (maxBodySize > 0 && bytesRead > maxBodySize) {
+        memoryReservation.close();
+        throw new 
WebApplicationException(buildPayloadTooLargeResponse(maxBodySize));
+      }
+      reserveMemoryIfNecessary();
+    }
+
+    private void reserveMemoryIfNecessary() {
+      if (bytesRead <= memoryCoveredBytes) {
+        return;
+      }
+      long sizeToReserve = bytesRead - memoryCoveredBytes;
+      if (!memoryReservation.reserve(sizeToReserve)) {
+        memoryReservation.close();
+        throw new 
WebApplicationException(buildMemoryQuotaExceededResponse(memoryLimit));
+      }
+      memoryCoveredBytes = bytesRead;
+    }
+
+    @Override
+    public void close() throws IOException {
+      try {
+        super.close();
+      } finally {
+        memoryReservation.close();
+      }
+    }
+  }
+}
diff --git 
a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/filter/RestRequestBodyMemoryManager.java
 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/filter/RestRequestBodyMemoryManager.java
new file mode 100644
index 00000000000..3b9ea6bb4b5
--- /dev/null
+++ 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/filter/RestRequestBodyMemoryManager.java
@@ -0,0 +1,116 @@
+/*
+ * 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.iotdb.rest.protocol.filter;
+
+import jakarta.ws.rs.container.ContainerRequestContext;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicLong;
+
+final class RestRequestBodyMemoryManager {
+
+  static final String REQUEST_BODY_MEMORY_RESERVATION_PROPERTY =
+      RestRequestBodyMemoryManager.class.getName() + 
".requestBodyMemoryReservation";
+  private static final AtomicLong RESERVED_MEMORY_IN_BYTES = new AtomicLong();
+
+  private RestRequestBodyMemoryManager() {}
+
+  static Reservation newReservation(long memoryLimitInBytes) {
+    return new Reservation(memoryLimitInBytes);
+  }
+
+  static long getReservedMemoryInBytes() {
+    return RESERVED_MEMORY_IN_BYTES.get();
+  }
+
+  static void resetForTest() {
+    RESERVED_MEMORY_IN_BYTES.set(0);
+  }
+
+  static void registerReservation(
+      ContainerRequestContext requestContext, Reservation memoryReservation) {
+    if (memoryReservation.isEnabled()) {
+      requestContext.setProperty(REQUEST_BODY_MEMORY_RESERVATION_PROPERTY, 
memoryReservation);
+    }
+  }
+
+  static void releaseReservation(ContainerRequestContext requestContext) {
+    Object reservation = 
requestContext.getProperty(REQUEST_BODY_MEMORY_RESERVATION_PROPERTY);
+    if (reservation instanceof Reservation) {
+      ((Reservation) reservation).close();
+      requestContext.removeProperty(REQUEST_BODY_MEMORY_RESERVATION_PROPERTY);
+    }
+  }
+
+  private static boolean tryReserve(long sizeInBytes, long memoryLimitInBytes) 
{
+    if (sizeInBytes <= 0 || memoryLimitInBytes <= 0) {
+      return true;
+    }
+
+    while (true) {
+      long currentReservedBytes = RESERVED_MEMORY_IN_BYTES.get();
+      if (currentReservedBytes > memoryLimitInBytes - sizeInBytes) {
+        return false;
+      }
+      if (RESERVED_MEMORY_IN_BYTES.compareAndSet(
+          currentReservedBytes, currentReservedBytes + sizeInBytes)) {
+        return true;
+      }
+    }
+  }
+
+  static final class Reservation implements AutoCloseable {
+
+    private final long memoryLimitInBytes;
+    private final AtomicBoolean released = new AtomicBoolean();
+    private long reservedMemoryInBytes;
+
+    private Reservation(long memoryLimitInBytes) {
+      this.memoryLimitInBytes = memoryLimitInBytes;
+    }
+
+    boolean isEnabled() {
+      return memoryLimitInBytes > 0;
+    }
+
+    synchronized boolean reserve(long sizeInBytes) {
+      if (sizeInBytes <= 0 || !isEnabled()) {
+        return true;
+      }
+      if (released.get()) {
+        return false;
+      }
+      if (!tryReserve(sizeInBytes, memoryLimitInBytes)) {
+        return false;
+      }
+      reservedMemoryInBytes += sizeInBytes;
+      return true;
+    }
+
+    @Override
+    public synchronized void close() {
+      if (released.compareAndSet(false, true)) {
+        long reservedBytes = reservedMemoryInBytes;
+        reservedMemoryInBytes = 0;
+        if (reservedBytes > 0) {
+          RESERVED_MEMORY_IN_BYTES.addAndGet(-reservedBytes);
+        }
+      }
+    }
+  }
+}
diff --git 
a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/handler/RequestLimitChecker.java
 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/handler/RequestLimitChecker.java
new file mode 100644
index 00000000000..0ec64b9b125
--- /dev/null
+++ 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/handler/RequestLimitChecker.java
@@ -0,0 +1,68 @@
+/*
+ * 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.iotdb.rest.protocol.handler;
+
+import org.apache.iotdb.db.conf.rest.IoTDBRestServiceConfig;
+import org.apache.iotdb.db.conf.rest.IoTDBRestServiceDescriptor;
+import org.apache.iotdb.rest.i18n.RestMessages;
+import org.apache.iotdb.rest.protocol.exception.RequestLimitExceededException;
+
+public class RequestLimitChecker {
+
+  private RequestLimitChecker() {}
+
+  public static void checkRowCount(String requestName, int rowCount) {
+    int maxRows = getConfig().getRestMaxInsertRows();
+    if (maxRows > 0 && rowCount > maxRows) {
+      throw new RequestLimitExceededException(
+          String.format(
+              
RestMessages.EXCEPTION_ARG_ROW_COUNT_ARG_EXCEEDS_LIMIT_ARG_EE427E4B,
+              requestName,
+              rowCount,
+              maxRows));
+    }
+  }
+
+  public static void checkColumnCount(String requestName, int columnCount) {
+    int maxColumns = getConfig().getRestMaxInsertColumns();
+    if (maxColumns > 0 && columnCount > maxColumns) {
+      throw new RequestLimitExceededException(
+          String.format(
+              
RestMessages.EXCEPTION_ARG_COLUMN_COUNT_ARG_EXCEEDS_LIMIT_ARG_DEE9637E,
+              requestName,
+              columnCount,
+              maxColumns));
+    }
+  }
+
+  public static void checkValueCount(String requestName, long valueCount) {
+    long maxValues = getConfig().getRestMaxInsertValues();
+    if (maxValues > 0 && valueCount > maxValues) {
+      throw new RequestLimitExceededException(
+          String.format(
+              
RestMessages.EXCEPTION_ARG_VALUE_COUNT_ARG_EXCEEDS_LIMIT_ARG_77F95703,
+              requestName,
+              valueCount,
+              maxValues));
+    }
+  }
+
+  private static IoTDBRestServiceConfig getConfig() {
+    return IoTDBRestServiceDescriptor.getInstance().getConfig();
+  }
+}
diff --git 
a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/table/v1/handler/ExceptionHandler.java
 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/table/v1/handler/ExceptionHandler.java
index e3b83f51b7d..65af32084ab 100644
--- 
a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/table/v1/handler/ExceptionHandler.java
+++ 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/table/v1/handler/ExceptionHandler.java
@@ -28,6 +28,7 @@ import 
org.apache.iotdb.commons.queryengine.plan.relational.sql.parser.ParsingEx
 import org.apache.iotdb.db.exception.StorageEngineException;
 import org.apache.iotdb.db.exception.metadata.DatabaseNotSetException;
 import org.apache.iotdb.db.exception.sql.StatementAnalyzeException;
+import org.apache.iotdb.rest.protocol.exception.RequestLimitExceededException;
 import org.apache.iotdb.rest.protocol.model.ExecutionStatus;
 import org.apache.iotdb.rpc.TSStatusCode;
 
@@ -46,7 +47,10 @@ public class ExceptionHandler {
 
   public static ExecutionStatus tryCatchException(Exception e) {
     ExecutionStatus responseResult = new ExecutionStatus();
-    if (e instanceof QueryProcessException) {
+    if (e instanceof RequestLimitExceededException) {
+      responseResult.setMessage(e.getMessage());
+      responseResult.setCode(413);
+    } else if (e instanceof QueryProcessException) {
       responseResult.setMessage(e.getMessage());
       responseResult.setCode(((QueryProcessException) e).getErrorCode());
     } else if (e instanceof DatabaseNotSetException) {
@@ -92,4 +96,8 @@ public class ExceptionHandler {
     LOGGER.warn(e.getMessage(), e);
     return responseResult;
   }
+
+  public static int getHttpStatus(Exception e) {
+    return e instanceof RequestLimitExceededException ? 413 : 
Status.OK.getStatusCode();
+  }
 }
diff --git 
a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/table/v1/handler/RequestValidationHandler.java
 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/table/v1/handler/RequestValidationHandler.java
index 8bab22426fe..3e6edabdeff 100644
--- 
a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/table/v1/handler/RequestValidationHandler.java
+++ 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/table/v1/handler/RequestValidationHandler.java
@@ -18,6 +18,7 @@
 package org.apache.iotdb.rest.protocol.table.v1.handler;
 
 import org.apache.iotdb.rest.i18n.RestMessages;
+import org.apache.iotdb.rest.protocol.handler.RequestLimitChecker;
 import org.apache.iotdb.rest.protocol.table.v1.model.InsertTabletRequest;
 import org.apache.iotdb.rest.protocol.table.v1.model.SQL;
 
@@ -64,6 +65,15 @@ public class RequestValidationHandler {
       errorMessages.add(RestMessages.VALUES_AND_TIMESTAMPS_SIZE_MISMATCH);
     }
 
+    int rowCount = insertTabletRequest.getTimestamps().size();
+    int columnCount = insertTabletRequest.getColumnNames().size();
+    RequestLimitChecker.checkRowCount(
+        RestMessages.MESSAGE_TABLE_INSERTTABLET_REQUEST_573D371C, rowCount);
+    RequestLimitChecker.checkColumnCount(
+        RestMessages.MESSAGE_TABLE_INSERTTABLET_REQUEST_573D371C, columnCount);
+    RequestLimitChecker.checkValueCount(
+        RestMessages.MESSAGE_TABLE_INSERTTABLET_REQUEST_573D371C, (long) 
rowCount * columnCount);
+
     for (int i = 0; i < insertTabletRequest.getDataTypes().size(); i++) {
       String dataType = insertTabletRequest.getDataTypes().get(i);
       if (isDataType(dataType)) {
diff --git 
a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/table/v1/impl/RestApiServiceImpl.java
 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/table/v1/impl/RestApiServiceImpl.java
index a04ae7a16b4..20249f4f682 100644
--- 
a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/table/v1/impl/RestApiServiceImpl.java
+++ 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/table/v1/impl/RestApiServiceImpl.java
@@ -113,7 +113,9 @@ public class RestApiServiceImpl extends RestApiService {
         return res;
       }
     } catch (Exception e) {
-      return 
Response.ok().entity(ExceptionHandler.tryCatchException(e)).build();
+      return Response.status(ExceptionHandler.getHttpStatus(e))
+          .entity(ExceptionHandler.tryCatchException(e))
+          .build();
     } finally {
       if (queryId != null) {
         COORDINATOR.cleanupQueryExecution(queryId);
@@ -136,7 +138,9 @@ public class RestApiServiceImpl extends RestApiService {
 
       return executeQueryInternal(sql, statement, clientSession, 
relationSqlParser);
     } catch (Exception e) {
-      return 
Response.ok().entity(ExceptionHandler.tryCatchException(e)).build();
+      return Response.status(ExceptionHandler.getHttpStatus(e))
+          .entity(ExceptionHandler.tryCatchException(e))
+          .build();
     } finally {
       long costTime = System.nanoTime() - startTime;
       Optional.ofNullable(statement)
@@ -178,7 +182,9 @@ public class RestApiServiceImpl extends RestApiService {
 
       return responseGenerateHelper(result);
     } catch (Exception e) {
-      return 
Response.ok().entity(ExceptionHandler.tryCatchException(e)).build();
+      return Response.status(ExceptionHandler.getHttpStatus(e))
+          .entity(ExceptionHandler.tryCatchException(e))
+          .build();
     } finally {
       long costTime = System.nanoTime() - startTime;
       Optional.ofNullable(insertTabletStatement)
@@ -234,7 +240,9 @@ public class RestApiServiceImpl extends RestApiService {
       }
       return responseGenerateHelper(result);
     } catch (Exception e) {
-      return 
Response.ok().entity(ExceptionHandler.tryCatchException(e)).build();
+      return Response.status(ExceptionHandler.getHttpStatus(e))
+          .entity(ExceptionHandler.tryCatchException(e))
+          .build();
     } finally {
       if (queryId != null) {
         COORDINATOR.cleanupQueryExecution(queryId);
diff --git 
a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v1/handler/ExceptionHandler.java
 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v1/handler/ExceptionHandler.java
index 1f43f2fc25f..62f3da75f63 100644
--- 
a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v1/handler/ExceptionHandler.java
+++ 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v1/handler/ExceptionHandler.java
@@ -27,6 +27,7 @@ import 
org.apache.iotdb.commons.exception.auth.AccessDeniedException;
 import org.apache.iotdb.db.exception.StorageEngineException;
 import org.apache.iotdb.db.exception.metadata.DatabaseNotSetException;
 import org.apache.iotdb.db.exception.sql.StatementAnalyzeException;
+import org.apache.iotdb.rest.protocol.exception.RequestLimitExceededException;
 import org.apache.iotdb.rest.protocol.v1.model.ExecutionStatus;
 import org.apache.iotdb.rpc.TSStatusCode;
 
@@ -45,7 +46,10 @@ public class ExceptionHandler {
 
   public static ExecutionStatus tryCatchException(Exception e) {
     ExecutionStatus responseResult = new ExecutionStatus();
-    if (e instanceof QueryProcessException) {
+    if (e instanceof RequestLimitExceededException) {
+      responseResult.setMessage(e.getMessage());
+      responseResult.setCode(413);
+    } else if (e instanceof QueryProcessException) {
       responseResult.setMessage(e.getMessage());
       responseResult.setCode(((QueryProcessException) e).getErrorCode());
     } else if (e instanceof DatabaseNotSetException) {
@@ -88,4 +92,8 @@ public class ExceptionHandler {
     LOGGER.warn(e.getMessage(), e);
     return responseResult;
   }
+
+  public static int getHttpStatus(Exception e) {
+    return e instanceof RequestLimitExceededException ? 413 : 
Status.OK.getStatusCode();
+  }
 }
diff --git 
a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v1/handler/RequestValidationHandler.java
 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v1/handler/RequestValidationHandler.java
index 9a01bffb249..a001a06e929 100644
--- 
a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v1/handler/RequestValidationHandler.java
+++ 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v1/handler/RequestValidationHandler.java
@@ -18,12 +18,14 @@
 package org.apache.iotdb.rest.protocol.v1.handler;
 
 import org.apache.iotdb.rest.i18n.RestMessages;
+import org.apache.iotdb.rest.protocol.handler.RequestLimitChecker;
 import org.apache.iotdb.rest.protocol.v1.model.ExpressionRequest;
 import org.apache.iotdb.rest.protocol.v1.model.InsertTabletRequest;
 import org.apache.iotdb.rest.protocol.v1.model.SQL;
 
 import org.apache.tsfile.external.commons.lang3.Validate;
 
+import java.util.List;
 import java.util.Objects;
 
 public class RequestValidationHandler {
@@ -42,9 +44,36 @@ public class RequestValidationHandler {
     Objects.requireNonNull(
         insertTabletRequest.getIsAligned(), 
RestMessages.IS_ALIGNED_CAMEL_NOT_NULL);
     Objects.requireNonNull(insertTabletRequest.getDeviceId(), 
RestMessages.DEVICE_ID_NOT_NULL);
+    Objects.requireNonNull(
+        insertTabletRequest.getMeasurements(), 
RestMessages.MEASUREMENTS_NOT_NULL);
     Objects.requireNonNull(
         insertTabletRequest.getDataTypes(), 
RestMessages.DATA_TYPES_CAMEL_NOT_NULL);
     Objects.requireNonNull(insertTabletRequest.getValues(), 
RestMessages.VALUES_NOT_NULL);
+
+    if (insertTabletRequest.getMeasurements().size() != 
insertTabletRequest.getDataTypes().size()) {
+      throw new IllegalArgumentException(
+          
RestMessages.EXCEPTION_MEASUREMENTS_AND_DATATYPES_SHOULD_HAVE_THE_SAME_SIZE_FF715FA9);
+    }
+    if (insertTabletRequest.getValues().size() != 
insertTabletRequest.getDataTypes().size()) {
+      throw new IllegalArgumentException(
+          
RestMessages.EXCEPTION_VALUES_AND_DATATYPES_SHOULD_HAVE_THE_SAME_SIZE_5BC1D604);
+    }
+
+    int rowCount = insertTabletRequest.getTimestamps().size();
+    int columnCount = insertTabletRequest.getMeasurements().size();
+    
RequestLimitChecker.checkRowCount(RestMessages.MESSAGE_INSERTTABLET_REQUEST_8647CA58,
 rowCount);
+    RequestLimitChecker.checkColumnCount(
+        RestMessages.MESSAGE_INSERTTABLET_REQUEST_8647CA58, columnCount);
+    RequestLimitChecker.checkValueCount(
+        RestMessages.MESSAGE_INSERTTABLET_REQUEST_8647CA58, (long) rowCount * 
columnCount);
+
+    for (List<Object> column : insertTabletRequest.getValues()) {
+      if (column.size() != rowCount) {
+        throw new IllegalArgumentException(
+            RestMessages
+                
.EXCEPTION_EACH_VALUE_COLUMN_SHOULD_HAVE_THE_SAME_SIZE_AS_TIMESTAMPS_523598BD);
+      }
+    }
   }
 
   public static void validateExpressionRequest(ExpressionRequest 
expressionRequest) {
diff --git 
a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v1/impl/GrafanaApiServiceImpl.java
 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v1/impl/GrafanaApiServiceImpl.java
index dcc17c43a59..94ecdc61e4d 100644
--- 
a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v1/impl/GrafanaApiServiceImpl.java
+++ 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v1/impl/GrafanaApiServiceImpl.java
@@ -142,7 +142,9 @@ public class GrafanaApiServiceImpl extends 
GrafanaApiService {
             queryExecution, statement, defaultQueryRowLimit);
       }
     } catch (Exception e) {
-      return 
Response.ok().entity(ExceptionHandler.tryCatchException(e)).build();
+      return Response.status(ExceptionHandler.getHttpStatus(e))
+          .entity(ExceptionHandler.tryCatchException(e))
+          .build();
     } finally {
       if (queryId != null) {
         COORDINATOR.cleanupQueryExecution(queryId);
@@ -219,7 +221,9 @@ public class GrafanaApiServiceImpl extends 
GrafanaApiService {
         }
       }
     } catch (Exception e) {
-      return 
Response.ok().entity(ExceptionHandler.tryCatchException(e)).build();
+      return Response.status(ExceptionHandler.getHttpStatus(e))
+          .entity(ExceptionHandler.tryCatchException(e))
+          .build();
     } finally {
       if (queryId != null) {
         COORDINATOR.cleanupQueryExecution(queryId);
@@ -284,7 +288,9 @@ public class GrafanaApiServiceImpl extends 
GrafanaApiService {
         return QueryDataSetHandler.fillGrafanaNodesResult(null, 
defaultQueryRowLimit);
       }
     } catch (Exception e) {
-      return 
Response.ok().entity(ExceptionHandler.tryCatchException(e)).build();
+      return Response.status(ExceptionHandler.getHttpStatus(e))
+          .entity(ExceptionHandler.tryCatchException(e))
+          .build();
     } finally {
       if (queryId != null) {
         COORDINATOR.cleanupQueryExecution(queryId);
diff --git 
a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v1/impl/RestApiServiceImpl.java
 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v1/impl/RestApiServiceImpl.java
index 4939e10a412..a5d7302920d 100644
--- 
a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v1/impl/RestApiServiceImpl.java
+++ 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v1/impl/RestApiServiceImpl.java
@@ -154,7 +154,9 @@ public class RestApiServiceImpl extends RestApiService {
           .build();
     } catch (Exception e) {
       finish = true;
-      return 
Response.ok().entity(ExceptionHandler.tryCatchException(e)).build();
+      return Response.status(ExceptionHandler.getHttpStatus(e))
+          .entity(ExceptionHandler.tryCatchException(e))
+          .build();
     } finally {
       long costTime = System.nanoTime() - startTime;
       Optional.ofNullable(statement)
@@ -237,7 +239,9 @@ public class RestApiServiceImpl extends RestApiService {
       }
     } catch (Exception e) {
       finish = true;
-      return 
Response.ok().entity(ExceptionHandler.tryCatchException(e)).build();
+      return Response.status(ExceptionHandler.getHttpStatus(e))
+          .entity(ExceptionHandler.tryCatchException(e))
+          .build();
     } finally {
       long costTime = System.nanoTime() - startTime;
       Optional.ofNullable(statement)
@@ -308,7 +312,9 @@ public class RestApiServiceImpl extends RestApiService {
                       .message(result.status.getMessage()))
           .build();
     } catch (Exception e) {
-      return 
Response.ok().entity(ExceptionHandler.tryCatchException(e)).build();
+      return Response.status(ExceptionHandler.getHttpStatus(e))
+          .entity(ExceptionHandler.tryCatchException(e))
+          .build();
     } finally {
       long costTime = System.nanoTime() - startTime;
       Optional.ofNullable(insertTabletStatement)
diff --git 
a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/handler/ExceptionHandler.java
 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/handler/ExceptionHandler.java
index 39780877239..9ed5111c7e7 100644
--- 
a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/handler/ExceptionHandler.java
+++ 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/handler/ExceptionHandler.java
@@ -27,6 +27,7 @@ import 
org.apache.iotdb.commons.exception.auth.AccessDeniedException;
 import org.apache.iotdb.db.exception.StorageEngineException;
 import org.apache.iotdb.db.exception.metadata.DatabaseNotSetException;
 import org.apache.iotdb.db.exception.sql.StatementAnalyzeException;
+import org.apache.iotdb.rest.protocol.exception.RequestLimitExceededException;
 import org.apache.iotdb.rest.protocol.model.ExecutionStatus;
 import org.apache.iotdb.rpc.TSStatusCode;
 
@@ -45,7 +46,10 @@ public class ExceptionHandler {
 
   public static ExecutionStatus tryCatchException(Exception e) {
     ExecutionStatus responseResult = new ExecutionStatus();
-    if (e instanceof QueryProcessException) {
+    if (e instanceof RequestLimitExceededException) {
+      responseResult.setMessage(e.getMessage());
+      responseResult.setCode(413);
+    } else if (e instanceof QueryProcessException) {
       responseResult.setMessage(e.getMessage());
       responseResult.setCode(((QueryProcessException) e).getErrorCode());
     } else if (e instanceof DatabaseNotSetException) {
@@ -88,4 +92,8 @@ public class ExceptionHandler {
     LOGGER.warn(e.getMessage(), e);
     return responseResult;
   }
+
+  public static int getHttpStatus(Exception e) {
+    return e instanceof RequestLimitExceededException ? 413 : 
Status.OK.getStatusCode();
+  }
 }
diff --git 
a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/handler/RequestValidationHandler.java
 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/handler/RequestValidationHandler.java
index 01cc4ea7ae2..d0fd4218ee7 100644
--- 
a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/handler/RequestValidationHandler.java
+++ 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/handler/RequestValidationHandler.java
@@ -18,6 +18,7 @@
 package org.apache.iotdb.rest.protocol.v2.handler;
 
 import org.apache.iotdb.rest.i18n.RestMessages;
+import org.apache.iotdb.rest.protocol.handler.RequestLimitChecker;
 import org.apache.iotdb.rest.protocol.v2.model.ExpressionRequest;
 import org.apache.iotdb.rest.protocol.v2.model.InsertRecordsRequest;
 import org.apache.iotdb.rest.protocol.v2.model.InsertTabletRequest;
@@ -57,6 +58,28 @@ public class RequestValidationHandler {
     Objects.requireNonNull(
         insertTabletRequest.getMeasurements(), 
RestMessages.MEASUREMENTS_NOT_NULL);
     Objects.requireNonNull(insertTabletRequest.getValues(), 
RestMessages.VALUES_NOT_NULL);
+    if (insertTabletRequest.getMeasurements().size() != 
insertTabletRequest.getDataTypes().size()) {
+      throw new IllegalArgumentException(
+          
RestMessages.EXCEPTION_MEASUREMENTS_AND_DATA_TYPES_SHOULD_HAVE_THE_SAME_SIZE_8526F19A);
+    }
+    if (insertTabletRequest.getValues().size() != 
insertTabletRequest.getDataTypes().size()) {
+      throw new IllegalArgumentException(
+          
RestMessages.EXCEPTION_VALUES_AND_DATA_TYPES_SHOULD_HAVE_THE_SAME_SIZE_0BAE701D);
+    }
+    int rowCount = insertTabletRequest.getTimestamps().size();
+    int columnCount = insertTabletRequest.getMeasurements().size();
+    
RequestLimitChecker.checkRowCount(RestMessages.MESSAGE_INSERTTABLET_REQUEST_8647CA58,
 rowCount);
+    RequestLimitChecker.checkColumnCount(
+        RestMessages.MESSAGE_INSERTTABLET_REQUEST_8647CA58, columnCount);
+    RequestLimitChecker.checkValueCount(
+        RestMessages.MESSAGE_INSERTTABLET_REQUEST_8647CA58, (long) rowCount * 
columnCount);
+    for (List<Object> column : insertTabletRequest.getValues()) {
+      if (column.size() != rowCount) {
+        throw new IllegalArgumentException(
+            RestMessages
+                
.EXCEPTION_EACH_VALUE_COLUMN_SHOULD_HAVE_THE_SAME_SIZE_AS_TIMESTAMPS_523598BD);
+      }
+    }
     List<String> errorMessages = new ArrayList<>();
     String device = insertTabletRequest.getDevice();
     for (int i = 0; i < insertTabletRequest.getMeasurements().size(); i++) {
@@ -82,10 +105,32 @@ public class RequestValidationHandler {
     Objects.requireNonNull(insertRecordsRequest.getValuesList(), 
RestMessages.VALUES_LIST_NOT_NULL);
     Objects.requireNonNull(
         insertRecordsRequest.getMeasurementsList(), 
RestMessages.MEASUREMENTS_LIST_NOT_NULL);
+    int rowCount = insertRecordsRequest.getDevices().size();
+    if (insertRecordsRequest.getTimestamps().size() != rowCount
+        || insertRecordsRequest.getMeasurementsList().size() != rowCount
+        || insertRecordsRequest.getDataTypesList().size() != rowCount
+        || insertRecordsRequest.getValuesList().size() != rowCount) {
+      throw new IllegalArgumentException(
+          RestMessages
+              
.EXCEPTION_DEVICES_TIMESTAMPS_MEASUREMENTS_LIST_DATA_TYPES_LIST_AND_VALUES_LIST_SHOULD_HAVE_THE_SAME_SIZE_5983AAC2);
+    }
+    RequestLimitChecker.checkRowCount(
+        RestMessages.MESSAGE_INSERTRECORDS_REQUEST_93E12369, rowCount);
     List<String> errorMessages = new ArrayList<>();
+    long valueCount = 0;
     for (int i = 0; i < insertRecordsRequest.getDataTypesList().size(); i++) {
       String device = insertRecordsRequest.getDevices().get(i);
       List<String> measurements = 
insertRecordsRequest.getMeasurementsList().get(i);
+      List<String> dataTypes = insertRecordsRequest.getDataTypesList().get(i);
+      List<Object> values = insertRecordsRequest.getValuesList().get(i);
+      if (measurements.size() != dataTypes.size() || values.size() != 
dataTypes.size()) {
+        throw new IllegalArgumentException(
+            RestMessages
+                
.EXCEPTION_EACH_INSERTRECORDS_ROW_SHOULD_HAVE_THE_SAME_NUMBER_OF_MEASUREMENTS_DATA_TYPES_AND_VALUES_AD58AEF2);
+      }
+      RequestLimitChecker.checkColumnCount(
+          RestMessages.MESSAGE_INSERTRECORDS_REQUEST_93E12369, 
measurements.size());
+      valueCount += values.size();
       for (int c = 0; c < 
insertRecordsRequest.getDataTypesList().get(i).size(); c++) {
         String dataType = 
insertRecordsRequest.getDataTypesList().get(i).get(c);
         String measurement = measurements.get(c);
@@ -99,6 +144,8 @@ public class RequestValidationHandler {
         }
       }
     }
+    RequestLimitChecker.checkValueCount(
+        RestMessages.MESSAGE_INSERTRECORDS_REQUEST_93E12369, valueCount);
     if (!errorMessages.isEmpty()) {
       throw new 
RuntimeException(String.join(RestMessages.ERROR_MESSAGE_SEPARATOR, 
errorMessages));
     }
diff --git 
a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/GrafanaApiServiceImpl.java
 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/GrafanaApiServiceImpl.java
index 32834a5bced..e6e7cdf3a5d 100644
--- 
a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/GrafanaApiServiceImpl.java
+++ 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/GrafanaApiServiceImpl.java
@@ -142,7 +142,9 @@ public class GrafanaApiServiceImpl extends 
GrafanaApiService {
             queryExecution, statement, defaultQueryRowLimit);
       }
     } catch (Exception e) {
-      return 
Response.ok().entity(ExceptionHandler.tryCatchException(e)).build();
+      return Response.status(ExceptionHandler.getHttpStatus(e))
+          .entity(ExceptionHandler.tryCatchException(e))
+          .build();
     } finally {
       if (queryId != null) {
         COORDINATOR.cleanupQueryExecution(queryId);
@@ -219,7 +221,9 @@ public class GrafanaApiServiceImpl extends 
GrafanaApiService {
         }
       }
     } catch (Exception e) {
-      return 
Response.ok().entity(ExceptionHandler.tryCatchException(e)).build();
+      return Response.status(ExceptionHandler.getHttpStatus(e))
+          .entity(ExceptionHandler.tryCatchException(e))
+          .build();
     } finally {
       if (queryId != null) {
         COORDINATOR.cleanupQueryExecution(queryId);
@@ -284,7 +288,9 @@ public class GrafanaApiServiceImpl extends 
GrafanaApiService {
         return QueryDataSetHandler.fillGrafanaNodesResult(null, 
defaultQueryRowLimit);
       }
     } catch (Exception e) {
-      return 
Response.ok().entity(ExceptionHandler.tryCatchException(e)).build();
+      return Response.status(ExceptionHandler.getHttpStatus(e))
+          .entity(ExceptionHandler.tryCatchException(e))
+          .build();
     } finally {
       if (queryId != null) {
         COORDINATOR.cleanupQueryExecution(queryId);
diff --git 
a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/RestApiServiceImpl.java
 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/RestApiServiceImpl.java
index cfe572ce9e0..f6a2ef7b54c 100644
--- 
a/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/RestApiServiceImpl.java
+++ 
b/external-service-impl/rest/src/main/java/org/apache/iotdb/rest/protocol/v2/impl/RestApiServiceImpl.java
@@ -185,7 +185,9 @@ public class RestApiServiceImpl extends RestApiService {
     } catch (Exception e) {
       finish = true;
       t = e;
-      return 
Response.ok().entity(ExceptionHandler.tryCatchException(e)).build();
+      return Response.status(ExceptionHandler.getHttpStatus(e))
+          .entity(ExceptionHandler.tryCatchException(e))
+          .build();
     } finally {
       long endTime = System.nanoTime();
       long costTime = endTime - startTime;
@@ -284,7 +286,9 @@ public class RestApiServiceImpl extends RestApiService {
       return responseGenerateHelper(result);
     } catch (Exception e) {
       finish = true;
-      return 
Response.ok().entity(ExceptionHandler.tryCatchException(e)).build();
+      return Response.status(ExceptionHandler.getHttpStatus(e))
+          .entity(ExceptionHandler.tryCatchException(e))
+          .build();
     } finally {
       long costTime = System.nanoTime() - startTime;
       if (statement != null) {
@@ -368,7 +372,9 @@ public class RestApiServiceImpl extends RestApiService {
       }
     } catch (Exception e) {
       finish = true;
-      return 
Response.ok().entity(ExceptionHandler.tryCatchException(e)).build();
+      return Response.status(ExceptionHandler.getHttpStatus(e))
+          .entity(ExceptionHandler.tryCatchException(e))
+          .build();
     } finally {
       long costTime = System.nanoTime() - startTime;
       Optional.ofNullable(statement)
@@ -418,7 +424,9 @@ public class RestApiServiceImpl extends RestApiService {
       return responseGenerateHelper(result);
 
     } catch (Exception e) {
-      return 
Response.ok().entity(ExceptionHandler.tryCatchException(e)).build();
+      return Response.status(ExceptionHandler.getHttpStatus(e))
+          .entity(ExceptionHandler.tryCatchException(e))
+          .build();
     } finally {
       long costTime = System.nanoTime() - startTime;
       Optional.ofNullable(insertRowsStatement)
@@ -472,7 +480,9 @@ public class RestApiServiceImpl extends RestApiService {
               false);
       return responseGenerateHelper(result);
     } catch (Exception e) {
-      return 
Response.ok().entity(ExceptionHandler.tryCatchException(e)).build();
+      return Response.status(ExceptionHandler.getHttpStatus(e))
+          .entity(ExceptionHandler.tryCatchException(e))
+          .build();
     } finally {
       long costTime = System.nanoTime() - startTime;
       Optional.ofNullable(insertTabletStatement)
diff --git 
a/external-service-impl/rest/src/test/java/org/apache/iotdb/rest/protocol/filter/RequestSizeLimitFilterTest.java
 
b/external-service-impl/rest/src/test/java/org/apache/iotdb/rest/protocol/filter/RequestSizeLimitFilterTest.java
new file mode 100644
index 00000000000..1311b8f1045
--- /dev/null
+++ 
b/external-service-impl/rest/src/test/java/org/apache/iotdb/rest/protocol/filter/RequestSizeLimitFilterTest.java
@@ -0,0 +1,258 @@
+/*
+ * 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.iotdb.rest.protocol.filter;
+
+import org.apache.iotdb.db.conf.rest.IoTDBRestServiceConfig;
+import org.apache.iotdb.db.conf.rest.IoTDBRestServiceDescriptor;
+import org.apache.iotdb.rest.i18n.RestMessages;
+import org.apache.iotdb.rest.protocol.model.ExecutionStatus;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import jakarta.ws.rs.WebApplicationException;
+import jakarta.ws.rs.container.ContainerRequestContext;
+import jakarta.ws.rs.container.ContainerResponseContext;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Proxy;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.assertTrue;
+
+public class RequestSizeLimitFilterTest {
+
+  private IoTDBRestServiceConfig config;
+  private long originalMaxBodySize;
+  private long originalMaxTotalConcurrentRequestBodySize;
+
+  @Before
+  public void setUp() {
+    config = IoTDBRestServiceDescriptor.getInstance().getConfig();
+    originalMaxBodySize = config.getRestMaxRequestBodySizeInBytes();
+    originalMaxTotalConcurrentRequestBodySize =
+        config.getRestMaxTotalConcurrentRequestBodySizeInBytes();
+    RestRequestBodyMemoryManager.resetForTest();
+  }
+
+  @After
+  public void tearDown() {
+    config.setRestMaxRequestBodySizeInBytes(originalMaxBodySize);
+    config.setRestMaxTotalConcurrentRequestBodySizeInBytes(
+        originalMaxTotalConcurrentRequestBodySize);
+    RestRequestBodyMemoryManager.resetForTest();
+  }
+
+  @Test
+  public void testAbortContentLengthOverLimit() {
+    config.setRestMaxRequestBodySizeInBytes(4);
+    config.setRestMaxTotalConcurrentRequestBodySizeInBytes(10);
+    TestRequestContext context = TestRequestContext.withLength(5);
+
+    new RequestSizeLimitFilter().filter(context.proxy());
+
+    assertPayloadTooLarge(context.abortedResponse(), 4);
+  }
+
+  @Test
+  public void testRejectStreamOverLimit() throws IOException {
+    config.setRestMaxRequestBodySizeInBytes(4);
+    config.setRestMaxTotalConcurrentRequestBodySizeInBytes(10);
+    TestRequestContext context =
+        
TestRequestContext.withStream("12345".getBytes(StandardCharsets.UTF_8));
+
+    new RequestSizeLimitFilter().filter(context.proxy());
+
+    assertNull(context.abortedResponse());
+    WebApplicationException exception =
+        assertThrows(WebApplicationException.class, () -> 
context.entityStream().readAllBytes());
+    assertPayloadTooLarge(exception.getResponse(), 4);
+    assertEquals(0, RestRequestBodyMemoryManager.getReservedMemoryInBytes());
+  }
+
+  @Test
+  public void testAbortContentLengthOverMemoryLimit() {
+    config.setRestMaxRequestBodySizeInBytes(10);
+    config.setRestMaxTotalConcurrentRequestBodySizeInBytes(4);
+    TestRequestContext context = TestRequestContext.withLength(5);
+
+    new RequestSizeLimitFilter().filter(context.proxy());
+
+    assertMemoryQuotaExceeded(context.abortedResponse(), 4);
+    assertEquals(0, RestRequestBodyMemoryManager.getReservedMemoryInBytes());
+  }
+
+  @Test
+  public void testRejectStreamOverMemoryLimit() throws IOException {
+    config.setRestMaxRequestBodySizeInBytes(10);
+    config.setRestMaxTotalConcurrentRequestBodySizeInBytes(4);
+    TestRequestContext context =
+        
TestRequestContext.withStream("12345".getBytes(StandardCharsets.UTF_8));
+
+    new RequestSizeLimitFilter().filter(context.proxy());
+
+    assertNull(context.abortedResponse());
+    WebApplicationException exception =
+        assertThrows(WebApplicationException.class, () -> 
context.entityStream().readAllBytes());
+    assertMemoryQuotaExceeded(exception.getResponse(), 4);
+    assertEquals(0, RestRequestBodyMemoryManager.getReservedMemoryInBytes());
+  }
+
+  @Test
+  public void testDisabledMemoryLimitDoesNotReserveMemory() throws IOException 
{
+    config.setRestMaxRequestBodySizeInBytes(10);
+    config.setRestMaxTotalConcurrentRequestBodySizeInBytes(-1);
+    TestRequestContext context =
+        
TestRequestContext.withStream("12345".getBytes(StandardCharsets.UTF_8));
+
+    new RequestSizeLimitFilter().filter(context.proxy());
+
+    assertNull(context.abortedResponse());
+    assertEquals(
+        "12345", new String(context.entityStream().readAllBytes(), 
StandardCharsets.UTF_8));
+    assertEquals(0, RestRequestBodyMemoryManager.getReservedMemoryInBytes());
+  }
+
+  @Test
+  public void testReleaseMemoryOnResponse() {
+    config.setRestMaxRequestBodySizeInBytes(10);
+    config.setRestMaxTotalConcurrentRequestBodySizeInBytes(5);
+    TestRequestContext context = TestRequestContext.withLength(4);
+    RequestSizeLimitFilter filter = new RequestSizeLimitFilter();
+
+    filter.filter(context.proxy());
+
+    assertNull(context.abortedResponse());
+    assertEquals(4, RestRequestBodyMemoryManager.getReservedMemoryInBytes());
+
+    new RequestBodyMemoryReleaseFilter().filter(context.proxy(), 
responseContext());
+
+    assertEquals(0, RestRequestBodyMemoryManager.getReservedMemoryInBytes());
+  }
+
+  private static void assertPayloadTooLarge(Response response, long 
maxBodySize) {
+    assertEquals(413, response.getStatus());
+    assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getMediaType());
+    assertTrue(response.getEntity() instanceof ExecutionStatus);
+
+    ExecutionStatus status = (ExecutionStatus) response.getEntity();
+    assertEquals(Integer.valueOf(413), status.getCode());
+    assertEquals(
+        String.format(
+            RestMessages
+                
.MESSAGE_REST_REQUEST_BODY_EXCEEDS_LIMIT_ARG_BYTES_USE_SET_CONFIGURATION_REST_MAX_REQUEST_BODY_SIZE_IN_BYTES_BYTES_TO_INCREASE_IT_424392C6,
+            maxBodySize),
+        status.getMessage());
+  }
+
+  private static void assertMemoryQuotaExceeded(Response response, long 
memoryLimit) {
+    assertEquals(503, response.getStatus());
+    assertEquals(MediaType.APPLICATION_JSON_TYPE, response.getMediaType());
+    assertTrue(response.getEntity() instanceof ExecutionStatus);
+
+    ExecutionStatus status = (ExecutionStatus) response.getEntity();
+    assertEquals(Integer.valueOf(503), status.getCode());
+    assertEquals(
+        String.format(
+            RestMessages
+                
.MESSAGE_REST_REQUEST_BODY_MEMORY_QUOTA_EXCEEDS_LIMIT_ARG_BYTES_USE_SET_CONFIGURATION_REST_MAX_TOTAL_CONCURRENT_REQUEST_BODY_SIZE_IN_BYTES_BYTES_TO_INCREASE_IT_F07B9DDD,
+            memoryLimit),
+        status.getMessage());
+  }
+
+  private static ContainerResponseContext responseContext() {
+    return (ContainerResponseContext)
+        Proxy.newProxyInstance(
+            ContainerResponseContext.class.getClassLoader(),
+            new Class<?>[] {ContainerResponseContext.class},
+            (proxy, method, args) -> {
+              throw new UnsupportedOperationException(method.getName());
+            });
+  }
+
+  private static class TestRequestContext {
+
+    private final int contentLength;
+    private final AtomicReference<InputStream> entityStream;
+    private final AtomicReference<Response> abortedResponse = new 
AtomicReference<>();
+    private final Map<String, Object> properties = new HashMap<>();
+
+    private TestRequestContext(int contentLength, InputStream entityStream) {
+      this.contentLength = contentLength;
+      this.entityStream = new AtomicReference<>(entityStream);
+    }
+
+    private static TestRequestContext withLength(int contentLength) {
+      return new TestRequestContext(contentLength, 
InputStream.nullInputStream());
+    }
+
+    private static TestRequestContext withStream(byte[] body) {
+      return new TestRequestContext(-1, new ByteArrayInputStream(body));
+    }
+
+    private ContainerRequestContext proxy() {
+      return (ContainerRequestContext)
+          Proxy.newProxyInstance(
+              ContainerRequestContext.class.getClassLoader(),
+              new Class<?>[] {ContainerRequestContext.class},
+              (proxy, method, args) -> {
+                switch (method.getName()) {
+                  case "getLength":
+                    return contentLength;
+                  case "getEntityStream":
+                    return entityStream.get();
+                  case "setEntityStream":
+                    entityStream.set((InputStream) args[0]);
+                    return null;
+                  case "abortWith":
+                    abortedResponse.set((Response) args[0]);
+                    return null;
+                  case "getProperty":
+                    return properties.get((String) args[0]);
+                  case "setProperty":
+                    properties.put((String) args[0], args[1]);
+                    return null;
+                  case "removeProperty":
+                    properties.remove((String) args[0]);
+                    return null;
+                  default:
+                    throw new UnsupportedOperationException(method.getName());
+                }
+              });
+    }
+
+    private InputStream entityStream() {
+      return entityStream.get();
+    }
+
+    private Response abortedResponse() {
+      return abortedResponse.get();
+    }
+  }
+}
diff --git 
a/external-service-impl/rest/src/test/java/org/apache/iotdb/rest/protocol/handler/RequestValidationLimitTest.java
 
b/external-service-impl/rest/src/test/java/org/apache/iotdb/rest/protocol/handler/RequestValidationLimitTest.java
new file mode 100644
index 00000000000..810de95c191
--- /dev/null
+++ 
b/external-service-impl/rest/src/test/java/org/apache/iotdb/rest/protocol/handler/RequestValidationLimitTest.java
@@ -0,0 +1,109 @@
+/*
+ * 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.iotdb.rest.protocol.handler;
+
+import org.apache.iotdb.db.conf.rest.IoTDBRestServiceConfig;
+import org.apache.iotdb.db.conf.rest.IoTDBRestServiceDescriptor;
+import org.apache.iotdb.rest.protocol.exception.RequestLimitExceededException;
+import org.apache.iotdb.rest.protocol.v1.model.InsertTabletRequest;
+import org.apache.iotdb.rest.protocol.v2.model.InsertRecordsRequest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import static 
org.apache.iotdb.rest.protocol.v1.handler.RequestValidationHandler.validateInsertTabletRequest;
+import static 
org.apache.iotdb.rest.protocol.v2.handler.RequestValidationHandler.validateInsertRecordsRequest;
+
+public class RequestValidationLimitTest {
+
+  private IoTDBRestServiceConfig config;
+  private int originalMaxInsertRows;
+  private int originalMaxInsertColumns;
+  private long originalMaxInsertValues;
+
+  @Before
+  public void setUp() {
+    config = IoTDBRestServiceDescriptor.getInstance().getConfig();
+    originalMaxInsertRows = config.getRestMaxInsertRows();
+    originalMaxInsertColumns = config.getRestMaxInsertColumns();
+    originalMaxInsertValues = config.getRestMaxInsertValues();
+  }
+
+  @After
+  public void tearDown() {
+    config.setRestMaxInsertRows(originalMaxInsertRows);
+    config.setRestMaxInsertColumns(originalMaxInsertColumns);
+    config.setRestMaxInsertValues(originalMaxInsertValues);
+  }
+
+  @Test(expected = RequestLimitExceededException.class)
+  public void testV1InsertTabletRejectsTooManyRows() {
+    config.setRestMaxInsertRows(2);
+
+    InsertTabletRequest request = new InsertTabletRequest();
+    request.setDeviceId("root.sg.d1");
+    request.setIsAligned(false);
+    request.setMeasurements(Collections.singletonList("s1"));
+    request.setDataTypes(Collections.singletonList("INT64"));
+    request.setTimestamps(Arrays.asList(1L, 2L, 3L));
+    request.setValues(Collections.singletonList(Arrays.asList(1L, 2L, 3L)));
+
+    validateInsertTabletRequest(request);
+  }
+
+  @Test(expected = RequestLimitExceededException.class)
+  public void testV2InsertRecordsRejectsTooManyValues() {
+    config.setRestMaxInsertRows(10);
+    config.setRestMaxInsertColumns(10);
+    config.setRestMaxInsertValues(2);
+
+    InsertRecordsRequest request = new InsertRecordsRequest();
+    request.setIsAligned(false);
+    request.setDevices(Arrays.asList("root.sg.d1", "root.sg.d2"));
+    request.setTimestamps(Arrays.asList(1L, 2L));
+    request.setMeasurementsList(
+        Arrays.asList(Arrays.asList("s1", "s2"), 
Collections.singletonList("s1")));
+    request.setDataTypesList(
+        Arrays.asList(Arrays.asList("INT64", "INT64"), 
Collections.singletonList("INT64")));
+    request.setValuesList(Arrays.asList(Arrays.asList(1L, 2L), 
Collections.singletonList(3L)));
+
+    validateInsertRecordsRequest(request);
+  }
+
+  @Test(expected = RequestLimitExceededException.class)
+  public void testTableInsertTabletRejectsTooManyColumns() {
+    config.setRestMaxInsertColumns(1);
+
+    org.apache.iotdb.rest.protocol.table.v1.model.InsertTabletRequest request =
+        new 
org.apache.iotdb.rest.protocol.table.v1.model.InsertTabletRequest();
+    request.setDatabase("db");
+    request.setTable("t1");
+    request.setColumnNames(Arrays.asList("tag1", "s1"));
+    request.setColumnCategories(Arrays.asList("TAG", "FIELD"));
+    request.setDataTypes(Arrays.asList("STRING", "INT64"));
+    request.setTimestamps(Collections.singletonList(1L));
+    request.setValues(Collections.singletonList(Arrays.asList("a", 1L)));
+
+    org.apache.iotdb.rest.protocol.table.v1.handler.RequestValidationHandler
+        .validateInsertTabletRequest(request);
+  }
+}
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/DataNodeMemoryConfig.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/DataNodeMemoryConfig.java
index 9476e84e15e..73c27a9b805 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/DataNodeMemoryConfig.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/DataNodeMemoryConfig.java
@@ -36,6 +36,9 @@ public class DataNodeMemoryConfig {
   public static final String SCHEMA_CACHE = "SchemaCache";
   public static final String SCHEMA_REGION = "SchemaRegion";
   public static final String PARTITION_CACHE = "PartitionCache";
+  private static final String DATANODE_MEMORY_PROPORTION = 
"datanode_memory_proportion";
+  private static final String 
STORAGE_QUERY_SCHEMA_CONSENSUS_FREE_MEMORY_PROPORTION =
+      "storage_query_schema_consensus_free_memory_proportion";
 
   /** Reject proportion for system */
   private double rejectProportion = 0.8;
@@ -152,26 +155,27 @@ public class DataNodeMemoryConfig {
   /** The memory manager of direct Buffer */
   private MemoryManager directBufferMemoryManager;
 
+  public static long getDefaultAutoResizingBufferMemorySizeInBytes() {
+    return Runtime.getRuntime().maxMemory() / 20;
+  }
+
+  public static long 
calculateAutoResizingBufferMemorySizeInBytes(TrimProperties properties) {
+    return calculateAutoResizingBufferMemorySizeInBytes(
+        getMemoryAllocateProportion(properties, false));
+  }
+
   public void init(TrimProperties properties) {
     // on heap memory
-    String memoryAllocateProportion = 
properties.getProperty("datanode_memory_proportion", null);
+    String memoryAllocateProportion = getMemoryAllocateProportion(properties, 
true);
     // Get global memory manager here
-    if (memoryAllocateProportion == null) {
-      memoryAllocateProportion =
-          
properties.getProperty("storage_query_schema_consensus_free_memory_proportion");
-      if (memoryAllocateProportion != null) {
-        LOGGER.warn(
-            DataNodeMiscMessages
-                
.MISC_LOG_THE_PARAMETER_STORAGE_QUERY_SCHEMA_CONSENSUS_FREE_MEMORY_51C9A377);
-      }
-    }
 
     long storageEngineMemorySize = Runtime.getRuntime().maxMemory() * 3 / 10;
     long queryEngineMemorySize = Runtime.getRuntime().maxMemory() * 3 / 10;
     long schemaEngineMemorySize = Runtime.getRuntime().maxMemory() / 10;
     long consensusMemorySize = Runtime.getRuntime().maxMemory() / 10;
     long pipeMemorySize = Runtime.getRuntime().maxMemory() / 10;
-    autoResizingBufferMemorySize = Runtime.getRuntime().maxMemory() / 20;
+    autoResizingBufferMemorySize =
+        calculateAutoResizingBufferMemorySizeInBytes(memoryAllocateProportion);
     if (memoryAllocateProportion != null) {
       String[] proportions = memoryAllocateProportion.split(":");
       int proportionSum = 0;
@@ -193,11 +197,6 @@ public class DataNodeMemoryConfig {
         if (proportions.length >= 6) {
           pipeMemorySize =
               maxMemoryAvailable * Integer.parseInt(proportions[4].trim()) / 
proportionSum;
-          autoResizingBufferMemorySize =
-              maxMemoryAvailable
-                  * Integer.parseInt(proportions[proportions.length - 
1].trim())
-                  / proportionSum
-                  / 2;
         } else {
           pipeMemorySize =
               (maxMemoryAvailable
@@ -266,6 +265,42 @@ public class DataNodeMemoryConfig {
         .setAutoResizingBufferMemoryControl(onHeapMemoryManager, 
autoResizingBufferMemorySize);
   }
 
+  private static String getMemoryAllocateProportion(
+      TrimProperties properties, boolean warnDeprecatedProperty) {
+    String memoryAllocateProportion = 
properties.getProperty(DATANODE_MEMORY_PROPORTION, null);
+    if (memoryAllocateProportion == null) {
+      memoryAllocateProportion =
+          
properties.getProperty(STORAGE_QUERY_SCHEMA_CONSENSUS_FREE_MEMORY_PROPORTION);
+      if (memoryAllocateProportion != null && warnDeprecatedProperty) {
+        LOGGER.warn(
+            DataNodeMiscMessages
+                
.MISC_LOG_THE_PARAMETER_STORAGE_QUERY_SCHEMA_CONSENSUS_FREE_MEMORY_51C9A377);
+      }
+    }
+    return memoryAllocateProportion;
+  }
+
+  private static long calculateAutoResizingBufferMemorySizeInBytes(
+      String memoryAllocateProportion) {
+    long autoResizingBufferMemorySize = 
getDefaultAutoResizingBufferMemorySizeInBytes();
+    if (memoryAllocateProportion != null) {
+      String[] proportions = memoryAllocateProportion.split(":");
+      int proportionSum = 0;
+      for (String proportion : proportions) {
+        proportionSum += Integer.parseInt(proportion.trim());
+      }
+      long maxMemoryAvailable = Runtime.getRuntime().maxMemory();
+      if (proportionSum != 0 && proportions.length >= 6) {
+        autoResizingBufferMemorySize =
+            maxMemoryAvailable
+                * Integer.parseInt(proportions[proportions.length - 1].trim())
+                / proportionSum
+                / 2;
+      }
+    }
+    return autoResizingBufferMemorySize;
+  }
+
   @SuppressWarnings("squid:S3518")
   private void initSchemaMemoryAllocate(
       MemoryManager schemaEngineMemoryManager, TrimProperties properties) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
index 1ab0c22bbf6..ecd3d73a3e3 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
@@ -39,6 +39,7 @@ import org.apache.iotdb.confignode.rpc.thrift.TCQConfig;
 import org.apache.iotdb.confignode.rpc.thrift.TGlobalConfig;
 import org.apache.iotdb.confignode.rpc.thrift.TRatisConfig;
 import org.apache.iotdb.consensus.config.IoTConsensusV2Config;
+import org.apache.iotdb.db.conf.rest.IoTDBRestServiceDescriptor;
 import org.apache.iotdb.db.consensus.DataRegionConsensusImpl;
 import org.apache.iotdb.db.i18n.DataNodeMiscMessages;
 import 
org.apache.iotdb.db.queryengine.plan.relational.metadata.fetcher.cache.LastCacheLoadStrategy;
@@ -2319,6 +2320,9 @@ public class IoTDBDescriptor {
       // update trusted_uri_pattern
       loadTrustedUriPattern(properties);
 
+      // update REST runtime limit config
+      
IoTDBRestServiceDescriptor.getInstance().loadHotModifiedProps(properties);
+
       // update cache_eviction_memory_computation_threshold
       conf.setCacheEvictionMemoryComputationThreshold(
           Integer.parseInt(
@@ -2380,6 +2384,7 @@ public class IoTDBDescriptor {
       ConfigurationFileUtils.updateAppliedProperties(properties, true);
       // Overwrite the keys whose setters above may have rewritten, so `show 
configuration`
       // displays the effective values rather than the raw file values.
+      
IoTDBRestServiceDescriptor.getInstance().overwriteAppliedRuntimeLimitProperties();
       overlayEffectiveConfigurationValues();
     } catch (Exception e) {
       if (e instanceof InterruptedException) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceConfig.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceConfig.java
index b7af9dcb201..2f202ceaa4e 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceConfig.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceConfig.java
@@ -19,6 +19,8 @@
 
 package org.apache.iotdb.db.conf.rest;
 
+import org.apache.iotdb.db.conf.DataNodeMemoryConfig;
+
 public class IoTDBRestServiceConfig {
 
   /** If the enableRestService is true, we will start REST Service. */
@@ -62,6 +64,22 @@ public class IoTDBRestServiceConfig {
 
   private int restQueryDefaultRowSizeLimit = 10000;
 
+  /** Maximum accepted REST request body size in bytes. */
+  private long restMaxRequestBodySizeInBytes = 16 * 1024 * 1024L;
+
+  /** Maximum total in-flight REST request body size in bytes across 
concurrent requests. */
+  private long restMaxTotalConcurrentRequestBodySizeInBytes =
+      DataNodeMemoryConfig.getDefaultAutoResizingBufferMemorySizeInBytes();
+
+  /** Maximum row count accepted by a single REST write request. */
+  private int restMaxInsertRows = 100000;
+
+  /** Maximum column count accepted by a single REST write request. */
+  private int restMaxInsertColumns = 1024;
+
+  /** Maximum value cell count accepted by a single REST write request. */
+  private long restMaxInsertValues = 1000000L;
+
   /** Is client authentication required. */
   private boolean clientAuth = false;
 
@@ -184,4 +202,46 @@ public class IoTDBRestServiceConfig {
   public void setRestQueryDefaultRowSizeLimit(int 
restQueryDefaultRowSizeLimit) {
     this.restQueryDefaultRowSizeLimit = restQueryDefaultRowSizeLimit;
   }
+
+  public long getRestMaxRequestBodySizeInBytes() {
+    return restMaxRequestBodySizeInBytes;
+  }
+
+  public void setRestMaxRequestBodySizeInBytes(long 
restMaxRequestBodySizeInBytes) {
+    this.restMaxRequestBodySizeInBytes = restMaxRequestBodySizeInBytes;
+  }
+
+  public long getRestMaxTotalConcurrentRequestBodySizeInBytes() {
+    return restMaxTotalConcurrentRequestBodySizeInBytes;
+  }
+
+  public void setRestMaxTotalConcurrentRequestBodySizeInBytes(
+      long restMaxTotalConcurrentRequestBodySizeInBytes) {
+    this.restMaxTotalConcurrentRequestBodySizeInBytes =
+        restMaxTotalConcurrentRequestBodySizeInBytes;
+  }
+
+  public int getRestMaxInsertRows() {
+    return restMaxInsertRows;
+  }
+
+  public void setRestMaxInsertRows(int restMaxInsertRows) {
+    this.restMaxInsertRows = restMaxInsertRows;
+  }
+
+  public int getRestMaxInsertColumns() {
+    return restMaxInsertColumns;
+  }
+
+  public void setRestMaxInsertColumns(int restMaxInsertColumns) {
+    this.restMaxInsertColumns = restMaxInsertColumns;
+  }
+
+  public long getRestMaxInsertValues() {
+    return restMaxInsertValues;
+  }
+
+  public void setRestMaxInsertValues(long restMaxInsertValues) {
+    this.restMaxInsertValues = restMaxInsertValues;
+  }
 }
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceDescriptor.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceDescriptor.java
index 003489e22b7..7cfdc0dd471 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceDescriptor.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/rest/IoTDBRestServiceDescriptor.java
@@ -19,8 +19,10 @@
 package org.apache.iotdb.db.conf.rest;
 
 import org.apache.iotdb.commons.conf.CommonConfig;
+import org.apache.iotdb.commons.conf.ConfigurationFileUtils;
 import org.apache.iotdb.commons.conf.IoTDBConstant;
 import org.apache.iotdb.commons.conf.TrimProperties;
+import org.apache.iotdb.db.conf.DataNodeMemoryConfig;
 import org.apache.iotdb.db.conf.IoTDBConfig;
 import org.apache.iotdb.db.i18n.DataNodeMiscMessages;
 import org.apache.iotdb.rpc.RpcSslUtils;
@@ -40,6 +42,16 @@ import java.nio.charset.StandardCharsets;
 public class IoTDBRestServiceDescriptor {
   private static final Logger logger = 
LoggerFactory.getLogger(IoTDBRestServiceDescriptor.class);
 
+  private static final String REST_QUERY_DEFAULT_ROW_SIZE_LIMIT =
+      "rest_query_default_row_size_limit";
+  private static final String REST_MAX_REQUEST_BODY_SIZE_IN_BYTES =
+      "rest_max_request_body_size_in_bytes";
+  private static final String 
REST_MAX_TOTAL_CONCURRENT_REQUEST_BODY_SIZE_IN_BYTES =
+      "rest_max_total_concurrent_request_body_size_in_bytes";
+  private static final String REST_MAX_INSERT_ROWS = "rest_max_insert_rows";
+  private static final String REST_MAX_INSERT_COLUMNS = 
"rest_max_insert_columns";
+  private static final String REST_MAX_INSERT_VALUES = 
"rest_max_insert_values";
+
   private final IoTDBRestServiceConfig conf = new IoTDBRestServiceConfig();
 
   protected IoTDBRestServiceDescriptor() {
@@ -88,11 +100,7 @@ public class IoTDBRestServiceDescriptor {
         Integer.parseInt(
             trimProperties.getProperty(
                 "rest_service_port", 
Integer.toString(conf.getRestServicePort()))));
-    conf.setRestQueryDefaultRowSizeLimit(
-        Integer.parseInt(
-            trimProperties.getProperty(
-                "rest_query_default_row_size_limit",
-                Integer.toString(conf.getRestQueryDefaultRowSizeLimit()))));
+    loadRuntimeLimitProps(trimProperties);
     conf.setEnableSwagger(
         Boolean.parseBoolean(
             trimProperties.getProperty(
@@ -118,6 +126,71 @@ public class IoTDBRestServiceDescriptor {
                 "idle_timeout_in_seconds", 
Integer.toString(conf.getIdleTimeoutInSeconds()))));
   }
 
+  public synchronized void loadHotModifiedProps(TrimProperties trimProperties) 
{
+    loadRuntimeLimitProps(trimProperties);
+  }
+
+  public synchronized void overwriteAppliedRuntimeLimitProperties() {
+    overlayRuntimeLimitProperties();
+  }
+
+  private void loadRuntimeLimitProps(TrimProperties trimProperties) {
+    conf.setRestQueryDefaultRowSizeLimit(
+        Integer.parseInt(
+            trimProperties.getProperty(
+                REST_QUERY_DEFAULT_ROW_SIZE_LIMIT,
+                Integer.toString(conf.getRestQueryDefaultRowSizeLimit()))));
+    conf.setRestMaxRequestBodySizeInBytes(
+        Long.parseLong(
+            trimProperties.getProperty(
+                REST_MAX_REQUEST_BODY_SIZE_IN_BYTES,
+                Long.toString(conf.getRestMaxRequestBodySizeInBytes()))));
+    conf.setRestMaxTotalConcurrentRequestBodySizeInBytes(
+        parseMaxTotalConcurrentRequestBodySizeInBytes(trimProperties));
+    conf.setRestMaxInsertRows(
+        Integer.parseInt(
+            trimProperties.getProperty(
+                REST_MAX_INSERT_ROWS, 
Integer.toString(conf.getRestMaxInsertRows()))));
+    conf.setRestMaxInsertColumns(
+        Integer.parseInt(
+            trimProperties.getProperty(
+                REST_MAX_INSERT_COLUMNS, 
Integer.toString(conf.getRestMaxInsertColumns()))));
+    conf.setRestMaxInsertValues(
+        Long.parseLong(
+            trimProperties.getProperty(
+                REST_MAX_INSERT_VALUES, 
Long.toString(conf.getRestMaxInsertValues()))));
+    overlayRuntimeLimitProperties();
+  }
+
+  private long parseMaxTotalConcurrentRequestBodySizeInBytes(TrimProperties 
trimProperties) {
+    long maxTotalConcurrentRequestBodySizeInBytes =
+        Long.parseLong(
+            trimProperties.getProperty(
+                REST_MAX_TOTAL_CONCURRENT_REQUEST_BODY_SIZE_IN_BYTES,
+                
Long.toString(conf.getRestMaxTotalConcurrentRequestBodySizeInBytes())));
+    return maxTotalConcurrentRequestBodySizeInBytes == 0
+        ? 
DataNodeMemoryConfig.calculateAutoResizingBufferMemorySizeInBytes(trimProperties)
+        : maxTotalConcurrentRequestBodySizeInBytes;
+  }
+
+  private void overlayRuntimeLimitProperties() {
+    ConfigurationFileUtils.updateAppliedProperties(
+        REST_QUERY_DEFAULT_ROW_SIZE_LIMIT,
+        Integer.toString(conf.getRestQueryDefaultRowSizeLimit()));
+    ConfigurationFileUtils.updateAppliedProperties(
+        REST_MAX_REQUEST_BODY_SIZE_IN_BYTES,
+        Long.toString(conf.getRestMaxRequestBodySizeInBytes()));
+    ConfigurationFileUtils.updateAppliedProperties(
+        REST_MAX_TOTAL_CONCURRENT_REQUEST_BODY_SIZE_IN_BYTES,
+        Long.toString(conf.getRestMaxTotalConcurrentRequestBodySizeInBytes()));
+    ConfigurationFileUtils.updateAppliedProperties(
+        REST_MAX_INSERT_ROWS, Integer.toString(conf.getRestMaxInsertRows()));
+    ConfigurationFileUtils.updateAppliedProperties(
+        REST_MAX_INSERT_COLUMNS, 
Integer.toString(conf.getRestMaxInsertColumns()));
+    ConfigurationFileUtils.updateAppliedProperties(
+        REST_MAX_INSERT_VALUES, Long.toString(conf.getRestMaxInsertValues()));
+  }
+
   /**
    * get props url location
    *
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/conf/DataNodeMemoryConfigTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/conf/DataNodeMemoryConfigTest.java
index 0d3447bbefb..7d227abcd0f 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/conf/DataNodeMemoryConfigTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/conf/DataNodeMemoryConfigTest.java
@@ -19,22 +19,51 @@
 
 package org.apache.iotdb.db.conf;
 
+import org.apache.iotdb.commons.conf.TrimProperties;
 import org.apache.iotdb.commons.memory.MemoryConfig;
 
-import org.junit.Assert;
 import org.junit.Test;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
 public class DataNodeMemoryConfigTest {
 
   @Test
   public void testRpcMemoryControlIsActivatedOnlyExplicitly() {
     DataNodeMemoryConfig memoryConfig = 
IoTDBDescriptor.getInstance().getMemoryConfig();
 
-    Assert.assertEquals(
-        0, 
MemoryConfig.getInstance().getAutoResizingBufferMemoryTotalSizeInBytes());
+    assertEquals(0, 
MemoryConfig.getInstance().getAutoResizingBufferMemoryTotalSizeInBytes());
 
     memoryConfig.activateAutoResizingBufferMemoryControl();
 
-    
Assert.assertTrue(MemoryConfig.getInstance().getAutoResizingBufferMemoryTotalSizeInBytes()
 > 0);
+    
assertTrue(MemoryConfig.getInstance().getAutoResizingBufferMemoryTotalSizeInBytes()
 > 0);
+  }
+
+  @Test
+  public void testDefaultAutoResizingBufferMemorySize() {
+    assertEquals(
+        Runtime.getRuntime().maxMemory() / 20,
+        DataNodeMemoryConfig.getDefaultAutoResizingBufferMemorySizeInBytes());
+  }
+
+  @Test
+  public void 
testCalculateAutoResizingBufferMemorySizeWithDataNodeMemoryProportion() {
+    TrimProperties properties = new TrimProperties();
+    properties.setProperty("datanode_memory_proportion", "1:1:1:1:1:5");
+
+    assertEquals(
+        Runtime.getRuntime().maxMemory() / 4,
+        
DataNodeMemoryConfig.calculateAutoResizingBufferMemorySizeInBytes(properties));
+  }
+
+  @Test
+  public void 
testCalculateAutoResizingBufferMemorySizeWithDeprecatedMemoryProportion() {
+    TrimProperties properties = new TrimProperties();
+    
properties.setProperty("storage_query_schema_consensus_free_memory_proportion", 
"1:1:1:1:1:2");
+
+    assertEquals(
+        Runtime.getRuntime().maxMemory() / 7,
+        
DataNodeMemoryConfig.calculateAutoResizingBufferMemorySizeInBytes(properties));
   }
 }
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/conf/PropertiesTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/conf/PropertiesTest.java
index f4daffbf303..24cb6a1b8c5 100755
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/conf/PropertiesTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/conf/PropertiesTest.java
@@ -19,8 +19,11 @@
 
 package org.apache.iotdb.db.conf;
 
+import org.apache.iotdb.commons.conf.ConfigurationFileUtils;
 import org.apache.iotdb.commons.conf.TrimProperties;
 import org.apache.iotdb.commons.utils.RegionMigrationFileRemoveRateLimiter;
+import org.apache.iotdb.db.conf.rest.IoTDBRestServiceConfig;
+import org.apache.iotdb.db.conf.rest.IoTDBRestServiceDescriptor;
 
 import com.tngtech.archunit.core.domain.JavaClasses;
 import com.tngtech.archunit.core.importer.ClassFileImporter;
@@ -65,6 +68,66 @@ public class PropertiesTest {
     }
   }
 
+  @Test
+  public void testHotReloadRestRuntimeLimitProperties() throws Exception {
+    IoTDBRestServiceConfig restConfig = 
IoTDBRestServiceDescriptor.getInstance().getConfig();
+    int originalQueryDefaultRowSizeLimit = 
restConfig.getRestQueryDefaultRowSizeLimit();
+    long originalMaxRequestBodySizeInBytes = 
restConfig.getRestMaxRequestBodySizeInBytes();
+    long originalMaxTotalConcurrentRequestBodySizeInBytes =
+        restConfig.getRestMaxTotalConcurrentRequestBodySizeInBytes();
+    int originalMaxInsertRows = restConfig.getRestMaxInsertRows();
+    int originalMaxInsertColumns = restConfig.getRestMaxInsertColumns();
+    long originalMaxInsertValues = restConfig.getRestMaxInsertValues();
+    int originalRestServicePort = restConfig.getRestServicePort();
+    boolean originalEnableHttps = restConfig.isEnableHttps();
+    try {
+      TrimProperties properties = new TrimProperties();
+      properties.setProperty("rest_query_default_row_size_limit", "123");
+      properties.setProperty("rest_max_request_body_size_in_bytes", "456");
+      
properties.setProperty("rest_max_total_concurrent_request_body_size_in_bytes", 
"789");
+      properties.setProperty("rest_max_insert_rows", "11");
+      properties.setProperty("rest_max_insert_columns", "12");
+      properties.setProperty("rest_max_insert_values", "13");
+      properties.setProperty("rest_service_port", 
Integer.toString(originalRestServicePort + 1));
+      properties.setProperty("enable_https", 
Boolean.toString(!originalEnableHttps));
+
+      IoTDBDescriptor.getInstance().loadHotModifiedProps(properties);
+
+      Assert.assertEquals(123, restConfig.getRestQueryDefaultRowSizeLimit());
+      Assert.assertEquals(456, restConfig.getRestMaxRequestBodySizeInBytes());
+      Assert.assertEquals(789, 
restConfig.getRestMaxTotalConcurrentRequestBodySizeInBytes());
+      Assert.assertEquals(11, restConfig.getRestMaxInsertRows());
+      Assert.assertEquals(12, restConfig.getRestMaxInsertColumns());
+      Assert.assertEquals(13, restConfig.getRestMaxInsertValues());
+      Assert.assertEquals(originalRestServicePort, 
restConfig.getRestServicePort());
+      Assert.assertEquals(originalEnableHttps, restConfig.isEnableHttps());
+
+      
properties.setProperty("rest_max_total_concurrent_request_body_size_in_bytes", 
"0");
+      properties.setProperty("datanode_memory_proportion", "1:1:1:1:1:5");
+
+      IoTDBDescriptor.getInstance().loadHotModifiedProps(properties);
+
+      Assert.assertEquals(
+          Runtime.getRuntime().maxMemory() / 4,
+          restConfig.getRestMaxTotalConcurrentRequestBodySizeInBytes());
+      Assert.assertEquals(
+          Long.toString(Runtime.getRuntime().maxMemory() / 4),
+          ConfigurationFileUtils.getAppliedProperties()
+              .get("rest_max_total_concurrent_request_body_size_in_bytes"));
+    } finally {
+      
restConfig.setRestQueryDefaultRowSizeLimit(originalQueryDefaultRowSizeLimit);
+      
restConfig.setRestMaxRequestBodySizeInBytes(originalMaxRequestBodySizeInBytes);
+      restConfig.setRestMaxTotalConcurrentRequestBodySizeInBytes(
+          originalMaxTotalConcurrentRequestBodySizeInBytes);
+      restConfig.setRestMaxInsertRows(originalMaxInsertRows);
+      restConfig.setRestMaxInsertColumns(originalMaxInsertColumns);
+      restConfig.setRestMaxInsertValues(originalMaxInsertValues);
+      restConfig.setRestServicePort(originalRestServicePort);
+      restConfig.setEnableHttps(originalEnableHttps);
+      
IoTDBRestServiceDescriptor.getInstance().overwriteAppliedRuntimeLimitProperties();
+    }
+  }
+
   @Test
   public void PropertiesWithSpace() {
     IoTDBDescriptor descriptor = IoTDBDescriptor.getInstance();
diff --git a/iotdb-core/datanode/src/test/resources/iotdb-common.properties 
b/iotdb-core/datanode/src/test/resources/iotdb-common.properties
index d22cfaa6372..a0399353b20 100644
--- a/iotdb-core/datanode/src/test/resources/iotdb-common.properties
+++ b/iotdb-core/datanode/src/test/resources/iotdb-common.properties
@@ -34,6 +34,21 @@ enable_rest_service=true
 # The request rowLimit/row_limit value cannot exceed this limit.
 # rest_query_default_row_size_limit=10000
 
+# Maximum REST request body size in bytes
+# rest_max_request_body_size_in_bytes=16777216
+
+# Maximum total in-flight REST request body size in bytes across concurrent 
requests. When set to 0, use the same budget as AutoResizingBuffer memory 
control. Set to a negative value to disable the limit.
+# rest_max_total_concurrent_request_body_size_in_bytes=0
+
+# Maximum rows accepted by a single REST write request
+# rest_max_insert_rows=100000
+
+# Maximum columns accepted by a single REST write request
+# rest_max_insert_columns=1024
+
+# Maximum values accepted by a single REST write request
+# rest_max_insert_values=1000000
+
 # is SSL enabled
 # enable_https=false
 
diff --git a/iotdb-core/datanode/src/test/resources/iotdb-system.properties 
b/iotdb-core/datanode/src/test/resources/iotdb-system.properties
index 4cde9826f07..9e0e16caaa9 100644
--- a/iotdb-core/datanode/src/test/resources/iotdb-system.properties
+++ b/iotdb-core/datanode/src/test/resources/iotdb-system.properties
@@ -52,6 +52,21 @@ enable_rest_service=true
 # The request rowLimit/row_limit value cannot exceed this limit.
 # rest_query_default_row_size_limit=10000
 
+# Maximum REST request body size in bytes
+# rest_max_request_body_size_in_bytes=16777216
+
+# Maximum total in-flight REST request body size in bytes across concurrent 
requests. When set to 0, use the same budget as AutoResizingBuffer memory 
control. Set to a negative value to disable the limit.
+# rest_max_total_concurrent_request_body_size_in_bytes=0
+
+# Maximum rows accepted by a single REST write request
+# rest_max_insert_rows=100000
+
+# Maximum columns accepted by a single REST write request
+# rest_max_insert_columns=1024
+
+# Maximum values accepted by a single REST write request
+# rest_max_insert_values=1000000
+
 # is SSL enabled
 # enable_https=false
 
diff --git 
a/iotdb-core/node-commons/src/assembly/resources/conf/iotdb-system.properties.template
 
b/iotdb-core/node-commons/src/assembly/resources/conf/iotdb-system.properties.template
index 0150f9db6fa..dd3ba2d295e 100644
--- 
a/iotdb-core/node-commons/src/assembly/resources/conf/iotdb-system.properties.template
+++ 
b/iotdb-core/node-commons/src/assembly/resources/conf/iotdb-system.properties.template
@@ -610,10 +610,35 @@ enable_swagger=false
 # The maximum row limit for REST and Grafana query responses.
 # The request rowLimit/row_limit value cannot exceed this limit.
 # A non-positive value is invalid and falls back to the default (10000); it no 
longer means unlimited.
-# effectiveMode: restart
+# effectiveMode: hot_reload
 # Datatype: int
 rest_query_default_row_size_limit=10000
 
+# Maximum REST request body size in bytes. Set to 0 or a negative value to 
disable the limit.
+# effectiveMode: hot_reload
+# Datatype: long
+rest_max_request_body_size_in_bytes=16777216
+
+# Maximum total in-flight REST request body size in bytes across concurrent 
requests. When set to 0, use the same budget as AutoResizingBuffer memory 
control. Set to a negative value to disable the limit.
+# effectiveMode: hot_reload
+# Datatype: long
+rest_max_total_concurrent_request_body_size_in_bytes=0
+
+# Maximum rows accepted by a single REST write request. Set to 0 or a negative 
value to disable the limit.
+# effectiveMode: hot_reload
+# Datatype: int
+rest_max_insert_rows=100000
+
+# Maximum columns accepted by a single REST write request. Set to 0 or a 
negative value to disable the limit.
+# effectiveMode: hot_reload
+# Datatype: int
+rest_max_insert_columns=1024
+
+# Maximum values accepted by a single REST write request. Set to 0 or a 
negative value to disable the limit.
+# effectiveMode: hot_reload
+# Datatype: long
+rest_max_insert_values=1000000
+
 # Is client authentication required
 # effectiveMode: restart
 # Datatype: boolean


Reply via email to