有没有办法告诉 Linux 它不应该将特定进程的内存交换到磁盘?
它是一个 Java 应用程序,所以理想情况下我希望有一种方法可以从命令行执行此操作。
我知道您可以将 global swappiness 设置为 0,但这明智吗?
你可以通过 Linux 下的mlockall(2)系统调用来做到这一点;这将适用于整个过程,但请阅读您需要通过的参数。
你真的需要把整个事情都拉到核心吗?如果它是一个 java 应用程序,您可能会将整个 JVM 锁定在内核中。我不知道执行此操作的命令行方法,但是您可以编写一个简单的程序来调用fork
,调用mlockall
,然后exec
。
您还可以查看madvise(2)中的访问模式通知之一是否满足您的需求。如果它适用于您,向 VM 子系统建议更好的分页策略可能会更好。
请注意,很久以前现在在 SunOS 下,有一种类似于 madvise 的机制,称为vadvise(2)。
如果您希望更改进程的交换性,请将其添加到 cgroup 并设置该 cgroup 的值:
https://unix.stackexchange.com/questions/10214/per-process-swapiness-for-linux#10227
您可以通过mlock系列系统调用来做到这一点。但是,我不确定您是否可以针对不同的流程执行此操作。
作为超级用户,您可以将其“优化”到最高优先级 -20,并希望这足以防止它被换出。通常是这样。正数降低调度优先级。普通用户不能向上友好(负数)
存在一类应用程序,您永远不希望它们交换。一个这样的类是数据库。数据库将使用内存作为其磁盘区域的缓存和缓冲区,并且将它们放入交换绝对没有任何意义。特定的内存可能会保存一些一周内不需要的相关数据,直到有一天客户要求它。如果没有缓存/交换,数据库将简单地在磁盘上找到相关记录,这将是相当快的;但是通过交换,您的服务可能突然需要很长时间才能响应。
mysqld
包括使用操作系统/系统调用的代码memlock
。在 Linux 上,至少从 2.6.9 开始,此系统调用将适用于具有CAP_IPC_LOCK
能力[1]的非 root 进程。使用memlock()
时,进程必须仍然在LimitMEMLOCK
限制范围内工作。[2]。(少数)好处之一systemd
是您可以授予mysqld
进程这些功能,而无需特殊程序。If 还可以按照您的预期设置 rlimits ulimit
。这是一个override
用于mysqld
执行必要步骤的文件,其中包括您可能需要的一些其他步骤,例如数据库:
[Service]
# Prevent mysql from swapping
CapabilityBoundingSet=CAP_IPC_LOCK
# Let mysqld lock all memory to core (don't swap)
LimitMEMLOCK=-1
# do not kills this process if low on memory
OOMScoreAdjust=-900
# Use higher io scheduling
IOSchedulingClass=realtime
Type=simple
ExecStart=
ExecStart=/usr/sbin/mysqld --memlock $MYSQLD_OPTS
注意标准社区mysql目前附带Type=forking
并添加--daemonize
选项到服务就ExecStart
行了。这本质上不如上述方法稳定。
更新我对这个解决方案不是 100% 满意。经过几天的运行,我注意到这个过程仍然有大量的交换!检查/proc/XXXX/smaps
,我注意到以下几点:
memlock
MySQL(或 Linux)中的选项已损坏。在这种情况下,这并不重要,因为 MySQL 不能 memlock 堆栈。除非在极不寻常的情况下,问这个问题意味着你做错了(tm)。
说真的,如果 Linux 想要交换并且您试图将进程保留在内存中,那么您对操作系统提出了不合理的要求。如果您的应用程序如此重要,那么 1) 购买更多内存,2) 从机器中删除其他应用程序/守护程序,或将机器专用于您的应用程序,和/或 3) 投资一个非常快速的磁盘子系统。这些步骤对于重要的应用程序是合理的。如果你不能证明它们是合理的,那么你可能也不能证明连接内存和饿死其他进程是合理的。
你为什么要这样做?
如果您试图提高此应用程序的性能,那么您可能走错了路。操作系统将换出一个进程以增加磁盘缓存的内存 - 即使有可用的 RAM,内核也最清楚(实际上编写调度程序的 samrt 人最清楚)。
如果您有一个需要响应的进程(它在不使用时被换出并且您需要它快速重新启动),那么将其设置为高优先级、mlock 或使用实时内核可能会有所帮助。