Linkis Label-Based Routing: How It Works and How to Configure Custom Route Labels for Multi-Tenant Traffic

Linkis routes HTTP requests to backend service instances by matching route labels parsed from query parameters or request bodies against labels registered in the Instance-Label Service, falling back to unlabeled instances when no match exists.

Apache Linkis provides a sophisticated label-based routing mechanism that enables multi-tenant traffic isolation by directing requests to specific service instances based on custom metadata labels. This system allows organizations to separate development, production, and testing workloads without modifying gateway code, as implemented in the apache/linkis repository.

How Linkis Label-Based Routing Works

The routing flow traverses six distinct phases, from initial request parsing to final instance selection. Understanding this pipeline is essential for configuring custom route labels effectively.

Step 1: Parsing Route Labels from Requests

The GatewayRouterConfiguration creates a DefaultLabelGatewayRouter that orchestrates the routing process. This router maintains a list of RouteLabelParser implementations responsible for extracting labels from incoming HTTP requests.

According to the source code in DefaultLabelGatewayRouter.scala, parsers read both query parameters (labels or labelsRoute) and request body JSON to construct a java.util.List[RouteLabel]. The DSSRouteLabelParser handles query parameter extraction, while the generic parser processes JSON payloads.

Step 2: Converting Parsed Data to RouteLabel Objects

Once raw label data is extracted, the GenericRoueLabelParser (note the typo in the source filename) converts JSON representations into concrete Label objects via the LabelBuilderFactory. Only objects implementing org.apache.linkis.manager.label.entity.route.RouteLabel are retained for subsequent routing decisions.

This conversion ensures type safety and validates that labels intended for routing actually support the routing interface.

Step 3: Searching Candidate Instances by Label

The AbstractLabelGatewayRouter.route method delegates instance discovery to insLabelService.searchInstancesByLabels(routeLabels). The Instance-Label Service, implemented by InsLabelServiceAdapter, maintains a mapping of labelKey → labelValue → ServiceInstance in its registry.

This service acts as the central directory for all label-to-instance relationships in the Linkis cluster.

Step 4: Fallback to Default Instances

When requests lack route labels or when no instances match the specified criteria, the system invokes getDefaultInstances(applicationName). This method retrieves all RPC-registered instances and filters out any that have label-based registrations, leaving only the "unlabeled" pool for fallback routing.

This ensures that legacy clients or unconfigured tenants still receive service through a default instance group.

Step 5: Instance Selection via Roulette

DefaultLabelGatewayRouter.selectInstance implements the final selection logic. The method first checks for an explicit serviceInstance in the request context. If absent, it filters candidates by applicationName (when supplied) and executes a roulette selection using Random.nextInt over the remaining instances.

The roulette also validates instance liveness by calling retainAllInRegistry, removing any candidates not currently registered in the service registry.

Step 6: Request Forwarding

After selection, the chosen ServiceInstance (containing host and port information) is injected into gatewayContext.getGatewayRoute.setServiceInstance. The gateway then forwards the HTTP request to the selected backend instance, completing the routing cycle.

Core Routing Concepts

Understanding these fundamental concepts is crucial for implementing multi-tenant routing:

  • Route Label Key: The constant LabelKeyConstant.ROUTE_KEY with value "route" identifies labels used for routing decisions.
  • Route Label Value: Tenant-oriented identifiers such as dev, prod, or test that distinguish traffic streams.
  • Label Service: The InsLabelServiceAdapter provides the persistent mapping between label combinations and running service instances.
  • Roulette: The random load-balancing algorithm implemented in DefaultLabelGatewayRouter.roulette that distributes traffic evenly among matching instances.

Configuring Custom Route Labels for Multi-Tenant Traffic

Implementing multi-tenant isolation requires configuration at both the service instance level and the client request level.

Registering Route Labels on Service Instances

When a Linkis service instance starts, it registers its metadata through SpringCloudInstanceLabelClient (or another InstanceLabelClient implementation). The registration attaches route labels to the instance's persistent metadata.

// Inside SpringCloudInstanceLabelClient.registerLabel(...)
val labels = new util.HashMap[String, Object]()
// Attach a custom route label, e.g. "dev"
labels.put(LabelKeyConstant.ROUTE_KEY, "dev")
insLabelRefreshRequest.setLabels(labels)

Source: SpringCloudInstanceLabelClient.scala

Defining Tenant-Specific Label Values

Organizations can define arbitrary label values to represent tenant boundaries:

  • Development tenant → label dev
  • Production tenant → label prod
  • Testing tenant → label test

