В этой статье мы рассмотрим только конфигурацию MongoDB, не затрагивая вопросы подключения репозитория монги и установки пакетов в систему.
Распределенный кластер MongoDB состоит из следующих компонентов:
Шард
Шард — это инстанс mongod, который хранит часть данных шардированной коллекции. Для использования в production, каждый шард должен быть набором реплик (replicaSet).
Сервер конфигураций
Так же экземпляр mongod, который хранит метаданные кластера. Метаданные указывают какие данные хранятся на каком шарде.
Сервер маршрутизации
Экземпляр mongos. Его задача — маршрутизация запросов от приложений к шардам.
Ниже приведена схема работы шардированного кластера MongoDB
Удобнее всего необходимые роли группировать следующим образом:
- Сервер конфигурации + сервер маршрутизации
- Шард
Допустим, для создания этих ролей мы имеем 3 сервера:
- mongos01
- mongos02
- mongos03
Настройка сервера конфигураций
Для того, что бы mongod работал как сервер конфигураций, приводим /etc/mongod.conf к следующему виду:
logpath=/var/log/mongodb/mongod.log
logappend=true
fork=true
dbpath=/opt/mongocfg
pidfilepath=/var/run/mongodb/mongod.pid
bind_ip=<lo ip>,<eth ip>
configsvr=false
После чего запускаем сервис
# service mongod start
Настройка сервера маршрутизации
Прежде чем переходить к настройке сервера маршрутизации, необходимо убедиться что в системе установлен пакет mongodb-org-mongos
# rpm -qa | grep mongos
mongodb-org-mongos-2.6.2-1.x86_64
Для начала, создадим файл конфигурации для сервиса mongos /etc/mongos.conf и приведем его к следующему виду:
configdb=mongos01:27019,mongos02:27019,mongos03:27019 # Mongo config servers addresses
port = 27017
logpath = /var/log/mongodb/mongos.log
logappend = true
fork = true
bind_ip=<lo ip>,<eth ip>
verbose = false
Mongo не включили в свой пакет init script для mongos, посему создадим его
cat > /etc/init.d/mongos << TheEnd
#!/bin/bash
# mongos - Startup script for mongos
# chkconfig: 35 85 15
# description: Mongo Router Process for sharding
# processname: mongos
# config: /etc/mongos.conf
# pidfile: /var/run/mongos.pid
. /etc/rc.d/init.d/functions
# mongos will read mongos.conf for configuration settings
# Add variable to support multiple instances of mongos
# The instance name is by default the name of this init script
# In this way another instance can be created by just copying this init script
# and creating a config file with the same name and a .conf extension
# For Example:
# /etc/init.d/mongos2
# /etc/mongos2.conf
# Optionally also create a sysconfig file to override env variables below
# /etc/sysconfig/mongos2
INSTANCE=`basename $0`
# By default OPTIONS just points to the /etc/mongod.conf config file
# This can be overriden in /etc/sysconfig/mongod
OPTIONS=" -f /etc/${INSTANCE}.conf"
PID_PATH=/var/run/mongo
PID_FILE=${PID_PATH}/${INSTANCE}.pid
MONGO_BIN=/usr/bin/mongos
MONGO_USER=mongod
MONGO_GROUP=mongod
MONGO_ULIMIT=12000
MONGO_LOCK_FILE=/var/lock/subsys/${INSTANCE}
# Source sysconfig options so that above values can be overriden
SYSCONFIG="/etc/sysconfig/${INSTANCE}"
if [ -f "$SYSCONFIG" ]; then
. "$SYSCONFIG" || true
fi
# Create mongo pids path if it does not exist
if [ ! -d "${PID_PATH}" ]; then
mkdir -p "${PID_PATH}"
chown "${MONGO_USER}:${MONGO_GROUP}" "${PID_PATH}"
fi
start()
{
echo -n $"Starting ${INSTANCE}: "
daemon --user "$MONGO_USER" --pidfile $PID_FILE $MONGO_BIN $OPTIONS --pidfilepath=$PID_FILE
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && touch $MONGO_LOCK_FILE
return $RETVAL
}
stop()
{
echo -n $"Stopping ${INSTANCE}: "
killproc -p $PID_FILE -t30 -TERM $MONGO_BIN
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && rm -f $MONGO_LOCK_FILE
[ $RETVAL -eq 0 ] && rm -f $PID_FILE
return $RETVAL
}
restart () {
stop
start
}
ulimit -n $MONGO_ULIMIT
RETVAL=0
case "$1" in
start)
start
;;
stop)
stop
;;
restart|reload|force-reload)
restart
;;
condrestart)
[ -f $MONGO_LOCK_FILE ] && restart || :
;;
status)
status -p $PID_FILE $MONGO_BIN
RETVAL=$?
;;
*)
echo "Usage: $0 {start|stop|status|restart|reload|force-reload|condrestart}"
RETVAL=1
esac
exit $RETVAL
TheEnd
Сделаем его исполняемым
chmod +x /etc/init.d/mongos
Теперь можно запускать
service mongos start
И не забыть
# chkconfig mongod on
# chkconfig mongos on
Теперь нужно повторить эти действия на остальных серверах.
Настройка шардов
Первое что необходимо помнить при настройке шардов для production среды — каждый шард это replica set.
Более подробно про репликацию в MongoDB можно прочесть в официальной документации
Мы же не будем на этом подробно останавливаться, а приступим к насройке.
У нас будет 4 сервера:
- Master для первого шарда (mongo01-rs01)
- Slave для первого шарда (mongo02-rs01)
- Master для второго шарда (mongo01-rs02)
- Slave для второго шарда (mongo02-rs02)
Допустим, на всех четырех серверах уже установлена система и установлен mongodb
В /etc/mongodb.conf на mongo01-rs01 и mongo02-rs01 нужно задать имя для набора реплик, которое будет использовать этот шард
replSet=rs01
Сохраняем и запускаем mongod.
Далее заходим в консоль mongo на сервере который планируем сделать Master
# mongo
И инициализируем набор реплик
> rs.initiate()
Что бы убедиться что набор реплик инициализирован посмотрим его конфиг
rs01:PRIMARY> rs.conf()
Вывод должен показать что-то подобное:
{
"_id" : "rs01",
"version" : 7,
"members" : [
{
"_id" : 0,
"host" : "mongo01-rs01:27017"
}
]
}
Далее добавляем наш второй сервер в этот набор
rs01:PRIMARY> rs.add(«mongo02-rs01»)
И проверяем конфиг
rs01:PRIMARY> rs.conf()
{
"_id" : "rs01",
"version" : 7,
"members" : [
{
"_id" : 0,
"host" : "mongo01-rs01:27017"
},
{
"_id" : 1,
"host" : "mongo02-rs01:27017",
}
]
}
Для повышения отказоустойчивости MongoDB рекомендуется количество машин в наборе делать не четным.
Так как мы не хотим создавать еще одну копию данных, мы можем создать Арбитра
Арбитр — это экземпляр mongod, который является членом набора реплик, но не хранит никаких данных. Он участвует в выборе нового мастера.
Про то как устроены выборы, очень подробно написано в официальной документации
Для того, чтобы не выделять под него отдельную машину — воспользуемся одной из ранее созданных — mongos01
Как мы помним, там по service mongod start запускается экземпляр mongod который является сервером конфигураций.
Что бы не запускать арбитра руками мы должны сделать для него init script
cat > /etc/init.d/mongo-rs01-arb << TheEnd
#!/bin/bash
# mongod - Startup script for mongod
# chkconfig: 35 85 15
# description: Mongo is a scalable, document-oriented database.
# processname: mongod
# config: /etc/mongod.conf
# pidfile: /var/run/mongodb/mongod.pid
. /etc/rc.d/init.d/functions
# things from mongod.conf get there by mongod reading it
# NOTE: if you change any OPTIONS here, you get what you pay for:
# this script assumes all options are in the config file.
CONFIGFILE="/etc/mongod-rs01-arb.conf"
OPTIONS=" -f $CONFIGFILE"
SYSCONFIG="/etc/sysconfig/mongod-rs01-arb"
# FIXME: 1.9.x has a --shutdown flag that parses the config file and
# shuts down the correct running pid, but that's unavailable in 1.8
# for now. This can go away when this script stops supporting 1.8.
DBPATH=`awk -F= '/^dbpath[[:blank:]]*=[[:blank:]]*/{print $2}' "$CONFIGFILE"`
PIDFILE=`awk -F= '/^pidfilepath[[:blank:]]*=[[:blank:]]*/{print $2}' "$CONFIGFILE"`
mongod=${MONGOD-/usr/bin/mongod}
MONGO_USER=mongod
MONGO_GROUP=mongod
if [ -f "$SYSCONFIG" ]; then
. "$SYSCONFIG"
fi
# Handle NUMA access to CPUs (SERVER-3574)
# This verifies the existence of numactl as well as testing that the command works
NUMACTL_ARGS="--interleave=all"
if which numactl >/dev/null 2>/dev/null && numactl $NUMACTL_ARGS ls / >/dev/null 2>/dev/null
then
NUMACTL="numactl $NUMACTL_ARGS"
else
NUMACTL=""
fi
start()
{
# Recommended ulimit values for mongod or mongos
# See http://docs.mongodb.org/manual/reference/ulimit/#recommended-settings
#
ulimit -f unlimited
ulimit -t unlimited
ulimit -v unlimited
ulimit -n 64000
ulimit -m unlimited
ulimit -u 32000
echo -n $"Starting mongod: "
daemon --user "$MONGO_USER" "$NUMACTL $mongod $OPTIONS >/dev/null 2>&1"
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/mongod-rs01-arb
}
stop()
{
echo -n $"Stopping mongod: "
killproc -p "$PIDFILE" -d 300 /usr/bin/mongod
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/mongod-rs01-arb
}
restart () {
stop
start
}
RETVAL=0
case "$1" in
start)
start
;;
stop)
stop
;;
restart|reload|force-reload)
restart
;;
condrestart)
[ -f /var/lock/subsys/mongod ] && restart || :
;;
status)
status $mongod
RETVAL=$?
;;
*)
echo "Usage: $0 {start|stop|status|restart|reload|force-reload|condrestart}"
RETVAL=1
esac
exit $RETVAL
TheEnd
Делаем его исполняемым
# chmod+x /etc/init.d/mongo-rs01-arb
Создадим для него BaseDir и файл конфигурации
# mkdir /opt/mongo-rs01-arb; chown mongod:mongod /opt/mongo-rs01-arb
# cp -av /etc/mongod.conf /etc/mongod-rs01-arb.conf
Далее в файле /etc/mongod-rs01-arb.conf редактируем следующие строки
port=27020
dbpath=/opt/mongo-rs01-arb
pidfilepath=/var/run/mongodb/mongod-rs01-arb.pid
И удаляем/комментируем строку
configsvr=true
Сохраняем файл и запускаем сервис
# service mongo-rs01-arb start
Далее возвращаемся на наш Master для rs01, и в консоли mongo добавляем арбитра в набор реплик
> rs.addArb(«mongos01:27020»)
Проверяем конфиг
rs01:PRIMARY> rs.conf()
{
"_id" : "rs01",
"version" : 7,
"members" : [
{
"_id" : 0,
"host" : "mongo01-rs01:27017"
},
{
"_id" : 1,
"host" : "mongo02-rs01:27017",
},
{
"_id" : 2,
"host" : "mongos01:27020",
"arbiterOnly" : true
}
]
}
Повторяем эту процедуру с оставшимися двумя серверами под второй набор реплик который будет вторым шардом в нашем кластере (mongo01-rs02 и mongo02-rs02)
И так, мы создали 2 набора реплик, которые теперь надо добавить в наш распределенный кластер.
Для этого идем на mongos01 и заходим в консоль mongo (Следует помнить, что, в данном случае, мы подключаемся к сервису mongos)
> sh.addShard(«rs01//mongo01-rs01:27017,mongo02-rs01:27017»)
> sh.addShard(«rs02/mongo01-rs02:27017,mongo02-rs02:27017»)
Проверяем:
> sh.status()
Вывод должен содержать следующие строки:
shards:
{ "_id" : "rs01", "host" : "rs01/mongo01-rs01:27017,mongo02-rs01:27017" }
{ "_id" : "rs02", "host" : "rs02/mongo01-rs02:27017,mongo02-rs02:27017" }
Это означает что в наш кластер успешно добавлены 2 шарда
Теперь добавим в наш распределенный кластер базу которую будем шардировать.
В нашем случае это будет база содержащая файловую систему GridFS
> use filestore
> sh.enableSharding(«filestore»)
> sh.shardCollection(«filestore.fs.chunks», { files_id: 1, n: 1 })
Проверяем статус
> sh.status()
Вывод должен быть примерно таким:
shards:
{ "_id" : "rs01", "host" : "rs01/mongo01-rs01:27017,mongo02-rs01:27017" }
{ "_id" : "rs02", "host" : "rs02/mongo01-rs02:27017,mongo02-rs02:27017"}
databases:
{ "_id" : "admin", "partitioned" : false, "primary" : "config" }
{ "_id" : "test", "partitioned" : false, "primary" : "rs02" }
{ "_id" : "filestore", "partitioned" : true, "primary" : "rs01" }
filestore.fs.chunks
shard key: { "files_id" : 1, "n" : 1 }
chunks:
rs01 1363
rs02 103
too many chunks to print, use verbose if you want to force print
Вот и все, теперь можем использовать наш распределенный GridFS в приложении обращаясь к экземплярам mongos
PS: про ошибки и не точности просьба писать в личку,
Автор: garacio