还是内存的问题,我不知道怎么限制内存使用量

最近几天一直在看如何限制mysql最多使用多少内存。

首先是Linux的setrlimit函数,可以限制的有:

RLIMIT_AS:地址空间的大小。

RLIMIT_DATA:数据段的大小(已初始化数据,未初始化数据和堆)

RLIMIT_MEMLOCK:被mlock/mlockall/map的MAP_LOCKED锁住的内存的总计大小

RLIMIT_RSS :废弃。

RLIMIT_STACK:栈的最大大小。

我拿RLIMIT_STACK测试了一下,代码如下:

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/resource.h>

int main()
{
    pthread_attr_t attr;
    size_t stacksize;
    struct rlimit rlim;

    pthread_attr_init(&attr);
    if(pthread_attr_getstacksize(&attr, &stacksize)!=0){
    printf("get stacksize fail\n");
    }
    getrlimit(RLIMIT_STACK, &rlim);
    printf("%zd\n", (size_t) rlim.rlim_cur);
    printf("%zd\n", stacksize);
    pthread_attr_destroy(&attr);
    sleep(1000000);    
    return 0;
}

Linux下,如果rlimit设置成unlimited,那么该线程的栈大小是2M(这个在pthread_create(3)中有说明)。否则,栈的初始大小由rlimit决定。

opensolaris下,rlimit的值和初始栈大小之间我没看出来明显的联系。在solaris下,没有用于增长栈的函数。每个进程初始的栈大小是一个page,系统给栈预留大概20M的地址空间。当栈增长超过1个page的时候,OS捕获这个page error,然后给它分配新的物理页。即便我把rlimit设置成512K,pthread_attr_getstacksize得到的值依然是0。并且,按setrlimit的man pages来说,solaris永远不会移动栈的位置。如果它预留的空间不足以栈增长,那么后果自负。不过我这些测试都是在32位的solaris下进行的,对于64位系统来说,地址空间简直就是白菜啊,需要纠结这些问题吗?默认情况下,32位的solaris的默认栈大小是1M,64位是2M。

我现在终于明白为什么mysql的代码中处处关心stack size。按默认来说,stack size=8M,那么对于一个32位的系统,可给用户态用的地址空间只有3G,仅仅能支持384个线程,而mysql是thread-per-connection的模式,也就是说它最高就只能同时处理384个连接。所以它要精确的算好stacksize,在mysqld_main中用pthread_attr_setstacksize把stacksize限制的尽可能的小。

我想来想去都觉得从系统层面限制内存使用量是一件很复杂很难行得通的事情。限制地址空间容易,但是限制物理内存很难。如果我没记错的话,当需要分配的内存较大时,glibc的malloc会自动把sbrk换成mmap。而mmap是不在RLIMIT_DATA的限制内的。而限制RLIMIT_AS是一件很愚蠢的事情,太一刀切了。

另外一个思路,就是根据mysql的配置文件大约可以估算出它最多能占多少内存,计算方式如下:

静态内存消耗:key_buffer_size query_cache_size
如果有innodb,那么加上innodb-buffer-pool-size innodb-log-buffer-size innodb-additional-mem-pool-size
内存表,临时表:max_heap_table_size+tmp_table_size

每个线程的内存消耗:
thread_stack+2*net_buffer_length +read_buffer_size+read_rnd_buffer_size+sort_buffer_size
如果启用了binlog,那么加上binlog_cache_size/binlog_stmt_cache_size (TODO:是不是支持事务才有?)
TODO:(myisam_sort_buffer_size vs sort_buffer_size)

于是总内存=静态内存+每个线程的内存消耗*最大连接数。线程的最大数量基本由max_connections决定(SUPER不受此限制)

我很想知道那些做托管主机服务的,如hostmonster,是怎么做资源限制的?如果租户利用OOM做Dos影响其它人呢?

此问题没完。今天太困,先睡。明天回一趟W公司,办公积金手续。

此博客中的热门博文

少写代码,多读别人写的代码

在windows下使用llvm+clang

tensorflow distributed runtime初窥