Consistency is critical: the value used during instance registration must match the value sent in client requests.

Passing Labels via Query Parameters

The gateway configuration in DSSGatewayConfiguration.scala defines the query parameter names for label extraction:

val DSS_URL_LABEL_PREFIX   = CommonVars("wds.dss.gateway.url.prefix.name", "labels")
val DSS_URL_ROUTE_LABEL_PREFIX = CommonVars("wds.dss.gateway.url.prefix.name", "labelsRoute")

Clients can specify labels using either parameter:


GET /gateway/entrance/execute?labels=dev
GET /gateway/entrance/execute?labelsRoute=prod

Embedding Labels in Request Body JSON

For POST requests, labels can be embedded within the JSON payload. The GenericRoueLabelParser extracts the labels field and builds RouteLabel objects:

{
  "labels": {
    "route": "test"
  },
  "code": "select * from production_table",
  "engineType": "spark"
}

Routing Behavior and Fallback Logic

The routing engine applies the following precedence rules:

  1. Exact match: If the request carries a matching route label (e.g., dev), the label service returns all instances registered with that label.
  2. Load balancing: When multiple instances match, the gateway selects one randomly via roulette.
  3. No label fallback: If the request lacks labels entirely, the gateway routes to the unlabeled default pool.
  4. No match error: If a label value has no registered instances (e.g., staging), the system returns a CANNOT_ROETE_SERVICE error.

End-to-End Multi-Tenant Configuration Example

Consider a scenario with two Spark engine instances serving different tenants.

Engine-A Configuration (Development):


# In Engine-A configuration (application.conf)

linkis.instance.label.ROUTE_KEY = dev

Engine-B Configuration (Production):

linkis.instance.label.ROUTE_KEY = prod

Both instances register their labels via the SpringCloudInstanceLabelClient upon startup.

Development Tenant Request:

POST http://gateway/linkis/entrance/execute?labels=dev
Content-Type: application/json

{
  "code": "print('Hello development environment')",
  "engineType": "spark"
}

The DSSRouteLabelParser extracts labels=dev, DefaultLabelGatewayRouter queries InsLabelService for instances bearing route=dev, and the request routes to Engine-A.

Production Tenant Request:

POST http://gateway/linkis/entrance/execute?labels=prod
Content-Type: application/json

{
  "code": "analyze production_dataset",
  "engineType": "spark"
}

This request follows the same flow but selects Engine-B based on the prod label match.

Summary

  • Linkis label-based routing matches RouteLabel objects from requests against registered instance labels in the InsLabelService.
  • The routing pipeline involves parsing (via RouteLabelParser), conversion (via GenericRoueLabelParser), instance discovery (via AbstractLabelGatewayRouter), and selection (via DefaultLabelGatewayRouter.roulette).
  • Custom route labels are configured per service instance by setting the ROUTE_KEY entry in the instance metadata through InstanceLabelClient.
  • Tenant traffic direction is achieved by supplying matching label values as query parameters (labels or labelsRoute) or within request body JSON.
  • The system provides automatic fallback to unlabeled instances when no route labels are specified, ensuring backward compatibility.

Frequently Asked Questions

What happens if a request contains a route label that no instance has registered?

If the request specifies a label value (e.g., labels=staging) that has no corresponding instances in the InsLabelService registry, the label search returns an empty set. This triggers a CANNOT_ROETE_SERVICE error, indicating that no suitable service instance exists for the requested tenant label. To resolve this, ensure at least one instance registers with the matching label key-value pair.

Can I use multiple route labels simultaneously for finer-grained routing?

Yes, the RouteLabelParser implementations return a java.util.List[RouteLabel], allowing multiple labels to be specified in a single request. The AbstractLabelGatewayRouter passes this list to searchInstancesByLabels, which finds instances matching all specified labels. This enables complex routing scenarios combining tenant identifiers with environment or version labels.

How does Linkis handle load balancing when multiple instances match the same route label?

When multiple instances match the requested route labels, DefaultLabelGatewayRouter.selectInstance performs a roulette selection using Random.nextInt over the candidate list. This random distribution ensures even load across identically-labeled instances. The method also filters out instances not present in the current registry via retainAllInRegistry, preventing routing to unhealthy or terminated services.

Where do I configure the route label for a Linkis service instance?

Configure the route label in the service instance's configuration file (typically application.conf or via environment variables) by setting linkis.instance.label.ROUTE_KEY to your desired tenant value. During startup, the SpringCloudInstanceLabelClient reads this configuration and registers the label with the central InsLabelService through the registerLabel method. This registration persists the mapping between the label value and the instance's network location.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →