SQL API
上一篇稍微看過了 Azure Cosmos DB 的簡單操作後,這一篇會來講解它的大致結構,可參考下圖:
https://ithelp.ithome.com.tw/upload/images/20181102/20112426pH8epMIjCX.png 每個 Azure 帳號可以創建多個 database,每個 database 可以包含多個 collections,在 collections 中包含多個 documents。而在 collection 中可以加入 stored procedures、triggers、User Defined Functions(UDFs) 等等。
插入資料到資料庫
接著我們使用程式插入一筆資料試試:
yarn add @azure/cosmos
const cosmos = require('@azure/cosmos');
const CosmosClient = cosmos.CosmosClient;
const endpoint = "填上 443 port 的 DB Endpoint";
const masterKey = "填上金鑰";
const client = new CosmosClient({ endpoint, auth: { masterKey } });
const databaseDefinition = { id: 'TestDB' };
const collectionDefinition = { id: 'Fruits' };
const documentDefinition = { name: 'Green Apple', category: 'Apple', data: Date.now() };
async function createFruit() {
const { body } = await client.database(databaseDefinition.id).container(collectionDefinition.id).items.create(documentDefinition);
console.log('Created item with content');
}
createFruit().catch(err => {
console.error(err);
});
點進去 Data explorer 的 Document 後可以看到剛才新增的資料如下:
document 結構
接著我們要來講一下每個欄位的意思:
_rid 由系統產生的唯一值,並且有順序性,例如上一筆插入的資料此欄位值為 `SvJDANLJWUiBhB4AAAAAAA==` 則下一筆會是 `SvJDANLJWUiChB4AAAAAAA==`
_etag 由系統產生, 用來優化 concurrency
_ts 由系統產生,當作最後一次更新的 timestamp
_self 由系統產生,代表資源的一個 URI,通常為此種格式 `/dbs/{dbName}/users/{userId}/permissions/{permissionId}`
id 可以由使用者自行設定,如果沒有設定系統會自動產生。
我們使用 Node.js SDK 時可以如下使用:
初始化連線:
const client = new CosmosClient({ endpoint: endpoint, auth: { masterKey: masterKey } });
創建資料庫:
const { database } = await client.databases.createIfNotExists({ id: databaseId });
建立 collection:
const { container } = await client.database(databaseId).containers.createIfNotExists({ id: containerId });
執行 SQL
const querySpec = {
query: "SELECT VALUE r.children FROM root r WHERE r.lastName = @lastName",
parameters: [
{
name: "@lastName",
value: "Andersen"
}
]
};
const { result: results } = await client.database(databaseId).container(containerId).items.query(querySpec).toArray();
for (var queryResult of results) {
let resultString = JSON.stringify(queryResult);
console.log(`\tQuery returned ${resultString}\n`);
}
Cassandra API
Cassandra DB 簡介
相信已經許多人先前已經搭配 Spark
使用過,不過因為本賽季後續會使用,所以還是簡介一下。Cassandra 本身是 2008 由 Facebook
開源的一個 NoSQL DB,轉眼間已經十年,與 IT 鐵人賽一樣。Cassandra 的資料是以 Key-Value
的方式儲存,資料模型與 Google BigTable
和 HBase
類似,但 Cassandra 在建立 cluster
中不會有 master
節點,每個節點都是平等的,這樣可以避免單一節點有問題時造成整個系統故障。
使用 Cassandra 一開始要先建立一個 KEYSPACE
,同時設定 replication 的方式。
CREATE KEYSPACE [IF NOT EXISTS] keyspace_name
WITH REPLICATION = {
'class' : 'SimpleStrategy', 'replication_factor' : N }
| 'class' : 'NetworkTopologyStrategy',
'dc1_name' : N [, ...]
}
[AND DURABLE_WRITES = true|false] ;
CAP
Azure Cosmos DB 的 Cassandra API
無痛轉移到 Azure Cosmos DB
的 Cassandra
,以後再也不用去監控 DB 機器的狀態,以及 CPU、 RAM 使用量突然飆高等問題,也不用管理一堆 yaml
等等的配置檔案以及煩惱配置跨地區 cluster
與設定網路等等,通通都交給 Azure Cosmos DB
幫你處理即可。throughput
與 latency
出問題時再也不用 Dear DevOps
然後 Dear SysOps
,只要於 portal
面板按個按鈕即可解決。
下一篇將介紹如何實際使用 Azure Cosmos DB 的 Cassandra API
。
這篇文章要來實際使用一下 Azure Cosmos DB
的 Cassandra API
。
set SSL_VERSION=TLSv1_2
set SSL_VALIDATE=false
cqlsh yichengcosmos.cassandra.cosmosdb.azure.com 10350 -u yichengcosmos -p <填上 PRIMARY PASSWORD> --ssl
使用官方範例
首先我們一樣先使用看看官方提供的範例:
git clone https://github.com/Azure-Samples/azure-cosmos-db-cassandra-nodejs-getting-started.git && cd azure-cosmos-db-cassandra-nodejs-getting-started && npm install
config.contactPoint
記得在後面加上 PORT 號
產生憑證
然後把他移動到專案目錄下,並把檔案副檔名改為 cer
。
mkdir ./cert && mv ~/Downloads/bc2025.crt ./cert/bc2025.cer
之後執行程式: node uprofile.js
。
這時各位可能會產生 Error: error:0906D06C:PEM routines:PEM_read_bio:no start line
的錯誤,然後十分困惑。
不過不要緊,我們不要用官方的,自己來產生一張 X509
證書即可:
openssl req -newkey rsa:2048 -new -nodes -keyout key.pem -out csr.pem
輸入後填上相關資訊,也可以都按 Enter
然後從 pem
轉為 crt
openssl x509 -req -days 365 -in csr.pem -signkey key.pem -out server.crt
最後再把 server.crt
改名字為 server.cer
即可
mv server.crt server.cer
之後執行範例程式:
這時會出現 { TypeError: Cannot read property 'type' of undefined
的錯誤,因為 Azure 目前的官方範例有點問題,在 batch
批量 Insert
的時候 params
多了一個參數。
這時把最後面的日期參數移除後再次執行:
沒想到又出現如下錯誤: { ResponseError: Logged batches are not supported by the service yet. Please use unlogged batches instead.
範例:
我們接著不使用官方範例,把 uprofile.js
直接改為以下,自己來操作看看。
創建 DB(Keyspace):
const cassandra = require('cassandra-driver');
const tls = require("tls");
const fs = require("fs");
const config = require("./config");
const ssl_option = {
cert: fs.readFileSync("./cert/server.cer"),
secureProtocol: "TLSv1_2_method"
};
const authProviderLocalCassandra =
new cassandra.auth.PlainTextAuthProvider(config.username, config.password);
const client = new cassandra.Client({
contactPoints: [config.contactPoint],
authProvider: authProviderLocalCassandra,
sslOptions:ssl_option
});
client.connect();
const query = "CREATE KEYSPACE IF NOT EXISTS Fruits WITH replication = {\'class\': \'NetworkTopologyStrategy\', \'datacenter\' : \'1\' }";
client.execute(query)
.then(result => {
console.log(result);
client.shutdown();
})
.catch(err => console.log(err));
創建 TABLE
const cassandra = require("cassandra-driver");
const tls = require("tls");
const fs = require("fs");
const config = require("./config");
const ssl_option = {
cert: fs.readFileSync("./cert/server.cer"),
secureProtocol: "TLSv1_2_method"
};
const authProviderLocalCassandra = new cassandra.auth.PlainTextAuthProvider(
config.username,
config.password
);
const client = new cassandra.Client({
contactPoints: [config.contactPoint],
authProvider: authProviderLocalCassandra,
sslOptions: ssl_option
});
client.connect()
.then(function () {
const query = "CREATE TABLE IF NOT EXISTS Fruits.banana " +
"(_id int PRIMARY KEY, price int, name text)";
return client.execute(query);
})
.catch(function (err) {
console.error('There was an error', err);
return client.shutdown();
});
插入資料與查詢資料:
const cassandra = require("cassandra-driver");
const tls = require("tls");
const fs = require("fs");
const config = require("./config");
const ssl_option = {
cert: fs.readFileSync("./cert/server.cer"),
secureProtocol: "TLSv1_2_method"
};
const authProviderLocalCassandra = new cassandra.auth.PlainTextAuthProvider(
config.username,
config.password
);
const client = new cassandra.Client({
contactPoints: [config.contactPoint],
authProvider: authProviderLocalCassandra,
sslOptions: ssl_option
});
client.connect()
.then(function () {
console.log('Inserting');
const query = 'INSERT INTO Fruits.banana (_id, price, name) VALUES (?, ?, ?)';
return client.execute(query, [1, 100, "Super banana"], { prepare: true});
})
.then(function () {
const query = 'SELECT price, name FROM Fruits.banana WHERE _id = ?';
return client.execute(query, [1], { prepare: true });
})
.then(function (result) {
const row = result.first();
console.log('Retrieved row: %j', row);
return client.shutdown();
})
.catch(function (err) {
console.error('There was an error', err);
return client.shutdown();
});
有時插入資料後按下 portal 頁面上的重新整理不會有反應,要把網頁重新整理一次才行。
那我們這篇介紹就到這邊為止,有興趣的朋友可以稍微玩一下。