33 votos

Windows Server 2008 R2 Metarchivo el Uso de la RAM

Tengo un servidor que ejecuta Windows Server 2008 R2 x64 con 4GB de memoria RAM, que alberga alrededor de 2-3 millones de archivos, la mayoría de los cuales son archivos de imagen.

Más de un curso de una semana, he notado que las aplicaciones en el servidor fueron ralentizando a paso de tortuga, debido a un exceso de paginación en el disco debido a la baja de la memoria, que tiene un golpe de efecto a todos los servicios actualmente en ejecución, causando un gran problema de rendimiento.

Tras la investigación en el Administrador de Tareas, me di cuenta de que casi todos los 4GB estaba en uso, pero cuando usted mira en la pestaña de Procesos, la suma de todos el uso de la memoria no se suman y en la mayoría de sólo 1,5 GB que se supone que esté en uso.

El uso de Google para encontrar una solución, parece que la mayoría de la RAM se utiliza en la "Metarchivo", que es una memoria caché de NTFS información para los archivos en el sistema de archivos para que el sistema no tenga que consultar la MFT para la información de nuevo. Esta caché nunca se borran o marcados como "caché" en el Administrador de Tareas o como "en Espera" en Sysinternal del RamMap.

Hubo una sugerencia para instalar el KB979149 revisión pero al tratar de instalarlo, dice que "Esta actualización no es aplicable a su equipo".

La única temporal correcciones que he encontrado hasta el momento son:

  1. Uso RAMmap de Sysinternals para "Vacío Sistema de Trabajo" cada 1-3 días que marca la caché como "en espera" y "caché" en el Administrador de Tareas de modo que la RAM puede ser utilizado por otras aplicaciones.
  2. Reinicie la máquina, lo cual es indeseable ya que este servidor es el que sirve a los sitios web públicos.

En el momento en que estoy teniendo para realizar la 2. revisión cada pocos días, para evitar que lleguen cuello de botella de los niveles.

Antes: (800 MB de RAM usadas - otras aplicaciones no pueden utilizar esta RAM)

BeforeClear.png

Después de: (800 MB de RAM marcado como caché - disponible para otras aplicaciones)

AfterClear.png

Así que mi pregunta es: ¿ cualquier método que existen por ahí para limitar el uso de la memoria RAM de este metarchivo?

16voto

BeowulfNode42 Puntos 1434

El mejor método para tratar con este problema es el uso de la SetSystemFileCacheSize API de MS KB976618 indica.

No periódicamente borrar la caché

El uso de la SetSystemFileCacheSize función en lugar de la eliminación de la caché periódicamente mejora el rendimiento y la estabilidad. Borrar la caché periódicamente el resultado será demasiado metarchivo y otra información de ser eliminadas de la memoria, y de windows, tendrá que volver a leer la información necesaria de vuelta en la memoria ram de la unidad de disco duro. Esto crea una repentina y severa caída en el rendimiento durante varios segundos cada vez que borrar la caché, seguido por el buen desempeño que poco a poco se degrada a medida que la memoria se llena con metarchivo de datos.

El uso de la SetSystemFileCacheSize función establece el mínimo y el máximo que resultará en windows marcar el exceso de edad de metarchivo de datos como de espera de memoria que las normales funciones de almacenamiento en caché puede utilizar o desechar de acuerdo a las actuales demandas de recursos y normal de la caché de prioridades. Esto también permite que más de metarchivo de datos de la memoria activa máxima que se establece, para estar en la memoria como en espera de datos si windows no se está usando la memoria para otra cosa, mientras que el mantenimiento de un montón de memoria disponible. Esta es la situación ideal de mantener las características de rendimiento del sistema de buenas todo el tiempo.

La 3ª Parte de los Programas no son compatibles con MS

Si usted es como yo y no desea ejecutar un binario de algunos desconocidos 3ª parte de los servidores de producción, quieres un oficial de MS herramienta o algún código que usted puede inspeccionar antes de que se ejecuta en los servidores. El DynCache herramienta para 2008 R2 es prácticamente imposible obtener de M$ sin tener que pagar por un caso de soporte y, francamente, basado en el código para el 2008 parece demasiado hinchado para la tarea como windows ya tiene incorporado en la lógica necesaria para dinámicamente el tamaño de la caché, sólo se necesita saber un máximo apropiado para su sistema.

La solución a todos los de arriba

Escribí un script de powershell que funciona en máquinas de 64 bits. Usted necesita para ejecutarlo como administrador con privilegios elevados. Usted debe ser capaz de ejecutar, como es, en cualquier x64 de windows Vista / Server 2008, hasta e incluyendo 8.1 / Server 2012 con cualquier cantidad de RAM. Usted no necesita instalar ningún software adicional y, como resultado, mantiene su servidor/estación de trabajo totalmente apoyado por la SRA.

