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_KEYwith value"route"identifies labels used for routing decisions. - Route Label Value: Tenant-oriented identifiers such as
dev,prod, ortestthat distinguish traffic streams. - Label Service: The
InsLabelServiceAdapterprovides the persistent mapping between label combinations and running service instances. - Roulette: The random load-balancing algorithm implemented in
DefaultLabelGatewayRouter.roulettethat 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:
- Exact match: If the request carries a matching route label (e.g.,
dev), the label service returns all instances registered with that label. - Load balancing: When multiple instances match, the gateway selects one randomly via roulette.
- No label fallback: If the request lacks labels entirely, the gateway routes to the unlabeled default pool.
- No match error: If a label value has no registered instances (e.g.,
staging), the system returns aCANNOT_ROETE_SERVICEerror.
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
RouteLabelobjects from requests against registered instance labels in theInsLabelService. - The routing pipeline involves parsing (via
RouteLabelParser), conversion (viaGenericRoueLabelParser), instance discovery (viaAbstractLabelGatewayRouter), and selection (viaDefaultLabelGatewayRouter.roulette). - Custom route labels are configured per service instance by setting the
ROUTE_KEYentry in the instance metadata throughInstanceLabelClient. - Tenant traffic direction is achieved by supplying matching label values as query parameters (
labelsorlabelsRoute) 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →