Plug-in performance reference

更新时间:
复制 MD 格式

Microservices Engine (MSE) cloud-native gateway supports built-in and custom plug-ins. The following benchmarks compare request latency across plug-in types and languages to help you evaluate performance when choosing a plug-in strategy.

Built-in plug-in latency

Built-in plug-ins operate at the microsecond level.

Plug-inLatency per request
key-auth~20 microseconds
basic-auth~30 microseconds

Custom plug-in latency by language

MSE supports custom plug-in development in C++, Golang, Rust, and AssemblyScript.

Benchmark setup

All four language implementations run identical processing logic on each incoming request:

  1. Add 20 request headers.

  2. Read those 20 headers.

  3. Remove all 20 headers.

This workload exercises the core header-manipulation APIs, providing a consistent basis for cross-language comparison.

Results

LanguageRequest latency
C++0.19 ms
Golang0.20 ms
Rust0.21 ms
AssemblyScript0.21 ms

All four languages deliver similar per-request latency, within 0.02 ms of each other. Language choice has minimal impact on plug-in performance for typical header-processing workloads. Choose based on team expertise and ecosystem preferences rather than performance alone.

Benchmark code

Each sample below implements the same logic: add 20 request headers, read them, then remove them.

C++

FilterHeadersStatus PluginContext::onRequestHeaders(uint32_t, bool) {
  std::string fake_header_key_prefix = "fake_key_";
  std::string fake_header_value_prefix = "fake_value_";
  // Add 20 headers
  for (size_t i = 0; i < 20; i++) {
    addRequestHeader(fake_header_key_prefix + std::to_string(i),
                     fake_header_value_prefix + std::to_string(i));
  }

  // Read 20 headers
  for (size_t i = 0; i < 20; i++) {
    getRequestHeader(fake_header_key_prefix + std::to_string(i));
  }

  // Remove 20 headers
  for (size_t i = 0; i < 20; i++) {
    removeRequestHeader(fake_header_key_prefix + std::to_string(i));
  }
  return FilterHeadersStatus::Continue;
}

Golang

func (ctx *httpContext) OnHttpRequestHeaders(numHeaders int, endOfStream bool) types.Action {
        fake_header_key_prefix := "fake_key_"
        fake_header_value_prefix := "fake_value_"
        for i := 0; i < 20; i++ {
                proxywasm.AddHttpRequestHeader(fake_header_key_prefix+strconv.Itoa(i),
                        fake_header_value_prefix+strconv.Itoa(i))
        }
        for i := 0; i < 20; i++ {
                proxywasm.GetHttpRequestHeader(fake_header_key_prefix + strconv.Itoa(i))
        }
        for i := 0; i < 20; i++ {
                proxywasm.RemoveHttpRequestHeader(fake_header_key_prefix + strconv.Itoa(i))
        }
        return types.ActionContinue
}

Rust

fn on_http_request_headers(&mut self, _: usize, _: bool) -> Action {
        for i in 0..20 {
            let key = "fake_key_".to_string() + &i.to_string();
            let value = "fake_value_".to_string() + &i.to_string();
            self.set_http_request_header(&key, Some(&value));
        }
        for i in 0..20 {
            let key = "fake_key_".to_string() + &i.to_string();
            self.get_http_request_header(&key);
        }
        for i in 0..20 {
            let key = "fake_key_".to_string() + &i.to_string();
            self.set_http_request_header(&key, None);
        }
        Action::Continue
    }

AssemblyScript

onRequestHeaders(a: u32, end_of_stream: bool): FilterHeadersStatusValues {
    let fake_header_key_prefix: string = "fake_key_";
    let fake_header_value_prefix: string = "fake_value_";
    for (let i = 0; i < 20; i++) {
       stream_context.headers.request.add(fake_header_key_prefix + i.toString(), fake_header_value_prefix + i.toString())
    }
    for (let i = 0; i < 20; i++) {
       stream_context.headers.request.get(fake_header_key_prefix + i.toString())
    }
    for (let i = 0; i < 20; i++) {
       stream_context.headers.request.remove(fake_header_key_prefix + i.toString())
    }
    return FilterHeadersStatusValues.Continue;
  }