Debe ejecutar esta secuencia de comandos en cada arranque con privilegios elevados para que el ajuste sea permanente. Programador de Tareas de Windows puede hacer esto para usted. Si la instalación de windows es dentro de una máquina virtual y cambiar la cantidad de memoria RAM asignada a la máquina virtual que también debe ejecutar después del cambio.

Puede ejecutar esta secuencia de comandos en cualquier momento en un sistema en funcionamiento, aun cuando en la producción de utilizar sin necesidad de tener que reiniciar el sistema o apagar cualquiera de los servicios.

# Filename: setfc.ps1
$version = 1.1

#########################
# Settings
#########################

# The percentage of physical ram that will be used for SetSystemFileCache Maximum
$MaxPercent = 12.5

#########################
# Init multipliers
#########################
$OSBits = ([System.IntPtr]::Size) * 8
switch ( $OSBits)
{
    32 { $KiB = [int]1024 }
    64 { $KiB = [long]1024 }
    default {
        # not 32 or 64 bit OS. what are you doing??
        $KiB = 1024 # and hope it works anyway
        write-output "You have a weird OS which is $OSBits bit. Having a go anyway."
    }
}
# These values "inherit" the data type from $KiB
$MiB = 1024 * $KiB
$GiB = 1024 * $MiB
$TiB = 1024 * $GiB
$PiB = 1024 * $TiB
$EiB = 1024 * $PiB


#########################
# Calculated Settings
#########################

# Note that because we are using signed integers instead of unsigned
# these values are "limited" to 2 GiB or 8 EiB for 32/64 bit OSes respectively

$PhysicalRam = 0
$PhysicalRam = [long](invoke-expression (((get-wmiobject -class "win32_physicalmemory").Capacity) -join '+'))
if ( -not $? ) {
    write-output "Trying another method of detecting amount of installed RAM."
 }
if ($PhysicalRam -eq 0) {
    $PhysicalRam = [long]((Get-WmiObject -Class Win32_ComputerSystem).TotalPhysicalMemory) # gives value a bit less than actual
}
if ($PhysicalRam -eq 0) {
    write-error "Cannot Detect Physical Ram Installed. Assuming 4 GiB."
    $PhysicalRam = 4 * $GiB
}
$NewMax = [long]($PhysicalRam * 0.01 * $MaxPercent)
# The default value
# $NewMax = 1 * $TiB


#########################
# constants
#########################

# Flags bits
$FILE_CACHE_MAX_HARD_ENABLE     = 1
$FILE_CACHE_MAX_HARD_DISABLE    = 2
$FILE_CACHE_MIN_HARD_ENABLE     = 4
$FILE_CACHE_MIN_HARD_DISABLE    = 8


################################
# C# code
# for interface to kernel32.dll
################################
$source = @"
using System;
using System.Runtime.InteropServices;

