前言
函數計算發佈了新的觸發器-- RDS 觸發器,這標誌着函數計算的事件源新增加了一名成員 -- 阿里雲關係型數據庫( Relational Database Service,簡稱 RDS), 根據官方文檔的示例,只有 eventFormat 爲 json 的示例,本文作爲補充, 講解 eventFormat 爲 protobuf 時的代碼示例。
protobuf 格式
syntax = "proto3";
package protocol;
enum DBType {
MySQL = 0;
Redis = 1;
Mongo = 2;
HBase = 3;
}
message Message {
//消費該message後可以ack的offset.考慮進行編碼.
int64 offset = 1;
//該message後可以ack的record對應的timestamp
int64 timestamp = 2;
//留作備用:以後傳送大的數據行可以拿來使用.
int32 spare_flag = 3;
int32 spare_seq = 4;
//message的version
int32 version = 5;
//數據源
DBType db_type = 6;
//數據行
repeated Entry entries = 7;
}
//操作
enum OpType {
UNKOWN_TYPE = 0;
BEGIN = 1;
COMMIT = 2;
//不在下列DDL操作用的query
QUERY = 3;
INSERT = 4;
UPDATE = 5;
DELETE = 6;
CREATE = 7;
ALTER = 8;
DROP = 9;
TRUNCATE = 10;
RENAME = 11;
//CREATE INDEX
CINDEX = 12;
//DROP INDEX
DINDEX = 13;
OPTIMIZE = 14;
XA = 15;
}
message Entry {
OpType operation = 1;
//時間戳,單位s
int64 timestamp = 2;
//Transaction id
string id = 3;
//一個事務中的第幾行
int64 sequence = 4;
//DML操作的db_name,DDL操作時候session的默認db
string db_name = 5;
//DML操作的table_name
string table_name = 6;
//after image,操作的後鏡像.
repeated Field row = 7;
//before image,操作的前鏡像
repeated Field before_row = 8;
//非DML語句的sql
string query = 9;
}
message Field {
//column name
string name = 1;
//字符集
string charset = 3;
//第幾列
int32 idx = 2;
//對應java中的type
int32 type_num = 4;
//對於mysql,mysql中的type num;
int32 org_type = 5;
//在db中原始type的name
string org_type_name = 6;
//預留的flag
int32 flag = 7;
//是否爲NULL
bool is_null = 8;
//是否是pk
bool is_pk = 9;
//是否是unsigned value
bool is_unsigned = 10;
//是否是timestamp value(timestamp展示值和時區相關,這裏記錄標準時區的值)
bool is_timestamp = 11;
//value的值都用bytes表示,消費端需要先用charset結合bytes生成對應string.然後再轉換爲type_num對應的type value.
//同時當charset爲空,即表示原數據類型就是binary類型
bytes value = 12;
}
代碼示例
完整的代碼示例請下載本文最後的附件, 包含 3種runtime( python, php, nodejs)的使用案例, 下面展示各自使用的代碼簡短示例。
java runtime 示例請參考:Redis緩存淘汰
python
# -*- coding: utf-8 -*-
from proto import rdsEvent_pb2
bin_data = b""
# local data only for test
with open('./proto.bin', 'rb') as f:
bin_data = f.read()
def handler(event, context):
target = rdsEvent_pb2.Message()
target.ParseFromString(event)
#target.ParseFromString(bin_data)
print(target.offset, target.db_type)
entry = target.entries[0]
print(entry.operation, entry.db_name, entry.table_name)
print(entry.row[0].name, entry.row[1].value, entry.row[2].type_num)
return "OK"
nodejs
'use strict';
var fs = require("fs");
var protobuf = require("protobufjs");
module.exports.handler = function(event, context, callback) {
protobuf.load("rdsEvent.proto", function(err, root) {
if (err)
throw err;
var rdsEventMessage = root.lookupType("proto.Message");
// local data only for test
//var event = fs.readFileSync('proto.bin');
var message = rdsEventMessage.decode(event);
console.log(JSON.stringify(message))
callback(null, 'hello world');
});
};
php
<?php
require_once __DIR__ . '/Proto/Field.php';
require_once __DIR__ . '/Proto/DBType.php';
require_once __DIR__ . '/Proto/OpType.php';
require_once __DIR__ . '/Proto/Entry.php';
require_once __DIR__ . '/Proto/Message.php';
require_once __DIR__ . '/GPBMetadata/RdsEvent.php';
// local data only for test
$filename = __DIR__ . "/proto.bin";
$handle = fopen($filename, "rb");
$data = fread($handle, filesize($filename));
fclose($handle);
function handler($event, $context) {
$res = new \Proto\Message();
//$res->mergeFromString($data);
$res->mergeFromString($event);
echo $res->getDbType() . PHP_EOL;
echo $res->getOffset() . PHP_EOL;
echo $res->getEntries()[0]->getTableName() . PHP_EOL;
return "ok";
}