overview
Alibaba CloudとMongoDBを触る機会ができたので、試しにいろいろいじってみる。
まずは事前準備としてローカルでMongoDBを触る。
Mongo DBとは
MongoDBはRDBMSではなく、いわゆるNoSQLと呼ばれるデータベースに分類されるものである。RDBMSのようにレコードをテーブルに格納するのではなく、「ドキュメント」と呼ばれる構造的データをJSONライクな形式で表現し、そのドキュメントの集合を「コレクション」として管理する(このデータの物理的な格納はBSONと呼ばれるJSONのバイナリ版といえる形式で行われる)。
引用:Wikipedia
データ構造は以下。
引用:公式
MongoDB のストレージ構造は、従来のリレーショナル データベースとは異なります。 MongoDB のデータは次のレベルで編成されます。
ドキュメント: ドキュメントは、MongoDB のデータの基本単位です。ドキュメントは BSON キーと値のペアで構成され、リレーショナル データベースの行に相当します。
コレクション: コレクションには複数のドキュメントが含まれます。リレーショナル データベースのテーブルに相当します。
データベース: データベースには複数のコレクションが含まれます。リレーショナル データベースに相当します。 ApsaraDB for MongoDB インスタンスに複数のデータベースを作成できます。
- 多くのプログラミング言語のネイティブデータ型に対応
- RDBのような多重JOINに陥りにくい
- 動的スキーマにより振る舞いを変えやすい
などの利点がある
スケールアウトしやすく、ログ蓄積や軽い読み取りを大量に捌くケースに使う。
ちなみにRedisよりも使われてるらしい。意外。
Redis vs Mongoに関してはAWSが示してくれているので参考になる。
https://aws.amazon.com/jp/compare/the-difference-between-redis-and-mongodb/
水平スケーリングにより、MongoDB は大量のデータを効率的に処理できます。シャーディングを使用して、複数のリージョンとノードにデータを分散します。クロスシャーディング操作では、複数のシャードにわたってクエリと更新を行うことができます。
Redis は MongoDB ほどのスケーラビリティを提供していません。Redis は、プライマリオペレーションにデフォルトでシャードを 1 つだけ使用します。シャーディングはハッシュベースで手動で管理する必要があるため、管理が複雑になります。Redis にはクロスシャード機能もありません。
MongoDB と Redis はどちらも、レプリケーションによる可用性をサポートしています。ただし、MongoDB はレプリカセットを使用することでより高い水準の可用性をサポートします。自動フェイルオーバーメカニズムをサポートしています。
これとは対照的に、Redis はデフォルトでは自動フェイルオーバーを提供しません。特にレプリカが別のデータセンターにある場合は、管理者ユーザーが手動フェイルオーバーを開始します。自動フェイルオーバーが必要な場合は、Redis Sentinel という別のコンポーネントをセットアップして構成する必要があります。
MongoDB は、マルチドキュメントの、原子性、一貫性、独立性、耐久性のある (ACID) トランザクションをサポートしています。そのため、複数の操作でデータの一貫性を保つことができます。MongoDB は、セッション内ですべての変更をコミットまたはロールバックします。これにより、ACID への準拠が確保されます。
逆に、Redis には ACID サポートが組み込まれていません。ただし、MULTI コマンドを使用すると、複数のコマンドを 1 つのアトミック操作にグループ化できます。しかし、これだけでは解決策にはなりません。また、Redis はトランザクション内でロールバック機能をネイティブにサポートしていないため、アプリケーションコード内にロールバック機能を実装する必要があります
MongoDB は、複雑な空間計算やデータ分析機能を実行する場合でも、高い柔軟性でクエリを実行できます。MongoDB は JSON に似た構文をサポートする MongoDB クエリー言語 (MQL) を使用しており、高度なクエリを簡略化します。
これとは対照的に、Redis は複雑なクエリや検索機能ではなく、key-value の高速アクセス操作に最適化されています。
どうやら同じNoSQLでもより可用性があって、データ保持もある程度担保しつつ、リッチな操作ができるのがMongo
アプリ側でデータ抽出を頑張れる&データが揮発性高いのであればRedis
というイメージ。
ただ、AlibabaCloudのApsaraDB for Redisでは以下の点が違うみたい。
Redis は、プライマリオペレーションにデフォルトでシャードを 1 つだけ使用します。シャーディングはハッシュベースで手動で管理する必要があるため、管理が複雑になります。Redis にはクロスシャード機能もありません。
クラスターバージョンでは、自動的にハッシュベースのシャーディングが行われ、各キーはハッシュスロットに割り当てられる。なので、ユーザーは手動でシャーディングを管理する手間を省ける。
Redis はデフォルトでは自動フェイルオーバーを提供しません。特にレプリカが別のデータセンターにある場合は、管理者ユーザーが手動フェイルオーバーを開始します。
master-replicaの構成になり、masterが障害発生する場合は、自動フェールオーバーする。
だから大きな懸念点はなさそう!
やってみる
まずはローカルでPythonからMongo DBに接続するAPIをつくる。
アプリケーション
使用技術スタック
- Docker
- Python
- FastAPI
- MongoDB
- pip
ファイル構成
DockerでFastAPIを利用。
公式サンプルをベースに用意。
FROM python:3.10.13
WORKDIR /code
COPY ./app/requirements.txt /code/requirements.txt
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt
COPY ./app /code/app
docker-composeを利用し、webコンテナとMongoDBコンテナを立てる
services:
web:
build: .
ports:
- '8000:8000'
volumes:
- ./app:/code/app
command: uvicorn main:app --host 0.0.0.0 --reload
working_dir: /code/app
mongo:
image: mongo
container_name: mongo
restart: always
ports:
- 27017:27017
requirements.txtを用意
fastapi>=0.68.0,<0.69.0
pydantic>=1.8.0,<2.0.0
uvicorn>=0.15.0,<0.16.0
pymongo
main.pyを用意
from fastapi import FastAPI, Body
from mongo import MongoManager
app = FastAPI()
mongo_manager = MongoManager()
@app.get("/")
def get_all():
all = mongo_manager.get_all()
return all
@app.get("/name/{name}")
def get_item(name: str):
return mongo_manager.get_by_name(name)
@app.post("/name")
def post_name(name: str = Body(...)):
mongo_manager.add_one(name)
return "ok"
@app.delete("/")
def delete_all():
mongo_manager.delete_all()
return "ok"
mongo.pyを用意
from pymongo import MongoClient
class MongoManager(object):
def __init__(self):
self.client = MongoClient('mongodb://mongo')
self.db = self.client['test']
def get_all(self):
"""全データ取得"""
return list(self.db.test.find({}, {'_id': 0}))
def get_by_name(self, name: str):
"""データ取得"""
return list(self.db.test.find({"dir": {
"name": name
}}, {'_id': 0}))
def add_one(self, name: str):
"""データ挿入"""
d = {"name": name}
data = {
'title': 'names',
'dir': d
}
return self.db.test.insert_one(data)
def delete_all(self):
"""全データ削除"""
self.db.test.delete_many({})
ローカルで起動する
docker-compose up
でコンテナを立ちあげると下記ログが出る。
[+] Running 2/0
✔ Container python-mongo-web-1 Created 0.0s
✔ Container python-mongo-mongo-1 Recreated 0.0s
Attaching to mongo, python-mongo-web-1
mongo | {"t":{"$date":"2024-03-17T07:53:14.978+00:00"},"s":"I", "c":"CONTROL", "id":23285, "ctx":"main","msg":"Automatically disabling TLS 1.0, to force-enable TLS 1.0 specify --sslDisabledProtocols 'none'"}
mongo | {"t":{"$date":"2024-03-17T07:53:14.978+00:00"},"s":"I", "c":"NETWORK", "id":4915701, "ctx":"main","msg":"Initialized wire specification","attr":{"spec":{"incomingExternalClient":{"minWireVersion":0,"maxWireVersion":21},"incomingInternalClient":{"minWireVersion":0,"maxWireVersion":21},"outgoing":{"minWireVersion":6,"maxWireVersion":21},"isInternalClient":true}}}
mongo | {"t":{"$date":"2024-03-17T07:53:14.979+00:00"},"s":"I", "c":"NETWORK", "id":4648601, "ctx":"main","msg":"Implicit TCP FastOpen unavailable. If TCP FastOpen is required, set tcpFastOpenServer, tcpFastOpenClient, and tcpFastOpenQueueSize."}
mongo | {"t":{"$date":"2024-03-17T07:53:14.981+00:00"},"s":"I", "c":"REPL", "id":5123008, "ctx":"main","msg":"Successfully registered PrimaryOnlyService","attr":{"service":"TenantMigrationDonorService","namespace":"config.tenantMigrationDonors"}}
mongo | {"t":{"$date":"2024-03-17T07:53:14.981+00:00"},"s":"I", "c":"REPL", "id":5123008, "ctx":"main","msg":"Successfully registered PrimaryOnlyService","attr":{"service":"TenantMigrationRecipientService","namespace":"config.tenantMigrationRecipients"}}
mongo | {"t":{"$date":"2024-03-17T07:53:14.981+00:00"},"s":"I", "c":"CONTROL", "id":5945603, "ctx":"main","msg":"Multi threading initialized"}
mongo | {"t":{"$date":"2024-03-17T07:53:14.981+00:00"},"s":"I", "c":"TENANT_M", "id":7091600, "ctx":"main","msg":"Starting TenantMigrationAccessBlockerRegistry"}
mongo | {"t":{"$date":"2024-03-17T07:53:14.982+00:00"},"s":"I", "c":"CONTROL", "id":4615611, "ctx":"initandlisten","msg":"MongoDB starting","attr":{"pid":1,"port":27017,"dbPath":"/data/db","architecture":"64-bit","host":"9e7f96999d20"}}
mongo | {"t":{"$date":"2024-03-17T07:53:14.982+00:00"},"s":"I", "c":"CONTROL", "id":23403, "ctx":"initandlisten","msg":"Build Info","attr":{"buildInfo":{"version":"7.0.6","gitVersion":"66cdc1f28172cb33ff68263050d73d4ade73b9a4","openSSLVersion":"OpenSSL 3.0.2 15 Mar 2022","modules":[],"allocator":"tcmalloc","environment":{"distmod":"ubuntu2204","distarch":"aarch64","target_arch":"aarch64"}}}}
mongo | {"t":{"$date":"2024-03-17T07:53:14.982+00:00"},"s":"I", "c":"CONTROL", "id":51765, "ctx":"initandlisten","msg":"Operating System","attr":{"os":{"name":"Ubuntu","version":"22.04"}}}
mongo | {"t":{"$date":"2024-03-17T07:53:14.982+00:00"},"s":"I", "c":"CONTROL", "id":21951, "ctx":"initandlisten","msg":"Options set by command line","attr":{"options":{"net":{"bindIp":"*"}}}}
mongo | {"t":{"$date":"2024-03-17T07:53:14.985+00:00"},"s":"I", "c":"STORAGE", "id":22270, "ctx":"initandlisten","msg":"Storage engine to use detected by data files","attr":{"dbpath":"/data/db","storageEngine":"wiredTiger"}}
mongo | {"t":{"$date":"2024-03-17T07:53:14.985+00:00"},"s":"I", "c":"STORAGE", "id":22297, "ctx":"initandlisten","msg":"Using the XFS filesystem is strongly recommended with the WiredTiger storage engine. See <http://dochub.mongodb.org/core/prodnotes-filesystem","tags":["startupWarnings>"]}
mongo | {"t":{"$date":"2024-03-17T07:53:14.985+00:00"},"s":"I", "c":"STORAGE", "id":22315, "ctx":"initandlisten","msg":"Opening WiredTiger","attr":{"config":"create,cache_size=3413M,session_max=33000,eviction=(threads_min=4,threads_max=4),config_base=false,statistics=(fast),log=(enabled=true,remove=true,path=journal,compressor=snappy),builtin_extension_config=(zstd=(compression_level=6)),file_manager=(close_idle_time=600,close_scan_interval=10,close_handle_minimum=2000),statistics_log=(wait=0),json_output=(error,message),verbose=[recovery_progress:1,checkpoint_progress:1,compact_progress:1,backup:0,checkpoint:0,compact:0,evict:0,history_store:0,recovery:0,rts:0,salvage:0,tiered:0,timestamp:0,transaction:0,verify:0,log:0],"}}
python-mongo-web-1 | INFO: Will watch for changes in these directories: ['/code/app']
python-mongo-web-1 | INFO: Uvicorn running on <http://0.0.0.0:8000> (Press CTRL+C to quit)
python-mongo-web-1 | INFO: Started reloader process [1] using statreload
python-mongo-web-1 | INFO: Started server process [8]
python-mongo-web-1 | INFO: Waiting for application startup.
python-mongo-web-1 | INFO: Application startup complete.
mongo | {"t":{"$date":"2024-03-17T07:53:15.936+00:00"},"s":"I", "c":"STORAGE", "id":4795906, "ctx":"initandlisten","msg":"WiredTiger opened","attr":{"durationMillis":951}}
mongo | {"t":{"$date":"2024-03-17T07:53:15.936+00:00"},"s":"I", "c":"RECOVERY", "id":23987, "ctx":"initandlisten","msg":"WiredTiger recoveryTimestamp","attr":{"recoveryTimestamp":{"$timestamp":{"t":0,"i":0}}}}
mongo | {"t":{"$date":"2024-03-17T07:53:15.942+00:00"},"s":"W", "c":"CONTROL", "id":22120, "ctx":"initandlisten","msg":"Access control is not enabled for the database. Read and write access to data and configuration is unrestricted","tags":["startupWarnings"]}
mongo | {"t":{"$date":"2024-03-17T07:53:15.943+00:00"},"s":"W", "c":"CONTROL", "id":5123300, "ctx":"initandlisten","msg":"vm.max_map_count is too low","attr":{"currentValue":262144,"recommendedMinimum":1677720,"maxConns":838860},"tags":["startupWarnings"]}
mongo | {"t":{"$date":"2024-03-17T07:53:15.945+00:00"},"s":"I", "c":"NETWORK", "id":4915702, "ctx":"initandlisten","msg":"Updated wire specification","attr":{"oldSpec":{"incomingExternalClient":{"minWireVersion":0,"maxWireVersion":21},"incomingInternalClient":{"minWireVersion":0,"maxWireVersion":21},"outgoing":{"minWireVersion":6,"maxWireVersion":21},"isInternalClient":true},"newSpec":{"incomingExternalClient":{"minWireVersion":0,"maxWireVersion":21},"incomingInternalClient":{"minWireVersion":21,"maxWireVersion":21},"outgoing":{"minWireVersion":21,"maxWireVersion":21},"isInternalClient":true}}}
mongo | {"t":{"$date":"2024-03-17T07:53:15.945+00:00"},"s":"I", "c":"REPL", "id":5853300, "ctx":"initandlisten","msg":"current featureCompatibilityVersion value","attr":{"featureCompatibilityVersion":"7.0","context":"startup"}}
mongo | {"t":{"$date":"2024-03-17T07:53:15.945+00:00"},"s":"I", "c":"STORAGE", "id":5071100, "ctx":"initandlisten","msg":"Clearing temp directory"}
mongo | {"t":{"$date":"2024-03-17T07:53:15.946+00:00"},"s":"I", "c":"CONTROL", "id":6608200, "ctx":"initandlisten","msg":"Initializing cluster server parameters from disk"}
mongo | {"t":{"$date":"2024-03-17T07:53:15.946+00:00"},"s":"I", "c":"CONTROL", "id":20536, "ctx":"initandlisten","msg":"Flow Control is enabled on this deployment"}
mongo | {"t":{"$date":"2024-03-17T07:53:15.947+00:00"},"s":"I", "c":"FTDC", "id":20625, "ctx":"initandlisten","msg":"Initializing full-time diagnostic data capture","attr":{"dataDirectory":"/data/db/diagnostic.data"}}
mongo | {"t":{"$date":"2024-03-17T07:53:15.949+00:00"},"s":"I", "c":"REPL", "id":6015317, "ctx":"initandlisten","msg":"Setting new configuration state","attr":{"newState":"ConfigReplicationDisabled","oldState":"ConfigPreStart"}}
mongo | {"t":{"$date":"2024-03-17T07:53:15.949+00:00"},"s":"I", "c":"STORAGE", "id":22262, "ctx":"initandlisten","msg":"Timestamp monitor starting"}
mongo | {"t":{"$date":"2024-03-17T07:53:15.951+00:00"},"s":"I", "c":"NETWORK", "id":23015, "ctx":"listener","msg":"Listening on","attr":{"address":"/tmp/mongodb-27017.sock"}}
mongo | {"t":{"$date":"2024-03-17T07:53:15.951+00:00"},"s":"I", "c":"NETWORK", "id":23015, "ctx":"listener","msg":"Listening on","attr":{"address":"0.0.0.0"}}
mongo | {"t":{"$date":"2024-03-17T07:53:15.951+00:00"},"s":"I", "c":"NETWORK", "id":23016, "ctx":"listener","msg":"Waiting for connections","attr":{"port":27017,"ssl":"off"}}
mongo | {"t":{"$date":"2024-03-17T07:53:15.951+00:00"},"s":"I", "c":"CONTROL", "id":8423403, "ctx":"initandlisten","msg":"mongod startup complete","attr":{"Summary of time elapsed":{"Startup from clean shutdown?":true,"Statistics":{"Transport layer setup":"0 ms","Run initial syncer crash recovery":"0 ms","Create storage engine lock file in the data directory":"0 ms","Get metadata describing storage engine":"0 ms","Validate options in metadata against current startup options":"0 ms","Create storage engine":"951 ms","Write current PID to file":"0 ms","Initialize FCV before rebuilding indexes":"2 ms","Drop abandoned idents and get back indexes that need to be rebuilt or builds that need to be restarted":"0 ms","Rebuild indexes for collections":"0 ms","Load cluster parameters from disk for a standalone":"0 ms","Build user and roles graph":"0 ms","Set up the background thread pool responsible for waiting for opTimes to be majority committed":"0 ms","Initialize information needed to make a mongod instance shard aware":"0 ms","Start up the replication coordinator":"1 ms","Start transport layer":"0 ms","_initAndListen total elapsed time":"969 ms"}}}}
mongo | {"t":{"$date":"2024-03-17T07:53:25.248+00:00"},"s":"I", "c":"NETWORK", "id":22943, "ctx":"listener","msg":"Connection accepted","attr":{"remote":"172.18.0.3:43728","uuid":{"uuid":{"$uuid":"d9da7bf8-5fd7-4663-9834-4e7e51ea0fce"}},"connectionId":1,"connectionCount":1}}
mongo | {"t":{"$date":"2024-03-17T07:53:25.251+00:00"},"s":"I", "c":"NETWORK", "id":51800, "ctx":"conn1","msg":"client metadata","attr":{"remote":"172.18.0.3:43728","client":"conn1","negotiatedCompressors":[],"doc":{"driver":{"name":"PyMongo","version":"4.6.2"},"os":{"type":"Linux","name":"Linux","architecture":"aarch64","version":"5.15.49-linuxkit-pr"},"platform":"CPython 3.9.18.final.0"}}}
mongo | {"t":{"$date":"2024-03-17T07:53:25.264+00:00"},"s":"I", "c":"NETWORK", "id":22943, "ctx":"listener","msg":"Connection accepted","attr":{"remote":"172.18.0.3:43742","uuid":{"uuid":{"$uuid":"812c9429-30d5-4e56-9c7c-cee9790633eb"}},"connectionId":2,"connectionCount":2}}
mongo | {"t":{"$date":"2024-03-17T07:53:25.265+00:00"},"s":"I", "c":"NETWORK", "id":51800, "ctx":"conn2","msg":"client metadata","attr":{"remote":"172.18.0.3:43742","client":"conn2","negotiatedCompressors":[],"doc":{"driver":{"name":"PyMongo","version":"4.6.2"},"os":{"type":"Linux","name":"Linux","architecture":"aarch64","version":"5.15.49-linuxkit-pr"},"platform":"CPython 3.9.18.final.0"}}}
無事立ち上げ成功!だけどMongoのログ長い。。。
実運用ではログレベル変更する設定を入れた方がよさそう。
https://www.mongodb.com/docs/manual/reference/log-messages/#configure-log-verbosity-levels
APIを叩く
postmanで各エンドポイントを叩いてみる。
↓
![https://storage.googleapis.com/zenn-user-upload/68dccd979a97-20240317.png](https://storage.googleapis.com/zenn-user-upload/68dccd979a97-20240317.png)
![https://storage.googleapis.com/zenn-user-upload/f802b6f158da-20240317.png](https://storage.googleapis.com/zenn-user-upload/f802b6f158da-20240317.png)
できた〜
とりあえず手元で動かせたので、次はMongo DBをAlibabaのをつかってみる。