namespace MyTools
{
    public static class cache
    {
        [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern bool GetSystemFileCacheSize(
            ref IntPtr lpMinimumFileCacheSize,
            ref IntPtr lpMaximumFileCacheSize,
            ref IntPtr lpFlags
            );

        [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
        public static extern bool SetSystemFileCacheSize(
          IntPtr MinimumFileCacheSize,
          IntPtr MaximumFileCacheSize,
          Int32 Flags
        );

        [DllImport("kernel32", CharSet = CharSet.Unicode)]
        public static extern int GetLastError();

        public static bool Get( ref IntPtr a, ref IntPtr c, ref IntPtr d )
        {
            IntPtr lpMinimumFileCacheSize = IntPtr.Zero;
            IntPtr lpMaximumFileCacheSize = IntPtr.Zero;
            IntPtr lpFlags = IntPtr.Zero;

            bool b = GetSystemFileCacheSize(ref lpMinimumFileCacheSize, ref lpMaximumFileCacheSize, ref lpFlags);

            a = lpMinimumFileCacheSize;
            c = lpMaximumFileCacheSize;
            d = lpFlags;
            return b;
        }


        public static bool Set( IntPtr MinimumFileCacheSize, IntPtr MaximumFileCacheSize, Int32 Flags )
        {
            bool b = SetSystemFileCacheSize( MinimumFileCacheSize, MaximumFileCacheSize, Flags );
            if ( !b ) {
                Console.Write("SetSystemFileCacheSize returned Error with GetLastError = ");
                Console.WriteLine( GetLastError() );
            }
            return b;
        }
    }

    public class AdjPriv
    {
        [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
        internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall, ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);

        [DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
        internal static extern bool OpenProcessToken(IntPtr h, int acc, ref IntPtr phtok);

        [DllImport("advapi32.dll", SetLastError = true)]
        internal static extern bool LookupPrivilegeValue(string host, string name, ref long pluid);

        [StructLayout(LayoutKind.Sequential, Pack = 1)]
        internal struct TokPriv1Luid
        {
            public int Count;
            public long Luid;
            public int Attr;
        }
        internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
        internal const int SE_PRIVILEGE_DISABLED = 0x00000000;
        internal const int TOKEN_QUERY = 0x00000008;
        internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;

        public static bool EnablePrivilege(long processHandle, string privilege, bool disable)
        {
            bool retVal;
            TokPriv1Luid tp;
            IntPtr hproc = new IntPtr(processHandle);
            IntPtr htok = IntPtr.Zero;
            retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, ref htok);
            tp.Count = 1;
            tp.Luid = 0;
            if(disable)
            {
                tp.Attr = SE_PRIVILEGE_DISABLED;
            } else {
                tp.Attr = SE_PRIVILEGE_ENABLED;
            }
            retVal = LookupPrivilegeValue(null, privilege, ref tp.Luid);
            retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, IntPtr.Zero, IntPtr.Zero);
            return retVal;
        }
    }
}
"@
# Add the c# code to the powershell type definitions
Add-Type -TypeDefinition $source -Language CSharp

#########################
# Powershell Functions
#########################
function output-flags ($flags)
{
    Write-output ("FILE_CACHE_MAX_HARD_ENABLE  : " + (($flags -band $FILE_CACHE_MAX_HARD_ENABLE) -gt 0) )
    Write-output ("FILE_CACHE_MAX_HARD_DISABLE : " + (($flags -band $FILE_CACHE_MAX_HARD_DISABLE) -gt 0) )
    Write-output ("FILE_CACHE_MIN_HARD_ENABLE  : " + (($flags -band $FILE_CACHE_MIN_HARD_ENABLE) -gt 0) )
    Write-output ("FILE_CACHE_MIN_HARD_DISABLE : " + (($flags -band $FILE_CACHE_MIN_HARD_DISABLE) -gt 0) )
    write-output ""
}

#########################
# Main program
#########################

write-output ""

#########################
# Get and set privilege info
$ProcessId = $pid
$processHandle = (Get-Process -id $ProcessId).Handle
$Privilege = "SeIncreaseQuotaPrivilege"
$Disable = $false
Write-output ("Enabling SE_INCREASE_QUOTA_NAME status: " + [MyTools.AdjPriv]::EnablePrivilege($processHandle, $Privilege, $Disable) )

write-output ("Program has elevated privledges: " + ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator") )
write-output ""
whoami /PRIV | findstr /I "SeIncreaseQuotaPrivilege" | findstr /I "Enabled"
if ( -not $? )  {
    write-error "user Security Token SE_INCREASE_QUOTA_NAME: Disabled`r`n"
}
write-output "`r`n"


#########################
# Get Current Settings
# Init variables
$SFCMin = 0
$SFCMax = 0
$SFCFlags = 0
#Get Current values from kernel
$status = [MyTools.cache]::Get( [ref]$SFCMin, [ref]$SFCMax, [ref]$SFCFlags )
#typecast values so we can do some math with them
$SFCMin = [long]$SFCMin
$SFCMax = [long]$SFCMax
$SFCFlags = [long]$SFCFlags
write-output "Return values from GetSystemFileCacheSize are: "
write-output "Function Result : $status"
write-output "            Min : $SFCMin"
write-output ("            Max : $SFCMax ( " + $SFCMax / 1024 / 1024 / 1024 + " GiB )")
write-output "          Flags : $SFCFlags"
output-flags $SFCFlags


#########################
# Output our intentions
write-output ("Physical Memory Detected : $PhysicalRam ( " + $PhysicalRam / $GiB + " GiB )")
write-output ("Setting Max to " + $MaxPercent + "% : $NewMax ( " + $NewMax / $MiB + " MiB )`r`n")

#########################
# Set new settings
$SFCFlags = $SFCFlags -bor $FILE_CACHE_MAX_HARD_ENABLE # set max enabled
$SFCFlags = $SFCFlags -band (-bnot $FILE_CACHE_MAX_HARD_DISABLE) # unset max dissabled if set
# or if you want to override this calculated value
# $SFCFlags = 0
$status = [MyTools.cache]::Set( $SFCMin, $NewMax, $SFCFlags ) # calls the c# routine that makes the kernel API call
write-output "Set function returned: $status`r`n"
# if it was successfull the new SystemFileCache maximum will be NewMax
if ( $status ) {
    $SFCMax = $NewMax
}


#########################
# After setting the new values, get them back from the system to confirm
# Re-Init variables
$SFCMin = 0
$SFCMax = 0
$SFCFlags = 0
#Get Current values from kernel
$status = [MyTools.cache]::Get( [ref]$SFCMin, [ref]$SFCMax, [ref]$SFCFlags )
#typecast values so we can do some math with them
$SFCMin = [long]$SFCMin
$SFCMax = [long]$SFCMax
$SFCFlags = [long]$SFCFlags
write-output "Return values from GetSystemFileCacheSize are: "
write-output "Function Result : $status"
write-output "            Min : $SFCMin"
write-output ("            Max : $SFCMax ( " + $SFCMax / 1024 / 1024 / 1024 + " GiB )")
write-output "          Flags : $SFCFlags"
output-flags $SFCFlags

No hay línea cerca de la parte superior que dice $MaxPercent = 12.5 que establece el nuevo máximo del conjunto de trabajo (memoria activa) a 12,5% del total de la memoria RAM física. Windows dinámicamente el tamaño de la cantidad de metarchivo de datos en la memoria activa basada en las exigencias del sistema, por lo que no es necesario ajustar de forma dinámica a este máximo.

Esto no va a solucionar cualquier problema que usted tenga con el archivo asignado en memoria caché demasiado grande.

También he hecho una GetSystemFileCacheSize script de powershell y publicado en http://stackoverflow.com/questions/5898843/c-sharp-get-system-file-cache-size/17875550#17875550


Edit: también debo señalar que no se debe de ejecutar cualquiera de estos 2 secuencias de comandos de la misma powershell instancia más de una vez o recibirá el mensaje de error de que el Add-Tipo de llamada ya se ha hecho.

Edit: actualizado SetSystemFileCacheSize secuencia de comandos de la versión 1.1 que calcula un adecuado max el valor de la caché para usted, y tiene una mejor salida del estado de diseño.

4voto

Russ Wheeler Puntos 173

Yo no pretendo ser un experto sobre el funcionamiento interno de la memoria o la caché de disco en un sistema operativo Windows, pero tengo dos observaciones:

  1. Si el sistema operativo no almacena en caché los datos en la memoria tendría que leer desde el disco, que es exponencialmente más lento de almacenamiento de los medios de comunicación de memoria, por lo que el problema de rendimiento que estamos viendo ahora casi seguro que sería peor.

  2. Estás tratando de resolver el problema mediante el tratamiento de un síntoma del problema en lugar de la causa del problema. La causa del problema es casi seguro que una falta de suficiente memoria RAM física y mi sugerencia sería la de dirección.

Además, mientras que la caché puede estar usando 1.5 GB de RAM me pregunto lo que el uso de memoria es para otros procesos y servicios y puede que la solución sea para investigar el uso de problemas potenciales.

3voto

James N. Puntos 31

A la gente que dio el obvio, pero ineficaz solución de simplemente agregar más memoria RAM, que claramente no han lidiado con este problema de primera mano.

Como se dijo anterior por un cartel, no importa la cantidad de memoria RAM que le echen el problema...todo va a llenar. Estoy ejecutando un conjunto de herramientas de Atlassian en nuestro servidor de la aplicación que se ha migrado de 32 bits (2003) para 64 bits (2008). De inmediato fue evidente que hubo una pérdida de rendimiento.

Cuando se mira en el administrador de tareas, casi toda la memoria utilizada; aunque los procesos que se están ejecutando no reflejan esto. Cuando aumentamos la memoria de 8 GB a 16 GB, el problema se consume la memoria adicional así.

La única manera de tratar el problema era que reiniciar el servidor, que derribó el uso de memoria igual a la de los procesos (alrededor de 3,5 GB). Esto comenzó a subir de nuevo dentro de un día o así.

Yo sabía que esto era una nueva de Microsoft bug/característica y estaba feliz de encontrar este artículo. Me encanta la forma en que Microsoft deja este detalle importante para los usuarios de averiguar. He descargado RamMap, que uno pensaría que sería un nativo de utilidad, y ahora puedo ver el Metarchivo de uso. Vamos a configurar la memoria caché se borra cada pocos días y esperemos que esto va a resolver el problema.

Es interesante que sólo he visto este problema en uno de varios de nuestros migrar los servidores, así que me pregunto si el metarchivo se alimentan sólo de ciertos tipos de aplicaciones.

2voto

OneSpeed Puntos 21

Este problema se puede abordar de forma rápida y gratis de usar el SysInternals CacheSet herramienta. Simplemente, establecer el conjunto de trabajo de un máximo a un valor conveniente a menos de la cantidad de RAM del sistema, y de aplicar.

1voto

TomTom Puntos 38586

Siento ser tan directo pero, ¿qué acerca de actualizar el servidor a una cantidad de ram que es un poco más alto que un lo que las estaciones de trabajo han ido estos días? 16gb memroy freaking barato. Menos costoso que incluso la mitad de un día de su tiempo.

EnMiMaquinaFunciona.com

EnMiMaquinaFunciona es una comunidad de administradores de sistemas en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros sysadmin, hacer tus propias preguntas o resolver las de los demás.

Powered by: