Memlink
Introduction
In cloud scenarios, as the memory capacity on hosts increases, the cost of memory continues to rise (exceeding 50%), and the overall memory utilization of most hosts is low. Therefore, technical means are needed to improve host memory utilization. From a single-host perspective, the biggest challenge is how to fully reclaim free memory inside virtual machines. Due to the isolation property of virtualization, the Host cannot perceive the memory semantics inside the Guest (including free, used, etc.), so the memory of virtual machines in current cloud scenarios is pre-occupied. For example, a 4U8G virtual machine needs to occupy 8GB of huge page memory when created, and during operation, it always occupies 8GB of huge page memory, even if the actual usage inside the virtual machine may be much lower than 8GB.
Memlink provides two core subsystems:
- Balloon Subsystem: Perceives memory usage inside the Guest through the virtio-balloon device and automatically reclaims free memory to improve Host memory utilization.
- Page Score Subsystem: Scans page access heat of virtual machine processes through the etmem kernel interface, generates page access scores (page score), and provides a query interface through Unix domain socket service, providing decision basis for memory optimization strategies such as page migration and memory compression.
Only supports aarch64 architecture.
Software Architecture
src/
├── main.c # Main entry, initializes subsystems and enters main loop
├── memlinkd.conf # Configuration file
├── memlinkd.service # systemd service file
├── CMakeLists.txt # CMake build script
├── balloon/ # Balloon subsystem
│ └── balloon.c/h # Balloon core logic and driver
├── page_score/ # Page Score subsystem
│ └── page_score.c/h # Page Score VM management (page scanning, score query)
├── sdk/ # External SDK
│ ├── memlink_sdk.c/h # Client SDK library (libmemlink_sdk.so)
│ └── memlink_example.c # SDK example tool
├── util/ # Utility modules
│ ├── config.c/h # Configuration file parsing
│ ├── server.c/h # Unix domain socket query service (single-threaded)
│ ├── vm_manager.c/h # VM lifecycle manager
│ ├── libvirt_helper.c/h # libvirt event listener wrapper
│ ├── etmem_scan_helper.c/h # etmem kernel interface wrapper (idle page scanning)
│ ├── log.c/h # Log module
│ └── util.c/h # General utilities
└── sysmonitor/
└── memlinkd-daemon # sysmonitor daemon configuration
Installation Guide
- Enter the project directory
- Install build dependencies:
yum-builddep memlinkd.spec - Package the source code:
tar jcvf memlinkd.tar.bz2 --exclude=.git src - Copy the package to the rpm build directory (create the directory if it doesn't exist):
cp memlinkd.tar.bz2 /root/rpmbuild/SOURCES/ - Execute the build:
rpmbuild -ba memlinkd.spec - Install memlink:
cd /root/rpmbuild/RPMS/aarch64/ && rpm -ivh memlinkd-* - Build artifacts after installation:
/usr/sbin/memlinkd— Main service program/etc/memlinkd.conf— Configuration filelibmemlink_sdk.so— SDK shared librarymemlink_example— SDK example tool
Software Dependencies
- libvirt / libvirt-devel
- libboundscheck
- systemd-units
- gnutls / gnutls-devel
- cmake
- CUnit-devel (for testing)
Usage Guide
Configuration File
memlink's configuration file is located at /etc/memlinkd.conf. All parameters are described below:
Balloon Subsystem Parameters
| Parameter | Value Range | Default | Description |
|---|---|---|---|
balloon_enable |
0 / 1 | 1 | Whether to enable the balloon subsystem |
balloon_target_used_percent |
[120, 10000] | 130 | Calculate the memory amount that a single VM should retain using the VM's used memory. For example, if configured as 130 (i.e., 1.3x), VM specification=8GB, used=4GB, then target=4GB * 1.3 = 5.2GB, meaning maximum reclaimable is 8GB - 5.2GB = 2.8GB. |
balloon_target_max_total_percent |
[0, 100] | 50 | Minimum percentage of memory to retain for the VM. For example, if configured as 50%, VM specification=10GB, then minimum retain is 10GB * 50% = 5GB, meaning maximum reclaim is 5GB. |
Page Score Subsystem Parameters
| Parameter | Value Range | Default | Description |
|---|---|---|---|
page_score_enable |
0 / 1 | 1 | Whether to enable the page score subsystem |
page_score_poll_cycle_sec |
[1, 3600] | 10 | Page score page scanning cycle (seconds) |
Other Parameters
| Parameter | Value Range | Default | Description |
|---|---|---|---|
host_info_poll_time |
[100, 6000] | 1000 | Host and VM information polling cycle (milliseconds) |
init_sem_wait_timeout |
[10000, 3600000] | 600000 | Initialization semaphore wait timeout (milliseconds) |
Configuration File Example
balloon_enable=1
balloon_target_used_percent = 130
balloon_target_max_total_percent = 50
page_score_enable=0
page_score_poll_cycle_sec=30
Running memlinkd
- Start memlinkd:
systemctl start memlinkd - VM memory balloon settings need to add the balloon device in the VM's XML configuration file. Add the following fields when starting the VM:
<domain type='kvm' id='1'>
<memoryBacking>
<hugepages>
<page size='2' unit='MiB'/>
</hugepages>
<allocation mode="hugepage-ondemand"/>
</memoryBacking>
...
<devices>
...
<memballoon model='virtio'>
<stats period='5'/>
</memballoon>
</devices>
</domain>
Page Score Query Interface
After memlinkd starts, it will open a Unix domain socket service (path /var/run/memlinkd.sock), providing page score query capability. Supports two types of requests:
Query Page Access Score (reqid: 1)
- Protocol: Unix domain socket text protocol, request format is
<reqid> <pid> <addr>\n - Example:
1 12345 7f000000 - Response:
OK <score>orERR <message> - Purpose: Query the access heat score of the specified virtual address page of the specified QEMU process (0-65535, higher value indicates more frequent access)
Query and Clear Access Count (reqid: 2)
- Protocol: Unix domain socket text protocol, request format is
<reqid> <pid>\n - Example:
2 12345 - Response:
OK <count>orERR <message> - Purpose: Query the total page access count of the specified QEMU process since the last query, and automatically clear after query
SDK Usage
memlink provides a C language SDK (libmemlink_sdk.so), which encapsulates the Unix domain socket query protocol for easy integration with external programs.
SDK API
// Query page access score
int QueryPageScore(uint64_t addr, int pid, uint64_t *score);
// Query and clear page access count
int QueryAndClearPageAccessedCount(int pid, uint64_t *accessed_count);
SDK Example Tool
memlink_example is the SDK's command-line example tool:
# Query page score
memlink_example -p 12345 -a 7f000000
# Query total access count
memlink_example -p 12345 -c
Integration Testing
cd tests/integration/
./test_memlinkd.sh
The test script will automatically check the memlinkd binary, configuration file, libvirtd status, and running VM status.