How ResourceManagerPersistence Handles Engine Resource Allocation in Apache Linkis: A Deep Dive into ResourceLabel Entities
ResourceManagerPersistence in Apache Linkis manages engine resource allocation by persisting PersistenceResource objects to a relational database and binding them to metadata through ResourceLabel entities (PersistenceLabel and PersistenceLabelRel), enabling label-based resource discovery and exclusive locking.
Apache Linkis orchestrates distributed computation engines across heterogeneous clusters using a sophisticated resource management system. The ResourceManagerPersistence layer provides the durable storage foundation for engine resource allocation, mapping CPU, memory, and GPU metrics to specific engine instances through the ResourceLabel entity system. This persistence layer, implemented primarily in DefaultResourceManagerPersistence, bridges the gap between transient engine processes and permanent resource records using MyBatis mappers.
The ResourceManagerPersistence Architecture
The ResourceManagerPersistence interface defines the contract for resource storage operations, while DefaultResourceManagerPersistence provides the concrete implementation. This class acts as a thin DAO façade that delegates SQL execution to MyBatis mappers including ResourceManagerMapper, LabelManagerMapper, and NodeManagerMapper.
The persistence layer stores three core entity types: PersistenceResource (holding actual resource metrics), PersistenceLabel (containing metadata labels), and PersistenceLabelRel (managing many-to-many relationships between resources and labels).
Engine Resource Allocation Lifecycle
Linkis manages engine resources through a complete lifecycle from registration to cleanup. Each phase involves specific persistence operations that maintain consistency between active engines and database records.
Resource Registration and Label Binding
When an engine or EngineManager (EM) starts, it registers its available resources through ResourceManagerPersistence.registerResource(...). In DefaultResourceManagerPersistence (source L71‑L77), this method inserts a PersistenceResource row containing the instance identifier, resource type, ticket ID, and serialized resource metrics.
Immediately after resource insertion, the implementation establishes label associations. It fetches label IDs belonging to the engine instance via labelManagerMapper.getLabelIdsByInstance, then creates the mapping through labelManagerMapper.addLabelsAndResource (source L88‑L93). This two-phase commit ensures every resource record links to its descriptive metadata.
Updating Engine Allocations
Dynamic resource scaling triggers updates through nodeResourceUpdate. The implementation first retrieves the existing resource ID using the ticket identifier (getNodeResourceUpdateResourceId), then updates the PersistenceResource row with new CPU, memory, or GPU values (source L61‑L68). This pattern ensures atomic updates without creating duplicate resource records.
Exclusive Resource Locking
For scenarios requiring dedicated resource allocation, lockResource provides atomic registration and label binding. This method combines resource insertion with immediate label relation creation in a single logical operation (source L92‑L97). By executing both steps together, the persistence layer guarantees that a resource is "locked" to a specific label set, preventing concurrent allocation attempts from other schedulers.
Label-Based Resource Discovery
Clients such as the Linkis Scheduler and Resource Pool discover engines through label queries. The getResourceByLabel method delegates to labelManagerMapper to execute SQL joins between the label table and resource table (source L95‑L103). This enables queries like "find all Spark engines with 8GB memory" by matching label key-value pairs against persisted resource records.
Resource Cleanup
When engine instances terminate, deleteServiceInstanceResource removes both the resource rows and their label relations (source L44‑L51). For ticket-based temporary resources, deleteExpiredTicketIdResource purges records that have exceeded their session timeout, preventing database bloat from orphaned engine sessions.
Understanding ResourceLabel Entities
The ResourceLabel system provides the metadata layer that makes engine resources discoverable and categorizable. Three entities cooperate to implement this labeling mechanism.
PersistenceLabel
PersistenceLabel represents concrete metadata tags such as engineType=Spark, resourcePool=default, or tenant=production. Defined in (source L25‑L35, L86‑L94), this entity extends GenericLabel to reuse label key/value handling logic. Key fields include:
labelKeyandvalue(inherited from GenericLabel)stringValue(serialized representation)labelValueSize(cardinality for optimization)createTimeandupdateTime(temporal tracking)
PersistenceLabelRel
PersistenceLabelRel serves as the junction table entity that implements the many-to-many relationship between resources and labels. This entity extends PersistenceLabel by adding a resourceId field that acts as a foreign key to PersistenceResource.id (source L20‑L30). When persisted, these records populate the persistence_label_rel database table.
PersistenceResource
While not detailed in the entity excerpt, PersistenceResource stores the actual quantitative metrics (CPU cores, memory bytes, GPU devices) alongside a ticketId that uniquely identifies the engine session. The resource type field distinguishes between Spark, Hive, Python, and other engine categories.
The Label-Resource Mapping Mechanism
The binding process operates through three distinct steps:
-
Label Resolution: When registering a resource, the system queries existing labels via
labelManagerMapper.getLabelIdsByInstanceto retrieve the integer IDs corresponding to the engine's metadata tags. -
Relation Persistence: The method
addLabelsAndResource(resourceId, labelIds)inserts rows into the relation table, establishing the many-to-many link between the new resource and its descriptive labels. -
Discovery Joins: Query methods like
getResourcesByLabelexecute SQL JOIN operations betweenpersistence_label_relandpersistence_resource, allowing efficient retrieval of all engine instances matching specific label criteria.
Practical Implementation Examples
Linkis manager services interact with the persistence layer through the ResourceManagerPersistence interface. Below are representative usage patterns:
// Register a new engine resource with automatic label mapping
PersistenceResource resource = new PersistenceResource();
resource.setInstance("engine01:10001");
resource.setResourceType("spark");
resource.setTicketId("ticket-1234");
resource.setResourceInfo("{\"cpu\":4,\"memory\":8192}");
resourceManagerPersistence.registerResource(resource);
// Label mapping handled internally via LabelManagerMapper
// Update resource allocation after dynamic scaling
PersistenceResource updatedResource = new PersistenceResource();
updatedResource.setCpu(8);
updatedResource.setMemory(16384);
resourceManagerPersistence.nodeResourceUpdate("ticket-1234", updatedResource);
// Discover all engines matching a specific label
Label sparkLabel = new GenericLabel();
sparkLabel.setLabelKey("engineType");
sparkLabel.setStringValue("Spark");
List<PersistenceResource> sparkEngines =
resourceManagerPersistence.getResourceByLabel(sparkLabel);
// Lock resource for exclusive use with specific labels
List<Integer> exclusiveLabelIds = Arrays.asList(101, 102);
PersistenceResource lockedResource = new PersistenceResource();
// ... set resource properties
resourceManagerPersistence.lockResource(exclusiveLabelIds, lockedResource);
Key Source Files in the Persistence Layer
Summary
- ResourceManagerPersistence provides the durable storage layer for Linkis engine resources, implemented by
DefaultResourceManagerPersistenceusing MyBatis mappers. - Engine resources follow a complete lifecycle: registration with label binding, dynamic updates through
nodeResourceUpdate, exclusive locking vialockResource, discovery through label queries, and cleanup on termination. - ResourceLabel entities consist of
PersistenceLabel(metadata definitions),PersistenceLabelRel(many-to-many join records), andPersistenceResource(actual capacity metrics). - The label-resource mapping enables sophisticated scheduling by allowing the ResourceManager to query engines by characteristics like
engineType,resourcePool, or custom tenant tags. - All persistence operations execute through the
ResourceManagerMapperandLabelManagerMapperinterfaces, with SQL mappings defined in corresponding XML configuration files.
Frequently Asked Questions
What is the difference between PersistenceLabel and PersistenceLabelRel?
PersistenceLabel stores the actual metadata tag definitions (such as engineType=Spark), while PersistenceLabelRel acts as a junction table entity that links those label definitions to specific resource records via foreign keys. When an engine registers, the system creates or references PersistenceLabel records for its metadata, then creates PersistenceLabelRel entries to bind those labels to the engine's PersistenceResource record.
How does ResourceManagerPersistence ensure atomic resource locking?
The lockResource method in DefaultResourceManagerPersistence combines resource registration and label relation creation into a single transactional operation. By executing both the registerResource database insert and the addLabelsAndResource mapping insert together, the implementation guarantees that a resource cannot be partially registered or claimed by multiple concurrent allocation requests.
Where are the actual SQL mappings defined for these operations?
While the Java interfaces ResourceManagerMapper and LabelManagerMapper define the method signatures, the actual SQL statements are defined in MyBatis XML mapper files located in the resources directory (typically under src/main/resources/mappers). These XML files map Java method calls to specific INSERT, UPDATE, SELECT, and DELETE statements targeting tables like persistence_resource, persistence_label, and persistence_label_rel.
How does label-based resource discovery work in practice?
When the Linkis Scheduler requests engines matching specific criteria, it constructs PersistenceLabel objects representing the desired characteristics. The getResourceByLabel method queries the database using a JOIN between the label table and resource table through the relation entity. This returns only PersistenceResource records that possess all specified labels, enabling efficient filtering of engine instances by their metadata rather than just their IDs.
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 →