尝试运行 mssql-conf 时,SQL Server 会在 RHEL 7.4 上终止并生成核心转储

本文可帮助你解决在安装后尝试运行 mssql-conf 时 SQL Server 终止并在 RHEL 7.4 上生成核心转储的问题。

原始产品版本:SQL Server
原始 KB 数: 4134638

现象

在 RHEL 7.4 上安装 Microsoft SQL Server 后,程序会在尝试运行 mssql-conf 工具时终止并生成核心转储。 此外,mssql-server 服务的 systemctl 日志中记录了以下条目(journalctl -u mssql-server.service):

此程序遇到严重错误,无法继续运行。
提供以下诊断信息:

原因:0x00000003
消息:结果
Stacktrace:0000557212bcd92 0000557721266767
进程:590 - sqlservr
线程:594(应用程序线程0x1000)
实例 ID:afe0f97b-fdbc-4a4d-910c-038e7ee2049b
崩溃 ID:544c4c67-0f49-4877-a959-92c14798d58e
生成戳:f7473acad6f0299cd161863aaa02e4284434ab6d915c7b467e2a14e907290249

正在捕获核心转储和信息...

原因

之所以出现此问题,是因为Linux 上的 SQL Server与旧版 VA 布局不兼容。 由于 RHEL 7.4 上启用了设置,因此所有进程都从此开始 using legacy_va_layout

在启动期间,Linux 上的 SQL Server验证地址范围。 当它由于旧版 VA 布局而发现不兼容时,它会引发断言、终止程序并生成核心转储。

由于以下任一原因,RHEL 7.4 可能会切换到使用旧版 VA 布局:

  • 软堆栈限制值设置为 “无限制 ”(例如,修改的 limits.conf 脚本或 ulimit -s 设置)。
  • 启用了全局旧版 VA 布局(例如, sysctl vm.legacy_va_layoutmodify/etc/sysctl.conf)。

解决方法

  1. 在布局中 /etc/security/limits.conf ,添加新行,然后输入代码:

    mssql soft stack 8192
    root soft stack 8192
    
  2. 在布局中/etc/sysctl.conf,添加新行,然后输入代码: vm.legacy_va_layout = 0

  3. 重新启动计算机: reboot

  4. 确保用户 (rootmssql)的软堆栈设置为 8192。 切换到用户的上下文,然后运行以下命令: ulimit -s

  5. 确保全局旧版 VA 布局为 0Sysctl vm.legacy_va_layout

检查堆栈大小限制

检查堆栈大小限制和 legacy_va_layout 设置(默认值,取自全新 RHEL-7 安装)。

[root@localhost ~]# sysctl vm.legacy_va_layout
vm.legacy_va_layout = 0
[root@localhost ~]# ulimit -s
8192

当这些设置在 x64 系统中进行时,地址空间布局如下所示:

+----------------------+ TASK_SIZE(1UL << 47) - PAGE_SIZE)
|STACK |
+----------------------+
+----------------------+ MMAP_BASE(STACK_SIZE + RND_OFFSET)
|MMAP() |
|vvv|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|^^^^^^^^^^^^^^|
|HEAP |
+----------------------+
|ELF 段 |
+----------------------+
+----------------------+ 0

MMAP_BASE 位于地址空间的顶部附近。 随着映射的添加,地址空间分配会减少。 这是 RHEL 的默认设置,这是 SQL Server 在启动时需要遇到的设置。

运行简单程序

运行一个简单的程序,该程序映射页面并返回内核返回的地址(示例):

mmap code
 =========
 #include <stdio.h>
 #include <sys/mman.h>

int main()
{
    void* result = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
    printf("mmap %p\n", result);
    return 0;
}

[root@localhost ~]# ./mmap
 mmap 0x7fb6976d6000

但是,如果更改了任一参数或两个参数,VA 布局可能会恢复到其旧版式:

+----------------------+ TASK_SIZE(1UL << 47) - PAGE_SIZE)
|STACK |
|vv^v|
| |
| |
| |
| |
| |
| |
| |
| |
| |
|^^^^^^^^^^^^^^|
|MMAP() |
+----------------------+ TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3)
| |
| |
| |
|^^^^^^^^^^^^^^|
|HEAP |
+----------------------+
|ELF 段 |
+----------------------+
+----------------------+ 0

此处,地址 MMAP_BASE 空间位于地址空间的三分之一处。 随着映射的添加,地址空间分配会增长(扩展)。

由于我们有 47 位虚拟地址空间(在 64 位 Linux 中) MMAP_BASE 放置在第 42 TB 虚拟0x2A0000000000左右。 因此,mssql 在尝试设置固定映射的映射时,在地址上已映射到 64 TB 以下。

调整堆栈大小,以无限增长 - 无限制

[root@localhost ~]# ulimit -s unlimited
[root@localhost ~]# ./mmap
mmap 0x2b6634464000

调整vm.legacy_va_layout

[root@localhost ~]# ulimit -s 8192
[root@localhost ~]# sysctl -w vm.legacy_va_layout=1
vm.legacy_va_layout = 1
[root@localhost ~]# ./mmap
mmap 0x2b46f28f9000

可以通过调整堆栈大小以无限增长来获得与设置 vm.legacy_va_layout 相同的效果。 区别在于,管理员设置 vm.legacy_va_layout=1后,系统将全局对所有进程使用旧 VA 布局。 (重写此方法的唯一方法是将 sysctl knob 重置为 0。但是,如果有 vm.legacy_va_layout=0 (default),可以通过发出 ulimit(或自定义 limits.conf)来调整每个登录会话的堆栈大小限制来调整该特征。