18.3. 启动数据库服务器
在任何人可以访问数据库前,你必须启动数据库服务器。 数据库服务器程序是postgres, 它必须知道在哪里能找到它要用的数据。这是用-D选项实现的。 因此,启动服务器最简单的方法是:
$ postgres -D /usr/local/pgsql/data
这将把服务器放在前台运行。这个步骤同样必须以PostgreSQL用户帐户登录来操作。如果没有-D选项,服务器将尝试使用环境变量PGDATA命名的目录。如果这个环境变量也没有提供则导致失败。
通常最好在后台启动postgres。要这样做,使用常用的 Unix shell 语法:
$ postgres -D /usr/local/pgsql/data >logfile 2>&1 &
如上所示,把服务器的stdout和stderr输出存储到某个地方是非常重要的。这将对审计目的和诊断问题有所帮助(更深入的有关日志文件处理的讨论请见(第 24.3 节)。
postgres还接受其它一些命令行选项。更多的信息请见postgres参考页 和下面的第 19 章。
这些 shell 语法很容易让人觉得无聊。因此我们提供了包装器程序pg_ctl以简化一些任务。例如:
pg_ctl start -l logfile
将在后台启动服务器并且把输出放到指定的日志文件中。-D选项和postgres中的一样。pg_ctl还可以用于停止服务器。
通常,你会希望在计算机启动的时候启动数据库服务器。自动启动脚本是操作系统相关的。PostgreSQL在contrib/start-scripts目录中提供了几种。安装将需要 root 权限。
不同的系统在引导时有不同的启动守护进程的习惯。许多系统有一个文件/etc/rc.local或/etc/rc.d/rc.local。其他的使用init.d或rc.d目录。不管你做什么,服务器必须由PostgreSQL用户账户而不是 root或任何其他用户启动。因此你可能应该在你的命令中使用su postgres -c '...'这种形式。例如:
su postgres -c 'pg_ctl start -D /usr/local/pgsql/data -l serverlog'
下面是一些更加与操作系统相关的建议(在每一种情况中要确保在我们展示通用值的地方使用正确的安装目录和用户名)。
对于FreeBSD,找找PostgreSQL源码发布中的文件contrib/start-scripts/freebsd。
-
在OpenBSD上, 把下面几行加到/etc/rc.local文件中:
if [ -x /usr/local/pgsql/bin/pg_ctl -a -x /usr/local/pgsql/bin/postgres ]; then su -l postgres -c '/usr/local/pgsql/bin/pg_ctl start -s -l /var/postgresql/log -D /usr/local/pgsql/data' echo -n ' postgresql' fi
-
在Linux系统上将
/usr/local/pgsql/bin/pg_ctl start -l logfile -D /usr/local/pgsql/data
加入到/etc/rc.d/rc.local或/etc/rc.local中,还可以在PostgreSQL的源码发布中找找文件contrib/start-scripts/linux。
在使用systemd时,可以使用下面的服务单元文件(例如/etc/systemd/system/postgresql.service):
[Unit] Description=PostgreSQL database server Documentation=man:postgres(1) [Service] Type=notify User=postgres ExecStart=/usr/local/pgsql/bin/postgres -D /usr/local/pgsql/data ExecReload=/bin/kill -HUP $MAINPID KillMode=mixed KillSignal=SIGINT TimeoutSec=0 [Install] WantedBy=multi-user.target
使用Type=notify要求服务器的二进制文件使用configure --with-systemd编译。
要仔细地考虑超时设置。在写作这份文档时,systemd的默认超时时长是 90 秒,并且将会杀死没有在这段时间内报告准备好的进程。但是PostgreSQL服务器可能因为执行崩溃恢复而导致启动过程大大超过这个默认时间。建议的值是 0 禁用超时逻辑。
在NetBSD上,你可以根据爱好选择FreeBSD或Linux的启动脚本。
-
在Solaris上,创建一个名为/etc/init.d/postgresql的文件,其中包含下列行:
su - postgres -c "/usr/local/pgsql/bin/pg_ctl start -l logfile -D /usr/local/pgsql/data"
然后在/etc/rc3.d中创建一个符号链接S99postgresql指向它。
当服务器在运行时,它的PID被保存在数据目录中的postmaster.pid文件。这样做 可以防止多个服务器实例运行在同一个数据目录中,并且也可以被用来关闭服务器。
18.3.1. 服务器启动失败
有几个常见的原因会导致服务器启动失败。通过检查服务器日志或使用手工启动的方法(不做标准输出或标准错误的重定向), 就可以看到出现什么错误消息。下面我们详细地解释一些最常见的错误消息。
Address already in use或其变体,那就有可能是别的问题。 例如,试图在一个被保留的端口上启动服务器会收到下面这样的消息:$ postgres -p 666 LOG: could not bind IPv4 socket: Permission denied HINT: Is another postmaster already running on port 666? If not, wait a few seconds and retry. FATAL: could not create TCP/IP listen socket
像这样的消息:
FATAL: could not create shared memory segment: Invalid argument DETAIL: Failed system call was shmget(key=5440001, size=4011376640, 03600).可能意味着你的内核对共享内存区的限制小于PostgreSQL试图创建的工作区域(本例中是 4011376640 字节)。或者可能意味着根本就没有 System-V 风格的共享内存支持被配置在你的内核中。作为一种临时的解决方案, 你可以试着以小于正常数量的缓冲区(shared_buffers)启动服务器。 你最终还是会希望重新配置内核以增加共享内存允许的尺寸。 当你试图在同一台机器上启动多个服务器,并且它们所需的总空间超过了内核的限制,也会报这个错。
一个这样的错误:
FATAL: could not create semaphores: No space left on device DETAIL: Failed system call was semget(5440126, 17, 03600).并不意味着你已经用光了磁盘空间。它的意思是你的内核对System V信号量的限制小于PostgreSQL想创建的数量。和上面一样,你可以通过减少允许的连接数(max_connections)来绕开这个限制,但最终你还是会希望提高内核的限制。
如果你收到一个"illegal system call"错误, 那么很有可能是你的内核根本不支持共享内存或者信号量。这种情况下你唯一的选择就是重新配置内核并且把这些特性打开。
关于配置System V IPC功能的细节请见第 18.4.1 节。
18.3.2. 客户端连接问题
尽管可能在客户端出现的错误情况范围宽广而且是应用相关的,但的确有几种与服务器的启动方式直接相关。除了下面提到的几种错误之外的问题都应该在相应的客户端应用文档中。
psql: could not connect to server: Connection refused Is the server running on host "server.joe.com" and accepting TCP/IP connections on port 5432?
这是常见的"I couldn't find a server to talk to"失败。上面的情况看起来是发生在尝试 TCP/IP 通信时。常见的错误是忘记把服务器配置成允许 TCP/IP 连接。
另外,当试图通过 Unix 域套接字与本地服务器通信时,你会看到这个:
psql: could not connect to server: No such file or directory Is the server running locally and accepting connections on Unix DOMain socket "/tmp/.s.PGSQL.5432"?
最后一行可以验证客户端是不是尝试连接到正确的位置。如果实际上没有服务器在那里运行,典型的核心错误消息将是Connection refused或No such file or directory(值得注意的是这种环境中的Connection refused并不表示服务器得到了你的连接请求并拒绝了它。那种情况会产生一个不同的消息,如第 20.4 节中所示)。其它像Connection timed out这样的消息可能表示更基础的问题,如缺少网络连接。