在資料科學專案中,資料儲存的佈署與管理至關重要。Docker 提供了輕量級的虛擬化方案,有效簡化資料函式庫的佈署流程。本文將著重於如何使用 Docker 佈署 Redis、MongoDB 和 PostgreSQL 等主流資料函式庫,並探討資料持久化的最佳實務,確保資料在容器生命週期後依然完整。此外,文章也將介紹序列化技術如 JSON、YAML 和 pickle,說明如何在 Python 環境下有效地儲存和交換資料。
資料儲存系統的 Docker 應用實踐
在資料科學的領域中,如何有效地管理和使用資料儲存系統是一個重要的課題。本章將探討如何利用 Docker 來簡化開放原始碼資料儲存技術的佈署與管理,並且介紹三種主要的資料儲存技術:Redis、MongoDB 和 PostgreSQL。
序列化技術在資料科學中的應用
在資料科學的工作流程中,資料結構和物件狀態的儲存、傳輸和重建是一個核心任務,這個過程被稱為序列化。序列化是一個已經被充分解決的問題,資料科學家有多種工具可以選擇來完成這項任務。本章將重點介紹序列化技術,特別是在將記憶體中的物件轉換為二進製表示以及使用流行的 JSON 格式進行序列化方面的應用。
序列化格式與方法
本文著重於 Python 環境下的工作,因此將重點介紹兩種 Python 特有的序列化方法:pickle 和透過位元組序列化。此外,還將探討兩種根據文字的序列化方法:JSON 和 YAML。
- JSON (JavaScript Object Notation):是一種機器可讀的 JavaScript 程式語言子集,已被程式設計社群廣泛採用為人類可讀、語言無關的序列化方法。
- YAML (YAML Ain’t Markup Language):是另一種解決相同問題的方案。JSON 和 YAML 都能夠使用標準的基本資料型別:整數、浮點數、布林值和空值,以及字串。對於更大的結構,它們都使用關聯陣列(字典)和有序列表(陣列、向量、列表或序列)。
以下是 JSON 和 YAML 的範例:
JSON 範例
{
"this_json": "is a JSON object",
"a_nested_object": {
"obj_id": 123,
"object_value": "temperamental",
"is_nested": true
},
"a_list": [1, 2, 3, 4],
"a_list_of_strings": ["green eggs", "ham"],
"last_used": null
}
YAML 範例
this_yaml: is a YAML object
a_nested_object:
obj_id: 123
object_value: temperamental
is_nested: true
a_list:
- 1
- 2
- 3
- 4
a_list_of_strings:
- green eggs
- ham
last_used: null
Python 中的二進位制編碼
Python 的 pickle 模組是將 Python 物件和資料序列化為二進位制位元組串流的首選方法。與 JSON 或 YAML 相比,pickle 有幾個根本的不同之處。JSON 和 YAML 是人類可讀的,而轉換為位元組串流的物件則不是。JSON 和 YAML 序列化的物件可以被任何語言的程式讀取,而 pickle 物件只能在 Python 中讀取。由於 pickle 物件不需要考慮互操作性,因此可以 pickle 的 Python 物件範圍很廣,而使用 JSON 或 YAML 只能序列化字典。
使用 Pickle 的範例
import pickle
# 定義一個物件
data = {
'foo': 'bar',
'numbers': [1, 2, 3]
}
# 將物件序列化為位元組串流
serialized_data = pickle.dumps(data)
print(serialized_data)
# 將位元組串流反序列化為物件
deserialized_data = pickle.loads(serialized_data)
print(deserialized_data)
Redis 資料儲存技術
Redis 是一種開放原始碼的記憶體資料結構儲存系統,用於儲存與鍵相關聯的不同型別的資料值。在我們的技術堆積疊中,Redis 將用於兩個主要目的:首先,它將作為快取,用於持久化物件超出 Python 程式的生命週期或在 Jupyter Notebook 之間;其次,我們將使用 Redis 作為訊息代理,以便使用名為 rq 的 Python 程式函式庫從筆記本執行延遲作業處理。
提取 Redis 映象
可以使用 docker pull 命令從 Docker Hub 提取 Redis 映象,如下所示:
$ docker pull redis
執行 Redis 容器
提取映象後,可以使用以下命令執行 Redis 容器:
$ docker run -d redis
驗證 Redis 伺服器
可以透過 redis-cli 命令向 Redis 伺服器傳送 PING 命令來驗證其功能:
$ docker exec <container_id> redis-cli ping
PONG
如果 Redis 伺服器正確回應 PONG,則表示一切正常。
結束並移除 Redis 容器
完成驗證後,可以停止並移除 Redis 容器:
$ docker stop <container_id>
$ docker rm <container_id>
Docker 資料持久化與 Redis 服務佈署
在 Docker 環境中執行資料函式庫服務時,將其視為由 Docker 管理的服務(或微服務)至關重要。容器本質上應為短暫的,能夠隨時啟動、停止和丟棄。若將資料儲存在容器內,每次容器重啟都會導致資料遺失。因此,資料持久化是確保資料在容器生命週期外依然存在的關鍵。
Docker 資料卷(Data Volumes)
Docker 資料卷是一種專門設計用於持久化資料的容器。透過將資料卷掛載到容器上,可以確保資料在容器刪除或重啟後仍然存在。這使得資料捲成為管理有狀態服務(如資料函式庫)的理想選擇。
建立與檢視資料卷
首先,建立一個新的資料卷,用於儲存 Redis 資料。
$ docker volume create --name redis-dbstore
redis-dbstore
使用 docker volume ls 命令可以檢視目前所有的資料卷。
$ docker volume ls
DRIVER VOLUME NAME
local redis-dbstore
啟動 Redis 服務並掛載資料卷
將建立的資料卷掛載到 Redis 容器,並以分離模式執行。
$ docker run -d --name this_redis -v redis-dbstore:/data redis
b216a67caedc934b09341cf1642e89079be09d52b607ce4ddecdeaae5b5ae704
驗證資料持久化
透過 redis-cli 在 Redis 容器中建立一個計數器,並驗證資料是否持久化。
$ docker exec this_redis redis-cli incr mycounter
1
$ docker exec this_redis redis-cli incr mycounter
2
$ docker exec this_redis redis-cli incr mycounter
3
停止並刪除容器後,再次啟動新的 Redis 容器,並掛載相同的資料卷。
$ docker stop this_redis && docker rm this_redis
this_redis
this_redis
$ docker run -d --name this_redis -v redis-dbstore:/data redis
12fe7cea2e63aa2055585fd97b6b9205774a59bbf716672f71e5d75858c7cd72
$ docker exec this_redis redis-cli incr mycounter
4
結果顯示計數器值為 4,證明資料已成功持久化。
連線容器
在同一主機上執行多個容器時,可以使用 --link 標誌來連線它們。雖然 --link 已被棄用,但仍可用於簡單的容器連線。
啟動一個新的 Jupyter 容器,並連結到正在執行的 Redis 容器。
$ docker run -d -v `pwd`:/home/jovyan --link this_redis jupyter/scipy-notebook
d6f09196bf85861df23eeb2f11bd68396287464d00febe27cda93024a3666251
進入 Jupyter 容器並檢查環境變數。
$ docker exec -it d6f0 bash
jovyan@d6f09196bf85:~$ env | grep THIS_REDIS
THIS_REDIS_PORT_6379_TCP=tcp://172.17.0.2:6379
THIS_REDIS_NAME=/determined_wilson/this_redis
THIS_REDIS_PORT=tcp://172.17.0.2:6379
THIS_REDIS_PORT_6379_TCP_PORT=6379
THIS_REDIS_ENV_REDIS_VERSION=3.2.8
THIS_REDIS_PORT_6379_TCP_PROTO=tcp
THIS_REDIS_ENV_GOSU_VERSION=1.7
THIS_REDIS_ENV_REDIS_DOWNLOAD_SHA1=6780d1abb66f33a97aad0ebbe020403d0a15b67f
THIS_REDIS_ENV_REDIS_DOWNLOAD_URL=http://download.redis.io/releases/redis-3.2.8.tar.gz
THIS_REDIS_PORT_6379_TCP_ADDR=172.17.0.2
使用環境變數中的 IP 位址對 Redis 容器進行 ping 測試。
jovyan@d6f09196bf85:~$ ping -c 4 $THIS_REDIS_PORT_6379_TCP_ADDR
PING 172.17.0.2 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: icmp_seq=0 ttl=64 time=0.470 ms
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.136 ms
64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.120 ms
64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.085 ms
---
172.17.0.2 ping statistics
---
4 packets transmitted, 4 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.085/0.203/0.470/0.155 ms
在 Jupyter 中使用 Redis
預設的 jupyter/scipy-notebook 映像檔不包含 Redis Python 程式函式庫。可以在執行中的容器中臨時安裝 Redis 程式函式庫,以便在 Jupyter Notebook 中使用 Redis。
# 在 Jupyter 容器中安裝 redis 程式函式庫(這裡省略具體安裝步驟,通常使用 pip 安裝)
# pip install redis
# 在 Jupyter Notebook 中連線 Redis 伺服器範例程式碼:
import redis
# 使用環境變數連線 Redis
redis_client = redis.Redis(host=os.environ['THIS_REDIS_PORT_6379_TCP_ADDR'], port=6379, db=0)
# 設定和取得一個值
redis_client.set('key', 'value')
print(redis_client.get('key'))
圖表翻譯:
此圖示展示了Redis作為持久化服務被Docker管理的過程。Docker透過資料卷實作了Redis資料的持久化,使得Redis服務能夠在容器重啟或刪除後仍然保留資料。
隨著容器技術的不斷發展,未來將會有更多高效、便捷的方式來管理和協調多容器應用。例如,Docker Compose 和 Kubernetes 等工具已經成為業界標準,用於簡化多容器應用的佈署和管理。未來,我們可以期待更多創新技術的出現,以進一步簡化容器的使用和管理。
程式碼最佳化與安全性考量
在實際應用中,應考慮對程式碼進行最佳化,以提高效能和安全性。例如,可以使用更高效的連線池管理 Redis 連線,或是對敏感資料進行加密處理。此外,還應定期更新和修補所使用的映像檔和程式函式庫,以防止潛在的安全漏洞。
程式碼範例:使用連線池管理 Redis 連線
import redis
# 建立 Redis 連線池
pool = redis.ConnectionPool(host=os.environ['THIS_REDIS_PORT_6379_TCP_ADDR'], port=6379, db=0)
# 使用連線池建立 Redis 客戶端
redis_client = redis.Redis(connection_pool=pool)
# 設定和取得一個值
redis_client.set('key', 'value')
print(redis_client.get('key'))
Redis 連線池架構圖
@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333
title Redis 連線池架構圖
rectangle "請求" as node1
rectangle "分配連線" as node2
rectangle "處理請求" as node3
rectangle "傳回結果" as node4
node1 --> node2
node2 --> node3
node3 --> node4
@enduml圖表翻譯: 此圖示展示了應用程式如何透過 Redis 連線池與 Redis 伺服器進行互動。連線池負責管理與 Redis 的連線,從而提高應用的效能和可擴充套件性。