RAM диск – это виртуальный диск, который создается в свободной области оперативной памяти и с точки зрения операционной системы выглядит как обычный локальный диск. Преимущество RAM Drive – очень высокая скорость чтения и записи на него (до 10 раз быстрее чем SSD, и до 2-3 раз чем NVME M.2). RAM диск можно использовать на компьютерах с большим объёмом RAM для хранения кеша и временных файлов приложений. Чаще всего RAM Drive используется для хранения кэша браузера, временных баз SQL, кэша приложений обработки графики, видео, рендеринга. При перезагрузке компьютера содержимое RAM диска обычно очищается.
Создать RAM диск в Windows 10 и 11
В Windows 10 и 11 нет встроенных средств для создания RAM дисков, поэтому нужно использовать сторонние программы (AMD RAMDisk, ImDisk, PassMark OSFMount, StarWind RAM Disk и т.д.).
В этом примере рассмотрим open-source утилиту ImDisk Toolkit (https://sourceforge.net/projects/imdisk-toolkit/). Ее преимущества:
- Бесплатная
- Компактная
- Нет ограничений на максимальный размер RAM диска
- Позволяет сохранять данные на RAM диске после выключения
- Скачайте и установите программу ImDisk Toolkit, запустив install.bat;
- После установки откройте ярлык RamDisk Configuration на рабочем столе;
- На вкладке Basic нужно указать размер RAM диска (обычно рекомендуется использовать не более чем 20-30% RAM), назначить букву диска, указать нужно ли запускать RAM диск автоматически после загрузки Windows;
- Можно автоматически перенаправить папки TEMP на RAM диск через переменные окружения или через символические ссылки;
- Нажмите Mount чтобы включить RAM Drive. Откройте проводник и проверьте, что в нем появится новый диск указанного вами размера.
- По умолчанию содержимое RAM диска очищается при перезагрузке Windows. Вы можете настроить автоматическое сохранение содержимого RAM диска в локальную папку при выключении компьютера. Для этого перейдите на вкладку Data, укажите целевой каталог, включите Synchronize at System Shutdown. При загрузке операционной системы содержимое этого каталога будет копироваться на RAM диск.
Вы можете перенести кэш приложений на RAM диск с помощью символьный ссылок Windows. Например, чтобы хранить кэш 1С на RAM-диске:
mklink /j %USERPROFILE%\AppData\Local\1C\1cv8 R:\User\Local
mklink /j %USERPROFILE%\AppData\Roaming\1C\1cv8 R:\User\Roaming
Чтобы браузер Google Chrome хранил данные на RAM диске, нужно добавить в ярлык его запуска следующий параметр:
"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --disk-cache-dir="R:\Chrome"
В таком режиме Google Chrome будет меньше изнашивать ваш SSD накопитель.
Скорость чтения и записи на RAM диск можно оценить с помощью утилиты Crystal Disk Mark. В нашем тесте скорость чтения/записи на RAM диск в DDR4 в 2-3 раза больше чем на SSD NVME M.2 накопитель.
Создаем RAM диск с помощью встроенных средств Windows Server
Windows Server вы можете создать RAM диск без использования сторонних программ. Можно выделить часть оперативной памяти сервера с помощью драйвера iSCSI.
Установите компонент iSCSI Target Server с помощью Server Manager (File and Storage Services -> File and iSCSI Services)
Откройте порты для службы iSCSI Service в Windows Defender Firewall. Можно разрешить доступ в графической консоли управления Windows Firewall или вы можете включить правила файервола с помощью PowerShell:
Set-NetFirewallRule -Name MsiScsi-in-TCP -Enabled True
Set-NetFirewallRule -Name MsiScsi-out-TCP -Enabled True
Чтобы разрешить трафик на loopback интерфейсе для iSCSI, измените в ветке реестра HKLM\Software\Microsoft\iSCSI Target значение DWORD параметра AllowLoopBack на 1: Можно изменить значение параметра реестра из PowerShell командой:
Set-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\iSCSI Target' -Name AllowLoopBack -Value 1
Затем создайте виртуальный RAM диск размером 5 Гб:
New-IscsiVirtualDisk -Path "ramdisk:testRAM.vhdx" -Size 5GB
Теперь нужно создать iSCSI таргет:
New-IscsiServerTarget -TargetName targetRAMDisk -InitiatorIds @("IPAddress:10.1.1.200")
Подключите RAM диск в созданный iSCSI таргет:
Add-IscsiVirtualDiskTargetMapping -TargetName targetRAMDisk -DevicePath "ramdisk:testRAM.vhdx"
Откройте консоль Server Manager -> Tools -> iSCSI Initiator.
На вкладке Targets укажите IP адрес вашего сервера, нажмите Quick Connect и подключите ваш iSCSI таргет.
Get-IscsiTarget | Connect-IscsiTarget
Теперь откройте консоль управления дисками (
diskmgmt.msс
), проверьте что у вас появился новый диск размером 5 Гб (это и есть ваш RAM диск). Инициализируйте, разметьте, отформатируйте диск, и назначьте ему букву диска.
Get-Disk | Where partitionstyle -eq 'raw' | Initialize-Disk -PartitionStyle MBR -PassThru | New-Partition -AssignDriveLetter -UseMaximumSize | Format-Volume -FileSystem NTFS -NewFileSystemLabel "disk2" -Confirm:$false
Теперь вы можете перенести необходимые файлы на RAM диск и перенастроить ПО на использование данного диска.
После перезагрузки сервера RAM диск удаляется (вместе со всем содержимым) и его нужно пересоздавать заново.
Но к сожалению при тесте оказалось, что производительность (iOPS) RAM диска, созданного через iSCSI таргет на Windows Server почти в 2 раза меньше, чем у RAM диска на базе ImDisk.
Круто!!!!
А можно полностью автоматизировать, исключив работу с GUI ?
Чтобы можно было монтировать RAM диск при запуске через PS….
Подключить ISCSI Target можно так
Get-IscsiTarget | Connect-IscsiTarget
Инициализировать дик и назначить ему букву тоже можно через PowerShell:
Get-Disk | Where partitionstyle -eq 'raw' | Initialize-Disk -PartitionStyle MBR -PassThru | New-Partition -AssignDriveLetter -UseMaximumSize | Format-Volume -FileSystem NTFS -NewFileSystemLabel "disk2" -Confirm:$false
Соберите это все в один PS и оттестируйте. Если что получится — поделитесь результатом 🙂
Еще примеры использования командлетов PowerShell для управления локальными дисками: https://winitpro.ru/index.php/2019/01/10/powershell-upravlenie-diskami-i-razdelami/
Благодарю за полезную информацию. Запутался немного с адресом New-IscsiServerTarget -TargetName targetRAMDisk -InitiatorIds @(«IPAddress:10.1.1.200»), пока не понял, что вместо 10.1.1.200 нужно подставит адрес сервера.
есть ли какие-то ньюансы при создании такого RAM диска по описанному сценарию в кластере из двух серверов с общей корзиной дисков, где поднят CSV?
Под какие задачи вы планируете RAM диска в кластере? Он будет независимым на каждой из нод….
под tempdb для SQL сервера
Добрый день!
Слетает диск при ребуте. Причем в инициаторе iSCSI конечный объект остается подключен, вот по кнопке «Устройства» — пусто. Что я делаю не так?
Заранее спасибо за ответ.
В статье указано, что такой RAM диск удаляется при перезегрузке. Если хотите его создавать и монтировать каждый раз при загрузке сервера, нужно из указанных команд реализовать powershell скрипт, который запускается при загрузке ОС.
$env:HostIP = (
Get-NetIPConfiguration |
Where-Object {
$_.IPv4DefaultGateway -ne $null -and
$_.NetAdapter.Status -ne «Disconnected»
}
).IPv4Address.IPAddress
if (Test-Path «Z:») {
Remove-IscsiVirtualDiskTargetMapping -TargetName targetRAMDisk -DevicePath «ramdisk:RAMDRIVE.vhdx»
Remove-IscsiServerTarget -TargetName targetRAMDisk
Remove-IscsiVirtualDisk -Path «ramdisk:RAMDRIVE.vhdx»
}
New-IscsiVirtualDisk -Path «ramdisk:RAMDRIVE.vhdx» -Size 48Gb
New-IscsiServerTarget -TargetName targetRAMDisk -InitiatorIds @(«IPAddress:$env:HostIP»)
Add-IscsiVirtualDiskTargetMapping -TargetName targetRAMDisk -DevicePath «ramdisk:RAMDRIVE.vhdx»
New-IscsiTargetPortal -TargetPortalAddress «$env:HostIP» -TargetPortalPortNumber 3260 -InitiatorPortalAddress «$env:HostIP»
Connect-IscsiTarget -NodeAddress iqn.1991-05.com.microsoft:$env:computername-targetramdisk-target
Get-Disk | Where partitionstyle -eq ‘raw’ | Initialize-Disk -PartitionStyle MBR -PassThru | New-Partition -DriveLetter Z -UseMaximumSize | Format-Volume -FileSystem NTFS -NewFileSystemLabel «RAMDRIVE» -Confirm:$false
Винда, правда, 2019.
А на обычной десятке такое нельзя провернуть, только через сторонние утилиты?
Да, можно. Есть куча сторонних утилит: ImDisk, StarWind RAM Disk, OSFMount
Спасибо за ответ, но я имел ввиду нельзя на обычной 10-ке поднять таргет сервер без использвания сторонних утилит? Что-то погуглил, ничего не нашел, частенько вопросы решаются через установку нужных компонентов с помощью PS, а тут гугл молчит. Сейчас воспользовался Asus ROG ramdisk, он даже умеет синхронизировать данные в какой-нить каталог, хотя не тестил еще. Диск создается, файлы положить, прочитать можно, скорости по 16-17к на райзене 5 3600Х
Еще один интересный момент, если пытаться разместить БД MS SQL на таком диске то возникает ошибка(MSSQL понимает, что диск виртуальный и просит разместить ее на томе, где можно получить размер сектора), но возникает только если пытаться разместить БД в директории, если просто в корень бросить, то все норм.
itpro, большое спасибо вам за статью, и спасибо вашим коментаторам!
Написал скрипт автоматизирующий описанное в статье и выложил на github.
https://github.com/griha5/RAMDiskScript — здесь поддерживается и создание, и прописывание
в системе RAM дисков так, чтобы диски восстанавливались при перезагрузке системы.
А вот усечённый вариант:
$diskLetter = 'B:'
$diskSize = 4Gb
if($diskLetter -match "^(?[a-zA-Z]):?$")
{
$diskLetter = $Matches["letter"].ToUpper()
}
else
{
throw "The disk letter (diskLetter) must be specified and be a capital or small letter of the Latin alphabet!"
}
$initiatorIds=@("DnsName:$([System.Net.Dns]::GetHostName())")
$diskPath="ramdisk:RAM-disk-$diskLetter.vhdx"
$targetName="target-RAM-disks"
if (!(Get-WindowsFeature -Name FS-iSCSITarget-Server).Installed) {
Write-Output "The 'iSCSI Target Server' role (FS-iSCSITarget-Server) is not installed"
Write-Output "Installing the iSCSI Target Server role (FS-iSCSITarget-Server)"
Install-WindowsFeature -Name FS-iSCSITarget-Server
}
if ((Get-Service -Name WinTarget).Status -eq 'Stopped') {
Write-Output "The 'Microsoft iSCSI Target Server' service (WinTarget) is not running"
Write-Output "Starting the 'Microsoft iSCSI Target Server' service (WinTarget)"
Start-Service -Name WinTarget
}
$ramDisk = Get-IscsiVirtualDisk -ComputerName localhost | Where Path -EQ $diskPath
if($ramDisk -eq $null)
{
$localDriveLetters = (Get-Volume).DriveLetter | Where-Object { $_ -ne $null } | Sort-Object -Unique
$removableDriveLetters = (Get-WmiObject Win32_DiskDrive | Where-Object { $_.MediaType -eq "RemovableMedia" }).Partitions | ForEach-Object {
$_.Associators | Where-Object { $_.ClassName -eq "Win32_LogicalDisk" } | ForEach-Object { $_.DeviceID }
} | Sort-Object -Unique
$networkDriveLetters = (Get-SmbMapping).LocalPath -replace ':'
$allDriveLetters = ($localDriveLetters + $removableDriveLetters + $networkDriveLetters) | ForEach-Object { $_.ToString().ToUpper() }
if($allDriveLetters.Contains($diskLetter.ToUpper()))
{
throw "The disk letter ${diskLetter}: is already in use!"
}
Write-Output "Creating a new iSCSI virtual disk $diskPath with a size of $diskSize"
$ramDisk = New-IscsiVirtualDisk -Path $diskPath -Size $diskSize -ComputerName localhost
}
else
{
if($ramDisk.Size -ne $diskSize)
{
Write-Output "Resizing the iSCSI virtual disk $diskPath is required"
$target = Get-IscsiServerTarget -ComputerName localhost | Where TargetName -EQ $targetName
if($target -ne $null)
{
if(-not -not ($target.LunMappings | Where-Object { $_.Path -eq $diskPath}))
{
Write-Output "Removing the disk from the iSCSI target $diskPath"
Remove-IscsiVirtualDiskTargetMapping -TargetName $targetName -DevicePath $diskPath -ComputerName localhost
}
}
Write-Output "Removing the old iSCSI virtual disk $diskPath with a size of ${ramDisk.Size}"
Remove-IscsiVirtualDisk -Path $diskPath -ComputerName localhost
Write-Output "Creating a new iSCSI virtual disk $diskPath with a size of $diskSize"
$ramDisk = New-IscsiVirtualDisk -Path $diskPath -Size $diskSize -ComputerName localhost
}
}
$target = Get-IscsiServerTarget -ComputerName localhost | Where TargetName -EQ $targetName
if($target -eq $null) {
Write-Output "Creating an iSCSI target"
$target = New-IscsiServerTarget -TargetName $targetName -InitiatorIds $initiatorIds -ComputerName localhost
} else {
if($target.InitiatorIds -eq $null -or (Compare-Object $target.InitiatorIds $initiatorIds) -ne $null){
Write-Output "Configuring the iSCSI target parameters"
Set-IscsiServerTarget -TargetName $target.TargetName -InitiatorIds $initiatorIds -ComputerName localhost
}
}
if(-not ($target.LunMappings | Where-Object { $_.Path -eq $diskPath}))
{
Write-Output "Adding a mapping for the iSCSI virtual disk"
Add-IscsiVirtualDiskTargetMapping -TargetName $targetName -DevicePath $diskPath -ComputerName localhost
}
if ((Get-Service -Name MSiSCSI).Status -eq 'Stopped')
{
Write-Output "The 'Microsoft iSCSI Initiator Service' service (MSiSCSI) is not running"
Write-Output "Starting the 'Microsoft iSCSI Initiator Service' service (MSiSCSI)"
Start-Service -Name MSiSCSI
}
if(-not (Get-IscsiTargetPortal | Where-Object {
$_.TargetPortalAddress.ToUpper() -eq [System.Net.Dns]::GetHostName().ToUpper() -and
$_.TargetPortalPortNumber -eq 3260 -and
$_.InitiatorPortalAddress -eq $null -and
-not $_.InitiatorInstanceName -and
$_.PSComputerName -eq $null -and
$_.IsDataDigest -eq $False -and
$_.IsHeaderDigest -eq $False }))
{
Write-Output "Creating a new iSCSI portal for $([System.Net.Dns]::GetHostName()):3260"
$portal = New-IscsiTargetPortal -TargetPortalAddress ([System.Net.Dns]::GetHostName()) -TargetPortalPortNumber 3260
}
if(-not (Get-IscsiTarget | Where-Object { $_.NodeAddress -eq $target.TargetIqn}).IsConnected)
{
Write-Output "Connecting to the iSCSI target ${target.TargetIqn}"
$connect = Connect-IscsiTarget -NodeAddress $target.TargetIqn
}
$attempts = 0
$disk = $null
while ($disk -eq $null -and $attempts -lt 3)
{
$attempts++
$disk = Get-Disk | Where SerialNumber -EQ $ramDisk.SerialNumber
if ($disk -eq $null)
{
Write-Output "Waiting for the virtual disk to be detected. Attempt ${attempts} ..."
Start-Sleep -Seconds 1
}
}
if ($disk -eq $null) {
throw "Failed to detect the virtual disk ${ramDisk.SerialNumber}"
}
if($disk.PartitionStyle -ne "MBR")
{
Write-Output "Initializing the disk ${ramDisk.SerialNumber}"
$disk = Initialize-Disk -InputObject $disk -PartitionStyle MBR -PassThru
}
$partition = Get-Partition -Disk $disk
if(-not $partition)
{
Write-Output "Creating a new partition with the letter ${diskLetter}:"
$partition = New-Partition -InputObject $disk -DriveLetter $diskLetter -UseMaximumSize
}
if(-not $partition.DriveLetter)
{
Write-Output "Assigning the disk letter ${diskLetter}:"
$partition | Add-PartitionAccessPath -AccessPath "${diskLetter}:"
}
$volume = Get-Volume -Partition $partition
if(-not $volume.FileSystem)
{
Write-Output "Formatting the disk ${diskLetter}:"
$volume = Format-Volume -Partition $partition -FileSystem NTFS -NewFileSystemLabel "RAMDRIVE_${diskLetter}" -Confirm:$false
}
Движок этого сайта вмешался в код, видно, посчитав название группы в регулярном выражении каким-то управляющим тегом и вырезал его. Так должно работать без ошибок:
$diskLetter = 'B:'
$diskSize = 4Gb
if($diskLetter -match "^([a-zA-Z]):?$")
{
$diskLetter = $Matches[1].ToUpper()
}
else
{
throw "The disk letter (diskLetter) must be specified and be a capital or small letter of the Latin alphabet!"
}
$initiatorIds=@("DnsName:$([System.Net.Dns]::GetHostName())")
$diskPath="ramdisk:RAM-disk-$diskLetter.vhdx"
$targetName="target-RAM-disks"
if (!(Get-WindowsFeature -Name FS-iSCSITarget-Server).Installed) {
Write-Output "The 'iSCSI Target Server' role (FS-iSCSITarget-Server) is not installed"
Write-Output "Installing the iSCSI Target Server role (FS-iSCSITarget-Server)"
Install-WindowsFeature -Name FS-iSCSITarget-Server
}
if ((Get-Service -Name WinTarget).Status -eq 'Stopped') {
Write-Output "The 'Microsoft iSCSI Target Server' service (WinTarget) is not running"
Write-Output "Starting the 'Microsoft iSCSI Target Server' service (WinTarget)"
Start-Service -Name WinTarget
}
$ramDisk = Get-IscsiVirtualDisk -ComputerName localhost | Where Path -EQ $diskPath
if($ramDisk -eq $null)
{
$localDriveLetters = (Get-Volume).DriveLetter | Where-Object { $_ -ne $null } | Sort-Object -Unique
$removableDriveLetters = (Get-WmiObject Win32_DiskDrive | Where-Object { $_.MediaType -eq "RemovableMedia" }).Partitions | ForEach-Object {
$_.Associators | Where-Object { $_.ClassName -eq "Win32_LogicalDisk" } | ForEach-Object { $_.DeviceID }
} | Sort-Object -Unique
$networkDriveLetters = (Get-SmbMapping).LocalPath -replace ':'
$allDriveLetters = ($localDriveLetters + $removableDriveLetters + $networkDriveLetters) | ForEach-Object { $_.ToString().ToUpper() }
if($allDriveLetters.Contains($diskLetter.ToUpper()))
{
throw "The disk letter ${diskLetter}: is already in use!"
}
Write-Output "Creating a new iSCSI virtual disk $diskPath with a size of $diskSize"
$ramDisk = New-IscsiVirtualDisk -Path $diskPath -Size $diskSize -ComputerName localhost
}
else
{
if($ramDisk.Size -ne $diskSize)
{
Write-Output "Resizing the iSCSI virtual disk $diskPath is required"
$target = Get-IscsiServerTarget -ComputerName localhost | Where TargetName -EQ $targetName
if($target -ne $null)
{
if(-not -not ($target.LunMappings | Where-Object { $_.Path -eq $diskPath}))
{
Write-Output "Removing the disk from the iSCSI target $diskPath"
Remove-IscsiVirtualDiskTargetMapping -TargetName $targetName -DevicePath $diskPath -ComputerName localhost
}
}
Write-Output "Removing the old iSCSI virtual disk $diskPath with a size of ${ramDisk.Size}"
Remove-IscsiVirtualDisk -Path $diskPath -ComputerName localhost
Write-Output "Creating a new iSCSI virtual disk $diskPath with a size of $diskSize"
$ramDisk = New-IscsiVirtualDisk -Path $diskPath -Size $diskSize -ComputerName localhost
}
}
$target = Get-IscsiServerTarget -ComputerName localhost | Where TargetName -EQ $targetName
if($target -eq $null) {
Write-Output "Creating an iSCSI target"
$target = New-IscsiServerTarget -TargetName $targetName -InitiatorIds $initiatorIds -ComputerName localhost
} else {
if($target.InitiatorIds -eq $null -or (Compare-Object $target.InitiatorIds $initiatorIds) -ne $null){
Write-Output "Configuring the iSCSI target parameters"
Set-IscsiServerTarget -TargetName $target.TargetName -InitiatorIds $initiatorIds -ComputerName localhost
}
}
if(-not ($target.LunMappings | Where-Object { $_.Path -eq $diskPath}))
{
Write-Output "Adding a mapping for the iSCSI virtual disk"
Add-IscsiVirtualDiskTargetMapping -TargetName $targetName -DevicePath $diskPath -ComputerName localhost
}
if ((Get-Service -Name MSiSCSI).Status -eq 'Stopped')
{
Write-Output "The 'Microsoft iSCSI Initiator Service' service (MSiSCSI) is not running"
Write-Output "Starting the 'Microsoft iSCSI Initiator Service' service (MSiSCSI)"
Start-Service -Name MSiSCSI
}
if(-not (Get-IscsiTargetPortal | Where-Object {
$_.TargetPortalAddress.ToUpper() -eq [System.Net.Dns]::GetHostName().ToUpper() -and
$_.TargetPortalPortNumber -eq 3260 -and
$_.InitiatorPortalAddress -eq $null -and
-not $_.InitiatorInstanceName -and
$_.PSComputerName -eq $null -and
$_.IsDataDigest -eq $False -and
$_.IsHeaderDigest -eq $False }))
{
Write-Output "Creating a new iSCSI portal for $([System.Net.Dns]::GetHostName()):3260"
$portal = New-IscsiTargetPortal -TargetPortalAddress ([System.Net.Dns]::GetHostName()) -TargetPortalPortNumber 3260
}
if(-not (Get-IscsiTarget | Where-Object { $_.NodeAddress -eq $target.TargetIqn}).IsConnected)
{
Write-Output "Connecting to the iSCSI target ${target.TargetIqn}"
$connect = Connect-IscsiTarget -NodeAddress $target.TargetIqn
}
$attempts = 0
$disk = $null
while ($disk -eq $null -and $attempts -lt 3)
{
$attempts++
$disk = Get-Disk | Where SerialNumber -EQ $ramDisk.SerialNumber
if ($disk -eq $null)
{
Write-Output "Waiting for the virtual disk to be detected. Attempt ${attempts} ..."
Start-Sleep -Seconds 1
}
}
if ($disk -eq $null) {
throw "Failed to detect the virtual disk ${ramDisk.SerialNumber}"
}
if($disk.PartitionStyle -ne "MBR")
{
Write-Output "Initializing the disk ${ramDisk.SerialNumber}"
$disk = Initialize-Disk -InputObject $disk -PartitionStyle MBR -PassThru
}
$partition = Get-Partition -Disk $disk
if(-not $partition)
{
Write-Output "Creating a new partition with the letter ${diskLetter}:"
$partition = New-Partition -InputObject $disk -DriveLetter $diskLetter -UseMaximumSize
}
if(-not $partition.DriveLetter)
{
Write-Output "Assigning the disk letter ${diskLetter}:"
$partition | Add-PartitionAccessPath -AccessPath "${diskLetter}:"
}
$volume = Get-Volume -Partition $partition
if(-not $volume.FileSystem)
{
Write-Output "Formatting the disk ${diskLetter}:"
$volume = Format-Volume -Partition $partition -FileSystem NTFS -NewFileSystemLabel "RAMDRIVE_${diskLetter}" -Confirm:$false
}
Спасибо за труд!!!