Dzięki @avanti, @MarkusWMalhberg - zastanawianie się, jak odpowiedzieć na komentarze, popchnęło mnie we właściwym kierunku. Trochę to zajęło, więc będę trochę gadatliwy, wyjaśniając konfigurację.
Przegląd
Koncentrując się na doświadczeniu użytkownika, chcemy stworzyć konfigurację bazy danych Mongo, która umożliwia odczyty i zapisy najbliżej użytkownika.
Założenia
- Użytkownicy prawie zawsze czytają i zapisują dokumenty w swoim regionie i nie przeszkadza im, że rzadkie odczyty danych z innych regionów są wolniejsze.
- Każdy dokument zawiera klucz wskazujący ich region (dla uproszczenia/klarowności)
Duża część dokumentacji shardingu skupia się na HA/DR. Dzięki doświadczeniu użytkownika i zgodności regionalnej nacisk kładzie się na lokalizację, a nie na dystrybucję obciążenia.
Ten przykład całkowicie zignoruje HA/DR, odczyta preferencje i problemy związane z zapisem, ale należy je rozwiązać, jeśli POC dojrzeje. Przykład ignoruje je na rzecz przejrzystości realizacji celu:lokalne odczyty/zapisy.
Referencje
- Segmentacja operacyjna
- Zarządzanie tagami fragmentów
- Konfiguracja zestawu replik
- Różne błędy bazy danych konfiguracji mongos
Sztuczki
Wiemy
- Chcemy jednej bazy danych aplikacji, aby wszystkie dane były dostępne
- Chcemy, aby użytkownicy odczytywali/zapisali lokalnie, więc potrzebujemy bazy danych w pobliżu każdej grupy użytkowników; potrzebujemy zestawu replik
- Zapisy mogą być dokonywane tylko w węzłach zestawu replik podstawowych, więc aby uzyskać węzły podstawowe obok każdej grupy użytkowników, potrzebujemy wielu replik; sharded klaster
W ramach standardowej wiedzy ReplicaSet i Sharding istnieją 2 klucze do tej konfiguracji:
- Przypisz priorytet do regionalnie lokalnego węzła ReplicaSet, aby upewnić się, że stanie się on podstawowym.
- Użyj tagowania klucza fragmentu uwzględniającego lokalizację, aby upewnić się, że dane są zapisywane w lokalnych fragmentach
Klucze fragmentów mogą być dowolne:zależy nam tylko na tym, aby użytkownicy mogli czytać/zapisywać lokalnie, w przeciwieństwie do efektywnego współdzielenia obciążenia.
Każda kolekcja będzie musiała zostać podzielona na fragmenty, w przeciwnym razie zapisy trafią do fragmentu zero.
Pożądana konfiguracja
Konfiguracja
#!/usr/bin/env bash
echo ">>> Clean up processes and files from previous runs"
echo ">>> killAll mongod mongos"
killall mongod mongos
echo ">>> Remove db files and logs"
rm -rf data
rm -rf log
# Create the common log directory
mkdir log
echo ">>> Start replica set for shard US-East"
mkdir -p data/shard-US-East/rsMemberEast data/shard-US-East/rsMemberWest
mongod --replSet shard-US-East --logpath "log/shard-US-East-rsMemberEast.log" --dbpath data/shard-US-East/rsMemberEast --port 37017 --fork --shardsvr --smallfiles
mongod --replSet shard-US-East --logpath "log/shard-US-East-rsMemberWest.log" --dbpath data/shard-US-East/rsMemberWest --port 37018 --fork --shardsvr --smallfiles
echo ">>> Sleep 15s to allow US-East replica set to start"
sleep 15
# The US-East replica set member is assigned priority 2 so that it becomes primary
echo ">>> Configure replica set for shard US-East"
mongo --port 37017 << 'EOF'
config = { _id: "shard-US-East", members:[
{ _id : 0, host : "localhost:37017", priority: 2 },
{ _id : 1, host : "localhost:37018" }]};
rs.initiate(config)
EOF
echo ">>> Start replica set for shard-US-West"
mkdir -p data/shard-US-West/rsMemberEast data/shard-US-West/rsMemberWest
mongod --replSet shard-US-West --logpath "log/shard-US-West-rsMemberEast.log" --dbpath data/shard-US-West/rsMemberEast --port 47017 --fork --shardsvr --smallfiles
mongod --replSet shard-US-West --logpath "log/shard-US-West-rsMemberWest.log" --dbpath data/shard-US-West/rsMemberWest --port 47018 --fork --shardsvr --smallfiles
echo ">>> Sleep 15s to allow US-West replica set to start"
sleep 15
# The US-West replica set member is assigned priority 2 so that it becomes primary
echo ">>> Configure replica set for shard-US-West"
mongo --port 47017 << 'EOF'
config = { _id: "shard-US-West", members:[
{ _id : 0, host : "localhost:47017" },
{ _id : 1, host : "localhost:47018", priority: 2 }]};
rs.initiate(config)
EOF
# Shard config servers: should be 3 and all must be up to deploy a shard cluster
# These are the mongos backing store for routing information
echo ">>> Start config servers"
mkdir -p data/config/config-us-east data/config/config-us-west data/config/config-redundant
mongod --logpath "log/cfg-us-east.log" --dbpath data/config/config-us-east --port 57040 --fork --configsvr --smallfiles
mongod --logpath "log/cfg-us-west.log" --dbpath data/config/config-us-west --port 57041 --fork --configsvr --smallfiles
mongod --logpath "log/cfg-redundant.log" --dbpath data/config/config-redundant --port 57042 --fork --configsvr --smallfiles
echo ">>> Sleep 5 to allow config servers to start and stabilize"
sleep 5
# All mongos's must point at the same config server, a coordinator dispatches writes to each
echo ">>> Start mongos"
mongos --logpath "log/mongos-us-east.log" --configdb localhost:57040,localhost:57041,localhost:57042 --port 27017 --fork
mongos --logpath "log/mongos-us-west.log" --configdb localhost:57040,localhost:57041,localhost:57042 --port 27018 --fork
echo ">>> Wait 60 seconds for the replica sets to stabilize"
sleep 60
# Enable sharding on the 'sales' database and 'sales.users' collection
# Every collection in 'sales' must be sharded or the writes will go to shard 0
# Add a shard tag so we can associate shard keys with the tag (region)
# Shard tag range main and max cannot be the same so we use a region id for US-East = 1
# and US-West = 2. sh.addTagRange() is inclusive of minKey and exclusive of maxKey.
# We only need to configure one mongos - config will be propogated to all mongos through
# the config server
echo ">>> Add shards to mongos"
mongo --port 27017 <<'EOF'
db.adminCommand( { addshard : "shard-US-East/"+"localhost:37017" } );
db.adminCommand( { addshard : "shard-US-West/"+"localhost:47017" } );
db.adminCommand({enableSharding: "sales"})
db.adminCommand({shardCollection: "sales.users", key: {region:1}});
sh.addShardTag("shard-US-East", "US-East")
sh.addShardTag("shard-US-West", "US-West")
sh.addTagRange("sales.users", { region: 1 }, { region: 2 }, "US-East")
sh.addTagRange("sales.users", { region: 2 }, { region: 3 }, "US-West")
EOF
Testowanie
Sprawdź, czy nasza konfiguracja jest poprawna za pomocą sh.status()
. Fragmenty notatek są prawidłowo przypisane, a tagi i regionalne klucze fragmentów są prawidłowo przypisane.
[[email protected] RegionalSharding 14:38:50]$ mongo --port 27017 sales
...
rakshasa(mongos-3.0.5)[mongos] sales> sh.status()
sharding version: {
"_id": 1,
"minCompatibleVersion": 5,
"currentVersion": 6,
"clusterId": ObjectId("55fdddc5746e30dc3651cda4")
}
shards:
{ "_id": "shard-US-East", "host": "shard-US-East/localhost:37017,localhost:37018", "tags": [ "US-East" ] }
{ "_id": "shard-US-West", "host": "shard-US-West/localhost:47017,localhost:47018", "tags": [ "US-West" ] }
balancer:
Currently enabled: yes
Currently running: no
Failed balancer rounds in last 5 attempts: 0
Migration Results for the last 24 hours:
1 : Success
databases:
{ "_id": "admin", "partitioned": false, "primary": "config" }
{ "_id": "test", "partitioned": false, "primary": "shard-US-East" }
{ "_id": "sales", "partitioned": true, "primary": "shard-US-East" }
sales.users
shard key: { "region": 1 }
chunks:
shard-US-East: 2
shard-US-West: 1
{ "region": { "$minKey" : 1 } } -> { "region": 1 } on: shard-US-East Timestamp(2, 1)
{ "region": 1 } -> { "region": 2 } on: shard-US-East Timestamp(1, 3)
{ "region": 2 } -> { "region": { "$maxKey" : 1 } } on: shard-US-West Timestamp(2, 0)
tag: US-East {
"region": 1
} -> {
"region": 2
}
tag: US-West {
"region": 2
} -> {
"region": 3
}
Sprawdź, czy zapisy są dokonywane we właściwym fragmencie i podstawowym.Utwórz rekord w każdym regionie
db.users.insert({region:1, name:"us east user"})
db.users.insert({region:2, name:"us west user"})
Możesz zalogować się do każdego członka każdego zestawu replik i widzieć użytkownika wschodniego tylko we fragmencie USA-Wschód, a użytkownika zachodniego tylko we fragmencie US-West.