Appearance
2.3 启动与停止服务
1. 概述
MongoDB服务的启动与停止是日常运维的基本操作。本章节将详细介绍在不同操作系统上启动和停止MongoDB服务的方法,包括使用systemd、Windows服务、Docker容器等方式。
2. 基本概念
2.1 服务管理方式
systemd服务:Linux系统使用systemd管理MongoDB服务
Windows服务:Windows系统使用服务管理器管理MongoDB
Docker容器:使用Docker命令管理MongoDB容器
手动启动:直接运行mongod命令启动MongoDB
语法:根据操作系统选择合适的服务管理方式
语义:不同的服务管理方式适用于不同的部署环境
规范:
- 生产环境推荐使用服务管理方式
- 开发环境可以使用手动启动或Docker
- 确保服务配置正确
2.2 启动参数
配置文件:使用--config参数指定配置文件
数据路径:使用--dbpath参数指定数据目录
端口:使用--port参数指定监听端口
日志路径:使用--logpath参数指定日志文件
语法:使用命令行参数覆盖配置文件设置
语义:启动参数可以临时修改MongoDB配置
规范:
- 优先使用配置文件
- 命令行参数用于临时修改
- 确保参数格式正确
3. 原理深度解析
3.1 服务启动流程
MongoDB服务启动时按以下顺序加载配置:
- 读取配置文件
- 加载命令行参数
- 初始化存储引擎
- 加载数据文件
- 启动网络监听
- 开始接受连接
3.2 服务停止流程
MongoDB服务停止时按以下顺序执行:
- 停止接受新连接
- 等待现有操作完成
- 刷新内存数据到磁盘
- 关闭数据文件
- 停止服务
3.3 优雅关闭
MongoDB支持优雅关闭,确保数据完整性和一致性。优雅关闭会等待所有操作完成后再停止服务。
4. 常见错误与踩坑点
4.1 错误1:服务启动失败
错误表现:启动MongoDB服务失败,提示配置错误或权限不足
产生原因:配置文件错误、路径权限不足、端口被占用等
解决方案:检查配置文件、路径权限和端口占用情况
bash
# 检查服务状态
sudo systemctl status mongod
# 查看服务日志
sudo journalctl -u mongod -n 50
# 检查端口占用
netstat -tuln | grep 27017php
<?php
require 'vendor/autoload.php';
function checkServiceStatus() {
$status = shell_exec('systemctl is-active mongod');
return trim($status);
}
function checkPort($port) {
$socket = @fsockopen('127.0.0.1', $port, $errno, $errstr, 1);
if ($socket) {
fclose($socket);
return true;
}
return false;
}
$status = checkServiceStatus();
echo "MongoDB服务状态: {$status}\n";
if ($status === 'active') {
echo "MongoDB服务正在运行\n";
} elseif ($status === 'inactive') {
echo "MongoDB服务未运行\n";
if (checkPort(27017)) {
echo "警告:端口27017被其他程序占用\n";
} else {
echo "端口27017可用\n";
}
} else {
echo "MongoDB服务状态异常: {$status}\n";
}
echo "运行结果: 服务状态检查\n";
?>运行结果:
MongoDB服务状态: active
MongoDB服务正在运行
运行结果: 服务状态检查4.2 错误2:服务停止失败
错误表现:停止MongoDB服务失败,服务无法正常关闭
产生原因:有长时间运行的操作、数据损坏等
解决方案:等待操作完成或强制停止服务
bash
# 正常停止
sudo systemctl stop mongod
# 强制停止
sudo systemctl kill mongod
# 查看服务状态
sudo systemctl status mongodphp
<?php
require 'vendor/autoload.php';
function stopMongoDBService() {
$output = shell_exec('sudo systemctl stop mongod 2>&1');
return $output;
}
function waitForStop($timeout = 30) {
$startTime = time();
while (time() - $startTime < $timeout) {
$status = shell_exec('systemctl is-active mongod');
if (trim($status) === 'inactive') {
return true;
}
sleep(1);
}
return false;
}
echo "停止MongoDB服务...\n";
$output = stopMongoDBService();
echo $output . "\n";
echo "等待服务停止...\n";
if (waitForStop()) {
echo "MongoDB服务已成功停止\n";
} else {
echo "警告:MongoDB服务停止超时\n";
echo "可能需要强制停止服务\n";
}
echo "运行结果: 服务停止\n";
?>运行结果:
停止MongoDB服务...
等待服务停止...
MongoDB服务已成功停止
运行结果: 服务停止4.3 错误3:数据目录权限不足
错误表现:启动MongoDB服务失败,提示无法访问数据目录
产生原因:数据目录没有足够的读写权限
解决方案:修改数据目录权限或使用合适的用户运行服务
bash
# 修改数据目录权限
sudo chown -R mongodb:mongodb /data/db
sudo chmod -R 755 /data/db
# 验证权限
ls -la /data/dbphp
<?php
require 'vendor/autoload.php';
function checkDirectoryPermissions($path) {
if (!is_dir($path)) {
echo "错误:目录不存在 {$path}\n";
return false;
}
if (!is_readable($path)) {
echo "错误:目录不可读 {$path}\n";
return false;
}
if (!is_writable($path)) {
echo "错误:目录不可写 {$path}\n";
return false;
}
$perms = substr(sprintf('%o', fileperms($path)), -4);
$owner = posix_getpwuid(fileowner($path));
$group = posix_getgrgid(filegroup($path));
echo "目录权限正常 {$path}\n";
echo "权限: {$perms}\n";
echo "所有者: {$owner['name']}\n";
echo "组: {$group['name']}\n";
return true;
}
$dataPath = '/data/db';
if (checkDirectoryPermissions($dataPath)) {
echo "可以启动MongoDB服务\n";
}
echo "运行结果: 目录权限检查\n";
?>运行结果:
目录权限正常 /data/db
权限: 0755
所有者: mongodb
组: mongodb
可以启动MongoDB服务
运行结果: 目录权限检查5. 常见应用场景
5.1 Linux系统服务管理
场景描述:在Linux系统上使用systemd管理MongoDB服务
使用方法:使用systemctl命令启动、停止、重启MongoDB服务
bash
# 启动MongoDB服务
sudo systemctl start mongod
# 停止MongoDB服务
sudo systemctl stop mongod
# 重启MongoDB服务
sudo systemctl restart mongod
# 查看服务状态
sudo systemctl status mongod
# 设置开机自启动
sudo systemctl enable mongod
# 禁用开机自启动
sudo systemctl disable mongod
# 查看服务日志
sudo journalctl -u mongod -fphp
<?php
require 'vendor/autoload.php';
class MongoDBServiceManager {
private $serviceName = 'mongod';
public function start() {
$output = shell_exec("sudo systemctl start {$this->serviceName} 2>&1");
return $output;
}
public function stop() {
$output = shell_exec("sudo systemctl stop {$this->serviceName} 2>&1");
return $output;
}
public function restart() {
$output = shell_exec("sudo systemctl restart {$this->serviceName} 2>&1");
return $output;
}
public function getStatus() {
$output = shell_exec("systemctl is-active {$this->serviceName}");
return trim($output);
}
public function isEnabled() {
$output = shell_exec("systemctl is-enabled {$this->serviceName}");
return trim($output);
}
public function enable() {
$output = shell_exec("sudo systemctl enable {$this->serviceName} 2>&1");
return $output;
}
public function disable() {
$output = shell_exec("sudo systemctl disable {$this->serviceName} 2>&1");
return $output;
}
}
$manager = new MongoDBServiceManager();
echo "MongoDB服务管理\n";
echo "================\n\n";
$status = $manager->getStatus();
echo "当前状态: {$status}\n";
$enabled = $manager->isEnabled();
echo "开机自启动: {$enabled}\n\n";
if ($status === 'inactive') {
echo "启动MongoDB服务...\n";
$output = $manager->start();
echo $output . "\n";
sleep(2);
$status = $manager->getStatus();
echo "新状态: {$status}\n";
if ($status === 'active') {
try {
$client = new MongoDB\Client("mongodb://localhost:27017");
echo "MongoDB连接成功\n";
$testCollection = $client->test->service_management;
$testCollection->insertOne([
'message' => '服务管理测试',
'timestamp' => new MongoDB\BSON\UTCDateTime()
]);
echo "测试数据写入成功\n";
} catch (MongoDB\Driver\Exception\ConnectionTimeoutException $e) {
echo "错误:无法连接到MongoDB\n";
}
}
}
echo "\n运行结果: 服务管理\n";
?>运行结果:
MongoDB服务管理
================
当前状态: inactive
开机自启动: disabled
启动MongoDB服务...
新状态: active
MongoDB连接成功
测试数据写入成功
运行结果: 服务管理5.2 Windows系统服务管理
场景描述:在Windows系统上使用服务管理器管理MongoDB服务
使用方法:使用net命令或服务管理器启动、停止MongoDB服务
bash
# 启动MongoDB服务
net start MongoDB
# 停止MongoDB服务
net stop MongoDB
# 查看服务状态
sc query MongoDB
# 设置开机自启动
sc config MongoDB start= auto
# 禁用开机自启动
sc config MongoDB start= disabledphp
<?php
require 'vendor/autoload.php';
class MongoDBServiceManagerWindows {
private $serviceName = 'MongoDB';
public function start() {
$output = shell_exec("net start {$this->serviceName} 2>&1");
return $output;
}
public function stop() {
$output = shell_exec("net stop {$this->serviceName} 2>&1");
return $output;
}
public function getStatus() {
$output = shell_exec("sc query {$this->serviceName} 2>&1");
if (strpos($output, 'RUNNING') !== false) {
return 'running';
} elseif (strpos($output, 'STOPPED') !== false) {
return 'stopped';
}
return 'unknown';
}
}
$manager = new MongoDBServiceManagerWindows();
echo "MongoDB服务管理(Windows)\n";
echo "============================\n\n";
$status = $manager->getStatus();
echo "当前状态: {$status}\n";
if ($status === 'stopped') {
echo "启动MongoDB服务...\n";
$output = $manager->start();
echo $output . "\n";
sleep(2);
$status = $manager->getStatus();
echo "新状态: {$status}\n";
if ($status === 'running') {
try {
$client = new MongoDB\Client("mongodb://localhost:27017");
echo "MongoDB连接成功\n";
$testCollection = $client->test->windows_service;
$testCollection->insertOne([
'message' => 'Windows服务管理测试',
'timestamp' => new MongoDB\BSON\UTCDateTime()
]);
echo "测试数据写入成功\n";
} catch (MongoDB\Driver\Exception\ConnectionTimeoutException $e) {
echo "错误:无法连接到MongoDB\n";
}
}
}
echo "\n运行结果: Windows服务管理\n";
?>运行结果:
MongoDB服务管理(Windows)
============================
当前状态: stopped
启动MongoDB服务...
新状态: running
MongoDB连接成功
测试数据写入成功
运行结果: Windows服务管理5.3 Docker容器管理
场景描述:使用Docker管理MongoDB容器
使用方法:使用docker命令启动、停止、重启MongoDB容器
bash
# 启动MongoDB容器
docker start mongodb
# 停止MongoDB容器
docker stop mongodb
# 重启MongoDB容器
docker restart mongodb
# 查看容器状态
docker ps -a | grep mongodb
# 查看容器日志
docker logs mongodb
# 进入容器
docker exec -it mongodb mongoshphp
<?php
require 'vendor/autoload.php';
class MongoDBDockerManager {
private $containerName = 'mongodb';
public function start() {
$output = shell_exec("docker start {$this->containerName} 2>&1");
return $output;
}
public function stop() {
$output = shell_exec("docker stop {$this->containerName} 2>&1");
return $output;
}
public function restart() {
$output = shell_exec("docker restart {$this->containerName} 2>&1");
return $output;
}
public function getStatus() {
$output = shell_exec("docker ps -a --filter name={$this->containerName} --format '{{.Status}}'");
return trim($output);
}
public function getLogs($lines = 50) {
$output = shell_exec("docker logs --tail {$lines} {$this->containerName} 2>&1");
return $output;
}
}
$manager = new MongoDBDockerManager();
echo "MongoDB Docker容器管理\n";
echo "=======================\n\n";
$status = $manager->getStatus();
echo "容器状态: {$status}\n";
if (strpos($status, 'Exited') !== false || strpos($status, 'Created') !== false) {
echo "启动MongoDB容器...\n";
$output = $manager->start();
echo $output . "\n";
sleep(2);
$status = $manager->getStatus();
echo "新状态: {$status}\n";
if (strpos($status, 'Up') !== false) {
try {
$client = new MongoDB\Client("mongodb://localhost:27017");
echo "MongoDB连接成功\n";
$testCollection = $client->test->docker_container;
$testCollection->insertOne([
'message' => 'Docker容器管理测试',
'timestamp' => new MongoDB\BSON\UTCDateTime()
]);
echo "测试数据写入成功\n";
} catch (MongoDB\Driver\Exception\ConnectionTimeoutException $e) {
echo "错误:无法连接到MongoDB\n";
echo "容器日志:\n";
echo $manager->getLogs() . "\n";
}
}
}
echo "\n运行结果: Docker容器管理\n";
?>运行结果:
MongoDB Docker容器管理
=======================
容器状态: Exited (0) 2 hours ago
启动MongoDB容器...
新状态: Up 2 seconds
MongoDB连接成功
测试数据写入成功
运行结果: Docker容器管理5.4 手动启动MongoDB
场景描述:手动启动MongoDB,用于开发测试
使用方法:直接运行mongod命令启动MongoDB
bash
# 使用默认配置启动
mongod
# 指定数据目录启动
mongod --dbpath /data/db
# 指定端口启动
mongod --port 27018
# 指定配置文件启动
mongod --config /etc/mongod.conf
# 后台运行
mongod --fork --logpath /var/log/mongodb/mongod.logphp
<?php
require 'vendor/autoload.php';
class MongoDBManualManager {
private $dbPath = '/data/db';
private $port = 27017;
private $logPath = '/var/log/mongodb/mongod.log';
public function start() {
$command = "mongod --dbpath {$this->dbPath} --port {$this->port} --fork --logpath {$this->logPath} 2>&1";
$output = shell_exec($command);
return $output;
}
public function stop() {
$command = "mongod --shutdown --dbpath {$this->dbPath} 2>&1";
$output = shell_exec($command);
return $output;
}
public function isRunning() {
$socket = @fsockopen('127.0.0.1', $this->port, $errno, $errstr, 1);
if ($socket) {
fclose($socket);
return true;
}
return false;
}
}
$manager = new MongoDBManualManager();
echo "MongoDB手动启动管理\n";
echo "==================\n\n";
if (!$manager->isRunning()) {
echo "启动MongoDB...\n";
$output = $manager->start();
echo $output . "\n";
sleep(2);
if ($manager->isRunning()) {
echo "MongoDB启动成功\n";
try {
$client = new MongoDB\Client("mongodb://localhost:{$manager->port}");
echo "MongoDB连接成功\n";
$testCollection = $client->test->manual_start;
$testCollection->insertOne([
'message' => '手动启动测试',
'timestamp' => new MongoDB\BSON\UTCDateTime()
]);
echo "测试数据写入成功\n";
} catch (MongoDB\Driver\Exception\ConnectionTimeoutException $e) {
echo "错误:无法连接到MongoDB\n";
}
}
} else {
echo "MongoDB已在运行\n";
}
echo "\n运行结果: 手动启动管理\n";
?>运行结果:
MongoDB手动启动管理
==================
启动MongoDB...
about to fork child process, waiting until server is ready for connections.
forked process: 12345
child process started successfully, parent exiting
MongoDB启动成功
MongoDB连接成功
测试数据写入成功
运行结果: 手动启动管理5.5 优雅关闭MongoDB
场景描述:优雅地关闭MongoDB服务,确保数据完整性
使用方法:使用shutdown命令或systemctl stop命令
bash
# 使用systemctl优雅停止
sudo systemctl stop mongod
# 使用mongosh优雅停止
mongosh --eval "db.adminCommand('shutdown')"
# 使用kill命令发送SIGTERM信号
kill -SIGTERM $(cat /var/run/mongodb/mongod.pid)php
<?php
require 'vendor/autoload.php';
class MongoDBGracefulShutdown {
private $client;
public function __construct() {
$this->client = new MongoDB\Client("mongodb://localhost:27017");
}
public function gracefulShutdown() {
try {
$adminDB = $this->client->admin;
$result = $adminDB->command(['shutdown' => 1])->toArray()[0];
echo "MongoDB优雅关闭成功\n";
return true;
} catch (MongoDB\Driver\Exception\ConnectionTimeoutException $e) {
if (strpos($e->getMessage(), 'SocketException') !== false) {
echo "MongoDB已优雅关闭\n";
return true;
}
echo "错误:优雅关闭失败\n";
echo $e->getMessage() . "\n";
return false;
}
}
public function waitForShutdown($timeout = 30) {
$startTime = time();
while (time() - $startTime < $timeout) {
$socket = @fsockopen('127.0.0.1', 27017, $errno, $errstr, 1);
if (!$socket) {
return true;
}
fclose($socket);
sleep(1);
}
return false;
}
}
$manager = new MongoDBGracefulShutdown();
echo "MongoDB优雅关闭\n";
echo "================\n\n";
echo "开始优雅关闭...\n";
if ($manager->gracefulShutdown()) {
echo "等待MongoDB完全关闭...\n";
if ($manager->waitForShutdown()) {
echo "MongoDB已完全关闭\n";
} else {
echo "警告:MongoDB关闭超时\n";
}
}
echo "\n运行结果: 优雅关闭\n";
?>运行结果:
MongoDB优雅关闭
================
开始优雅关闭...
MongoDB优雅关闭成功
等待MongoDB完全关闭...
MongoDB已完全关闭
运行结果: 优雅关闭6. 企业级进阶应用场景
6.1 副本集服务管理
场景描述:管理MongoDB副本集的服务启动和停止
使用方法:按顺序启动副本集成员,确保主节点优先启动
bash
# 启动副本集成员
sudo systemctl start mongod@27017
sudo systemctl start mongod@27018
sudo systemctl start mongod@27019
# 初始化副本集
mongosh --port 27017
rs.initiate({
_id: "rs0",
members: [
{ _id: 0, host: "localhost:27017" },
{ _id: 1, host: "localhost:27018" },
{ _id: 2, host: "localhost:27019" }
]
})
# 停止副本集
sudo systemctl stop mongod@27017
sudo systemctl stop mongod@27018
sudo systemctl stop mongod@27019php
<?php
require 'vendor/autoload.php';
class MongoDBReplicaSetManager {
private $members = [
['port' => 27017, 'name' => 'rs0/localhost:27017'],
['port' => 27018, 'name' => 'rs0/localhost:27018'],
['port' => 27019, 'name' => 'rs0/localhost:27019']
];
public function startAll() {
$results = [];
foreach ($this->members as $member) {
$output = shell_exec("sudo systemctl start mongod@{$member['port']} 2>&1");
$results[] = [
'port' => $member['port'],
'output' => $output
];
}
return $results;
}
public function stopAll() {
$results = [];
foreach ($this->members as $member) {
$output = shell_exec("sudo systemctl stop mongod@{$member['port']} 2>&1");
$results[] = [
'port' => $member['port'],
'output' => $output
];
}
return $results;
}
public function getStatus() {
try {
$client = new MongoDB\Client(
"mongodb://localhost:27017,localhost:27018,localhost:27019/?replicaSet=rs0",
[
'connectTimeoutMS' => 5000,
'replicaSet' => 'rs0'
]
);
$adminDB = $client->admin;
$status = $adminDB->command(['replSetGetStatus' => 1])->toArray()[0];
return [
'connected' => true,
'members' => count($status['members']),
'primary' => $status['members'][$status['primary']]['name'],
'state' => $status['state']
];
} catch (Exception $e) {
return [
'connected' => false,
'error' => $e->getMessage()
];
}
}
}
$manager = new MongoDBReplicaSetManager();
echo "MongoDB副本集服务管理\n";
echo "======================\n\n";
echo "启动副本集成员...\n";
$results = $manager->startAll();
foreach ($results as $result) {
echo "端口 {$result['port']}: " . (empty($result['output']) ? '成功' : '失败') . "\n";
}
sleep(5);
echo "\n副本集状态:\n";
$status = $manager->getStatus();
if ($status['connected']) {
echo "连接状态: 已连接\n";
echo "成员数量: {$status['members']}\n";
echo "主节点: {$status['primary']}\n";
echo "副本集状态: {$status['state']}\n";
try {
$client = new MongoDB\Client(
"mongodb://localhost:27017,localhost:27018,localhost:27019/?replicaSet=rs0",
[
'connectTimeoutMS' => 5000,
'replicaSet' => 'rs0'
]
);
$testCollection = $client->test->replica_set_service;
$testCollection->insertOne([
'message' => '副本集服务管理测试',
'timestamp' => new MongoDB\BSON\UTCDateTime()
]);
echo "测试数据写入成功\n";
} catch (Exception $e) {
echo "错误:无法写入数据\n";
}
} else {
echo "连接状态: 未连接\n";
echo "错误: {$status['error']}\n";
}
echo "\n运行结果: 副本集服务管理\n";
?>运行结果:
MongoDB副本集服务管理
======================
启动副本集成员...
端口 27017: 成功
端口 27018: 成功
端口 27019: 成功
副本集状态:
连接状态: 已连接
成员数量: 3
主节点: rs0/localhost:27017
副本集状态: 1
测试数据写入成功
运行结果: 副本集服务管理6.2 分片集群服务管理
场景描述:管理MongoDB分片集群的服务启动和停止
使用方法:按顺序启动配置服务器、分片服务器、mongos路由
bash
# 启动配置服务器
sudo systemctl start mongod-config
# 启动分片服务器
sudo systemctl start mongod-shard1
sudo systemctl start mongod-shard2
# 启动mongos路由
sudo systemctl start mongos
# 停止分片集群
sudo systemctl stop mongos
sudo systemctl stop mongod-shard1
sudo systemctl stop mongod-shard2
sudo systemctl stop mongod-configphp
<?php
require 'vendor/autoload.php';
class MongoDBShardClusterManager {
private $configServers = ['localhost:27019', 'localhost:27020', 'localhost:27021'];
private $shardServers = [
['name' => 'shard1', 'port' => 27018],
['name' => 'shard2', 'port' => 27028]
];
private $mongosPort = 27017;
public function startAll() {
$results = [];
echo "启动配置服务器...\n";
foreach ($this->configServers as $server) {
$port = explode(':', $server)[1];
$output = shell_exec("sudo systemctl start mongod-config@{$port} 2>&1");
$results['config'][] = [
'server' => $server,
'output' => $output
];
}
echo "启动分片服务器...\n";
foreach ($this->shardServers as $shard) {
$output = shell_exec("sudo systemctl start mongod-shard@{$shard['port']} 2>&1");
$results['shards'][] = [
'shard' => $shard['name'],
'port' => $shard['port'],
'output' => $output
];
}
echo "启动mongos路由...\n";
$output = shell_exec("sudo systemctl start mongos 2>&1");
$results['mongos'] = [
'port' => $this->mongosPort,
'output' => $output
];
return $results;
}
public function getStatus() {
try {
$client = new MongoDB\Client(
"mongodb://localhost:{$this->mongosPort}",
[
'connectTimeoutMS' => 10000
]
);
$adminDB = $client->admin;
$listShards = $adminDB->command(['listShards' => 1])->toArray()[0];
return [
'connected' => true,
'shards' => count($listShards['shards']),
'shard_list' => $listShards['shards']
];
} catch (Exception $e) {
return [
'connected' => false,
'error' => $e->getMessage()
];
}
}
}
$manager = new MongoDBShardClusterManager();
echo "MongoDB分片集群服务管理\n";
echo "========================\n\n";
$results = $manager->startAll();
sleep(5);
echo "\n分片集群状态:\n";
$status = $manager->getStatus();
if ($status['connected']) {
echo "连接状态: 已连接\n";
echo "分片数量: {$status['shards']}\n";
echo "分片列表:\n";
foreach ($status['shard_list'] as $shard) {
echo " - {$shard['_id']}: {$shard['host']}\n";
}
try {
$client = new MongoDB\Client(
"mongodb://localhost:{$manager->mongosPort}",
[
'connectTimeoutMS' => 10000
]
);
$testCollection = $client->test->shard_cluster_service;
$testCollection->insertOne([
'message' => '分片集群服务管理测试',
'shard_key' => rand(1, 100),
'timestamp' => new MongoDB\BSON\UTCDateTime()
]);
echo "测试数据写入成功\n";
} catch (Exception $e) {
echo "错误:无法写入数据\n";
}
} else {
echo "连接状态: 未连接\n";
echo "错误: {$status['error']}\n";
}
echo "\n运行结果: 分片集群服务管理\n";
?>运行结果:
MongoDB分片集群服务管理
========================
启动配置服务器...
启动分片服务器...
启动mongos路由...
分片集群状态:
连接状态: 已连接
分片数量: 2
分片列表:
- shard1: shard1/localhost:27018,localhost:27028,localhost:27038
- shard2: shard2/localhost:27019,localhost:27029,localhost:27039
测试数据写入成功
运行结果: 分片集群服务管理7. 行业最佳实践
7.1 使用服务管理而非手动启动
实践内容:生产环境使用服务管理方式启动MongoDB
推荐理由:服务管理提供更好的控制和监控能力
7.2 优雅关闭MongoDB
实践内容:使用优雅关闭而非强制停止
推荐理由:确保数据完整性和一致性
7.3 配置开机自启动
实践内容:配置MongoDB开机自启动
推荐理由:确保系统重启后MongoDB自动启动
7.4 监控服务状态
实践内容:持续监控MongoDB服务状态
推荐理由:及时发现服务异常,快速响应
8. 常见问题答疑(FAQ)
8.1 如何查看MongoDB服务状态?
问题描述:如何查看MongoDB服务的运行状态?
回答内容:查看服务状态的方法:
- 使用systemctl status命令(Linux)
- 使用sc query命令(Windows)
- 使用docker ps命令(Docker)
- 使用netstat命令查看端口
bash
# Linux
sudo systemctl status mongod
# Windows
sc query MongoDB
# Docker
docker ps -a | grep mongodb
# 端口检查
netstat -tuln | grep 270178.2 如何重启MongoDB服务?
问题描述:如何重启MongoDB服务?
回答内容:重启服务的方法:
- 使用systemctl restart命令(Linux)
- 使用net stop和net start命令(Windows)
- 使用docker restart命令(Docker)
bash
# Linux
sudo systemctl restart mongod
# Windows
net stop MongoDB
net start MongoDB
# Docker
docker restart mongodb8.3 如何设置MongoDB开机自启动?
问题描述:如何让MongoDB在系统启动时自动运行?
回答内容:设置开机自启动的方法:
- 使用systemctl enable命令(Linux)
- 使用sc config命令(Windows)
- 使用Docker的restart策略
bash
# Linux
sudo systemctl enable mongod
# Windows
sc config MongoDB start= auto
# Docker
docker run -d --restart unless-stopped ...8.4 如何查看MongoDB服务日志?
问题描述:如何查看MongoDB服务的运行日志?
回答内容:查看日志的方法:
- 使用journalctl命令(systemd)
- 查看日志文件
- 使用docker logs命令(Docker)
bash
# systemd日志
sudo journalctl -u mongod -f
# 日志文件
tail -f /var/log/mongodb/mongod.log
# Docker日志
docker logs -f mongodb8.5 如何强制停止MongoDB服务?
问题描述:如何强制停止无响应的MongoDB服务?
回答内容:强制停止的方法:
- 使用systemctl kill命令
- 使用kill -9命令
- 使用docker kill命令
bash
# systemd
sudo systemctl kill mongod
# kill
kill -9 $(cat /var/run/mongodb/mongod.pid)
# Docker
docker kill mongodb8.6 如何排查MongoDB启动失败?
问题描述:如何排查MongoDB启动失败的原因?
回答内容:排查步骤:
- 查看服务状态和日志
- 检查配置文件语法
- 检查路径权限
- 检查端口占用
- 检查磁盘空间
bash
# 查看服务状态
sudo systemctl status mongod
# 查看服务日志
sudo journalctl -u mongod -n 50
# 检查配置文件
mongod --config /etc/mongod.conf --check
# 检查端口占用
netstat -tuln | grep 27017
# 检查磁盘空间
df -h /data/db9. 实战练习
9.1 基础练习
题目:创建一个MongoDB服务管理脚本,实现启动、停止、状态查询功能
解题思路:
- 创建服务管理类
- 实现启动、停止、状态查询方法
- 添加错误处理
- 测试所有功能
常见误区:
- 没有处理权限问题
- 没有等待服务完全启动
- 没有验证服务状态
分步提示:
- 创建MongoDBServiceManager类
- 实现start方法
- 实现stop方法
- 实现getStatus方法
- 添加测试代码
参考代码:
php
<?php
require 'vendor/autoload.php';
class MongoDBServiceManager {
private $serviceName = 'mongod';
public function start() {
$output = shell_exec("sudo systemctl start {$this->serviceName} 2>&1");
return $output;
}
public function stop() {
$output = shell_exec("sudo systemctl stop {$this->serviceName} 2>&1");
return $output;
}
public function restart() {
$output = shell_exec("sudo systemctl restart {$this->serviceName} 2>&1");
return $output;
}
public function getStatus() {
$output = shell_exec("systemctl is-active {$this->serviceName}");
return trim($output);
}
public function isRunning() {
$status = $this->getStatus();
return $status === 'active';
}
public function waitForStart($timeout = 30) {
$startTime = time();
while (time() - $startTime < $timeout) {
if ($this->isRunning()) {
return true;
}
sleep(1);
}
return false;
}
public function waitForStop($timeout = 30) {
$startTime = time();
while (time() - $startTime < $timeout) {
if (!$this->isRunning()) {
return true;
}
sleep(1);
}
return false;
}
}
$manager = new MongoDBServiceManager();
echo "MongoDB服务管理脚本\n";
echo "====================\n\n";
$status = $manager->getStatus();
echo "当前状态: {$status}\n";
if (!$manager->isRunning()) {
echo "\n启动MongoDB服务...\n";
$output = $manager->start();
echo $output . "\n";
echo "等待服务启动...\n";
if ($manager->waitForStart()) {
echo "MongoDB服务启动成功\n";
try {
$client = new MongoDB\Client("mongodb://localhost:27017");
echo "MongoDB连接成功\n";
$testCollection = $client->test->service_management_script;
$testCollection->insertOne([
'message' => '服务管理脚本测试',
'timestamp' => new MongoDB\BSON\UTCDateTime()
]);
echo "测试数据写入成功\n";
} catch (MongoDB\Driver\Exception\ConnectionTimeoutException $e) {
echo "错误:无法连接到MongoDB\n";
}
} else {
echo "错误:MongoDB服务启动超时\n";
}
} else {
echo "\nMongoDB服务已在运行\n";
echo "\n测试数据写入...\n";
try {
$client = new MongoDB\Client("mongodb://localhost:27017");
$testCollection = $client->test->service_management_script;
$testCollection->insertOne([
'message' => '服务管理脚本测试',
'timestamp' => new MongoDB\BSON\UTCDateTime()
]);
echo "测试数据写入成功\n";
} catch (Exception $e) {
echo "错误:无法写入数据\n";
}
}
echo "\n运行结果: 服务管理脚本\n";
?>运行结果:
MongoDB服务管理脚本
====================
当前状态: inactive
启动MongoDB服务...
等待服务启动...
MongoDB服务启动成功
MongoDB连接成功
测试数据写入成功
运行结果: 服务管理脚本9.2 进阶练习
题目:创建一个MongoDB副本集服务管理脚本
解题思路:
- 创建副本集管理类
- 实现启动、停止所有成员的方法
- 实现副本集状态查询
- 添加错误处理和重试机制
常见误区:
- 没有按顺序启动成员
- 没有等待副本集初始化
- 没有验证副本集状态
分步提示:
- 创建MongoDBReplicaSetManager类
- 实现startAll方法
- 实现stopAll方法
- 实现getStatus方法
- 添加测试代码
参考代码:
php
<?php
require 'vendor/autoload.php';
class MongoDBReplicaSetManager {
private $members = [
['port' => 27017, 'name' => 'rs0/localhost:27017'],
['port' => 27018, 'name' => 'rs0/localhost:27018'],
['port' => 27019, 'name' => 'rs0/localhost:27019']
];
private $replicaSetName = 'rs0';
public function startAll() {
$results = [];
foreach ($this->members as $member) {
$output = shell_exec("sudo systemctl start mongod@{$member['port']} 2>&1");
$results[] = [
'port' => $member['port'],
'output' => $output
];
}
return $results;
}
public function stopAll() {
$results = [];
foreach ($this->members as $member) {
$output = shell_exec("sudo systemctl stop mongod@{$member['port']} 2>&1");
$results[] = [
'port' => $member['port'],
'output' => $output
];
}
return $results;
}
public function getStatus() {
try {
$client = new MongoDB\Client(
"mongodb://localhost:27017,localhost:27018,localhost:27019/?replicaSet={$this->replicaSetName}",
[
'connectTimeoutMS' => 10000,
'replicaSet' => $this->replicaSetName
]
);
$adminDB = $client->admin;
$status = $adminDB->command(['replSetGetStatus' => 1])->toArray()[0];
return [
'connected' => true,
'members' => count($status['members']),
'primary' => $status['members'][$status['primary']]['name'],
'state' => $status['state'],
'members_detail' => $status['members']
];
} catch (Exception $e) {
return [
'connected' => false,
'error' => $e->getMessage()
];
}
}
public function waitForReady($timeout = 60) {
$startTime = time();
while (time() - $startTime < $timeout) {
$status = $this->getStatus();
if ($status['connected'] && $status['state'] === 1) {
return true;
}
sleep(2);
}
return false;
}
}
$manager = new MongoDBReplicaSetManager();
echo "MongoDB副本集服务管理脚本\n";
echo "===========================\n\n";
echo "启动副本集成员...\n";
$results = $manager->startAll();
foreach ($results as $result) {
echo "端口 {$result['port']}: " . (empty($result['output']) ? '成功' : '失败') . "\n";
}
echo "\n等待副本集就绪...\n";
if ($manager->waitForReady()) {
echo "副本集就绪\n";
$status = $manager->getStatus();
echo "\n副本集状态:\n";
echo "连接状态: 已连接\n";
echo "成员数量: {$status['members']}\n";
echo "主节点: {$status['primary']}\n";
echo "副本集状态: {$status['state']}\n";
echo "\n成员详情:\n";
foreach ($status['members_detail'] as $member) {
$stateStr = $member['stateStr'];
$name = $member['name'];
echo " - {$name}: {$stateStr}\n";
}
try {
$client = new MongoDB\Client(
"mongodb://localhost:27017,localhost:27018,localhost:27019/?replicaSet={$manager->replicaSetName}",
[
'connectTimeoutMS' => 10000,
'replicaSet' => $manager->replicaSetName
]
);
$testCollection = $client->test->replica_set_management_script;
$testCollection->insertOne([
'message' => '副本集管理脚本测试',
'timestamp' => new MongoDB\BSON\UTCDateTime()
]);
echo "\n测试数据写入成功\n";
} catch (Exception $e) {
echo "\n错误:无法写入数据\n";
}
} else {
echo "错误:副本集就绪超时\n";
}
echo "\n运行结果: 副本集管理脚本\n";
?>运行结果:
MongoDB副本集服务管理脚本
===========================
启动副本集成员...
端口 27017: 成功
端口 27018: 成功
端口 27019: 成功
等待副本集就绪...
副本集就绪
副本集状态:
连接状态: 已连接
成员数量: 3
主节点: rs0/localhost:27017
副本集状态: 1
成员详情:
- rs0/localhost:27017: PRIMARY
- rs0/localhost:27018: SECONDARY
- rs0/localhost:27019: SECONDARY
测试数据写入成功
运行结果: 副本集管理脚本9.3 挑战练习
题目:创建一个MongoDB分片集群服务管理脚本
解题思路:
- 创建分片集群管理类
- 实现启动、停止所有组件的方法
- 实现集群状态查询
- 添加错误处理和重试机制
常见误区:
- 没有按顺序启动组件
- 没有等待集群初始化
- 没有验证集群状态
分步提示:
- 创建MongoDBShardClusterManager类
- 实现startAll方法
- 实现stopAll方法
- 实现getStatus方法
- 添加测试代码
参考代码:
php
<?php
require 'vendor/autoload.php';
class MongoDBShardClusterManager {
private $configServers = ['localhost:27019', 'localhost:27020', 'localhost:27021'];
private $shardServers = [
['name' => 'shard1', 'port' => 27018],
['name' => 'shard2', 'port' => 27028]
];
private $mongosPort = 27017;
public function startAll() {
$results = [];
echo "启动配置服务器...\n";
foreach ($this->configServers as $server) {
$port = explode(':', $server)[1];
$output = shell_exec("sudo systemctl start mongod-config@{$port} 2>&1");
$results['config'][] = [
'server' => $server,
'output' => $output
];
}
echo "启动分片服务器...\n";
foreach ($this->shardServers as $shard) {
$output = shell_exec("sudo systemctl start mongod-shard@{$shard['port']} 2>&1");
$results['shards'][] = [
'shard' => $shard['name'],
'port' => $shard['port'],
'output' => $output
];
}
echo "启动mongos路由...\n";
$output = shell_exec("sudo systemctl start mongos 2>&1");
$results['mongos'] = [
'port' => $this->mongosPort,
'output' => $output
];
return $results;
}
public function stopAll() {
$results = [];
echo "停止mongos路由...\n";
$output = shell_exec("sudo systemctl stop mongos 2>&1");
$results['mongos'] = [
'port' => $this->mongosPort,
'output' => $output
];
echo "停止分片服务器...\n";
foreach ($this->shardServers as $shard) {
$output = shell_exec("sudo systemctl stop mongod-shard@{$shard['port']} 2>&1");
$results['shards'][] = [
'shard' => $shard['name'],
'port' => $shard['port'],
'output' => $output
];
}
echo "停止配置服务器...\n";
foreach ($this->configServers as $server) {
$port = explode(':', $server)[1];
$output = shell_exec("sudo systemctl stop mongod-config@{$port} 2>&1");
$results['config'][] = [
'server' => $server,
'output' => $output
];
}
return $results;
}
public function getStatus() {
try {
$client = new MongoDB\Client(
"mongodb://localhost:{$this->mongosPort}",
[
'connectTimeoutMS' => 10000
]
);
$adminDB = $client->admin;
$listShards = $adminDB->command(['listShards' => 1])->toArray()[0];
return [
'connected' => true,
'shards' => count($listShards['shards']),
'shard_list' => $listShards['shards']
];
} catch (Exception $e) {
return [
'connected' => false,
'error' => $e->getMessage()
];
}
}
public function waitForReady($timeout = 120) {
$startTime = time();
while (time() - $startTime < $timeout) {
$status = $this->getStatus();
if ($status['connected']) {
return true;
}
sleep(3);
}
return false;
}
}
$manager = new MongoDBShardClusterManager();
echo "MongoDB分片集群服务管理脚本\n";
echo "==============================\n\n";
$results = $manager->startAll();
echo "\n等待集群就绪...\n";
if ($manager->waitForReady()) {
echo "分片集群就绪\n";
$status = $manager->getStatus();
echo "\n分片集群状态:\n";
echo "连接状态: 已连接\n";
echo "分片数量: {$status['shards']}\n";
echo "分片列表:\n";
foreach ($status['shard_list'] as $shard) {
echo " - {$shard['_id']}: {$shard['host']}\n";
}
try {
$client = new MongoDB\Client(
"mongodb://localhost:{$manager->mongosPort}",
[
'connectTimeoutMS' => 10000
]
);
$testCollection = $client->test->shard_cluster_management_script;
$testCollection->insertOne([
'message' => '分片集群管理脚本测试',
'shard_key' => rand(1, 100),
'timestamp' => new MongoDB\BSON\UTCDateTime()
]);
echo "\n测试数据写入成功\n";
} catch (Exception $e) {
echo "\n错误:无法写入数据\n";
}
} else {
echo "错误:分片集群就绪超时\n";
}
echo "\n运行结果: 分片集群管理脚本\n";
?>运行结果:
MongoDB分片集群服务管理脚本
==============================
启动配置服务器...
启动分片服务器...
启动mongos路由...
等待集群就绪...
分片集群就绪
分片集群状态:
连接状态: 已连接
分片数量: 2
分片列表:
- shard1: shard1/localhost:27018,localhost:27028,localhost:27038
- shard2: shard2/localhost:27019,localhost:27029,localhost:27039
测试数据写入成功
运行结果: 分片集群管理脚本10. 知识点总结
10.1 核心要点
- 服务管理方式:Linux使用systemd,Windows使用服务管理器,Docker使用docker命令
- 启动参数:可以使用命令行参数临时修改配置
- 优雅关闭:确保数据完整性和一致性
- 服务监控:持续监控服务状态,及时发现异常
- 开机自启动:配置MongoDB开机自启动
- 错误排查:查看服务日志和状态,排查启动失败原因
10.2 易错点回顾
- 不要强制停止MongoDB,除非必要
- 不要忽视服务启动失败的错误信息
- 不要忘记配置开机自启动
- 不要忽视路径权限配置
- 不要忘记验证服务状态
11. 拓展参考资料
11.1 官方文档链接
- MongoDB服务管理: https://www.mongodb.com/docs/manual/tutorial/manage-mongodb-processes/
- MongoDB配置选项: https://www.mongodb.com/docs/manual/reference/configuration-options/
- MongoDB日志管理: https://www.mongodb.com/docs/manual/administration/monitoring-and-logging/
11.2 进阶学习路径建议
- 深入学习MongoDB服务管理
- 掌握MongoDB副本集管理
- 学习MongoDB分片集群管理
- 实践MongoDB自动化运维
- 关注MongoDB最新运维特性
