Deno如何實現(xiàn)Mysql中間件

[toc]

Deno如何實現(xiàn)Mysql中間件

其他語言類似,換湯不換藥

首先講解一下mysql協(xié)議

想要編寫mysql中間件,必須需要對mysql協(xié)議有所了解的圆。mysql協(xié)議中間件。接下來會簡單講解一些基本協(xié)議半火,如果您想仔細(xì)了解越妈,請您移步官方文檔mysql protocol

mysql 協(xié)議了解

簡介

mysql采用C/S模式,服務(wù)器啟動后會監(jiān)聽本地端口钮糖∶仿樱客戶端請求到達時,會執(zhí)行三段握手以及mysql的權(quán)限認(rèn)證店归,驗證成功后會客服端會發(fā)送請求報文阎抒,服務(wù)端發(fā)送響應(yīng)報文進行交互

C->S
graph LR
Client-->Server

存在以下數(shù)據(jù)包

  • 登陸時的auth包
  • 執(zhí)行SQL的CMD包
S->C
graph LR
Server-->Client

存在以下數(shù)據(jù)包

  • 握手包
  • 數(shù)據(jù)包
  • 數(shù)據(jù)流結(jié)束包
  • 成功包(OK Packet)
  • 錯誤信息包

如何與MySql建立連接

所有客戶端鏈接都需要和經(jīng)過server認(rèn)證

驗證分為4個步驟

1、三次握手建立tcp連接

客服端撥號進行鏈接

    // 偽代碼
    public async connect(){
        this.conn = Deno.dail({
            hostname,
            port,
            transport:"tcp"
        })
    }

2消痛、建立mysql連接且叁,也就是認(rèn)證階段

認(rèn)證階段 Initial Handshake

  1. 服務(wù)器按照 Protocol::HandshakeV10協(xié)議發(fā)送給客服端
  2. 客戶端根據(jù)協(xié)議內(nèi)容進行內(nèi)容修改然后Protocol::HandshakeResponse提交服務(wù)端進行驗證

下面這個圖更直觀


Protocol::HandshakeV10 協(xié)議直觀圖

密碼驗證圖-盜用


image
// **** 驗證流程 ****
// 1、mysql.user中存儲的是兩次sha1加密過后的stage2hash 
// 2秩伞、服務(wù)端發(fā)送隨機字符串scramble到客服端并且mysqld利用stage2hash+scramble進行一次sha1操作逞带,生成key欺矫。
// 3、客戶端利用用戶輸入pwd生成stage2hash展氓,加上mysqld發(fā)送過來的scramble進行一次sha1操作穆趴,生成和mysqld相同的key。然后再拿這個key和stage1hash進行一次xor操作带饱,生成ciphertext毡代,發(fā)送給mysqld
// 4、mysqld拿到客戶端發(fā)送的ciphertext勺疼,加上之前生成的key教寂,進行一次xor逆向操作,解密出stage1hash执庐,再對stage1hash進行一次sha1操作酪耕,生成stage2hash爹梁,再拿著這個stage2hash和mysql.user表中存儲的信息對比识樱,如果一致,則此次密碼認(rèn)證通過揭绑。


export function authPwd(password:string,scramble:Unit8Array){
    // 客服發(fā)送驗證信息
    const hash = new Hash("sha1");
    const pwdDigestOnce = hash.digest(encode(password)).data;
    const pwdDigestTwice = hash.digest(pwd1).data;
    let scrambleAndPwdDigest = new Unit8Array(seed.length + pwdDigestTwice.length);
    scrambleAndPwdDigest.set(scramble);
    scrambleAndPwdDigest.set(pwdDigestTwice, scramble.length);
    scrambleAndPwdDigest = hash.digest(scrambleAndPwdDigest).data;
    const ciphertext = scrambleAndPwdDigest.map((byte, index) => {
        // key和stage1hash進行一次xor操作
        return byte ^ pwdDigestOnce[index];
    });

    return ciphertext;
}


  1. 服務(wù)端返回驗證結(jié)果

3递鹉、認(rèn)證通過之后盟步,客戶端開始于服務(wù)端進行交互,也就是命令執(zhí)行階段

    // receive = await this.packet(); 等待服務(wù)端驗證結(jié)果
    // 通過是OK packet Err packet 返回驗證結(jié)果
    if (header === 0xff) {
      const error = parseError(receive.body, this);
      log.error(`connect error(${error.code}): ${error.message}`);
      this.close();
      throw new Error(error.message);
    } 
    // 鏈接成功

4躏结、斷開mysql連接

客服端發(fā)出退出命令包
四次握手?jǐn)嚅_tcp連接 只需 this.conn.close()

如何維護一個連接池

// promise 經(jīng)典defer操作 
interface Defered<T>{
    promise:promise<T>;
    reslove:(c?:T)=>void;
    reject:(e?:any)=>void;
}

export function defer<T>():Defer<T>{
    let reject: (arg?: any) => void;
    let resolve: (arg?: any) => void;
    const promise = new Promise<T>((res, rej) => {
        resolve = res;
        reject = rej;
    });
    return {
        promise,
        reject,
        resolve
    };
}

const connection = await this.pool.getConnection(); 

async getConnection(): Promise<T> {
    // 如果存在可用已經(jīng)建立的conn直接取出來用
    if (this.availableConn.length) {
      return this.availableConn.pop();
    } else if (this._size < this.poolSize) {
    // 沒有可用conn如果創(chuàng)建新的conn直至最大
      this._size++;
      const item = await this.create();
      return item;
    }
    // 沒有可用conn却盘,且已經(jīng)達到最大鏈接數(shù)量 等待
    const d = defer<T>();
    this._queue.push(d);
    await d.promise;
    return this.availableConn.pop();
}

// 使用完畢歸還
async returnConnection(item: T) {
    this.availableConn.push(item);
    if (this._queue.length) {
      this._queue.shift().resolve();
    }
}

如何增刪改查 - part 2

避免篇幅較長,下次繼續(xù)講解媳拴。原理與建立連接不變黄橘,按照協(xié)議格式進行curd

總結(jié)

編寫mysql中間件的難點是 需要分析協(xié)議,按照協(xié)議進行無腦式編寫屈溉。
其中連程池的需要借助promise實現(xiàn)協(xié)程是一個難點塞关。

思考

mysql中間件目前利用js編寫,替換成rust編寫ffi是否能提高性能子巾。

感覺可以 【故作思考.jpg】

待我繼續(xù)學(xué)習(xí)學(xué)習(xí)rust
參考:
https://github.com/manyuanrong/deno_mysql
https://github.com/bartlomieju/deno-postgres
https://github.com/bartlomieju/deno-postgres

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末帆赢,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子线梗,更是在濱河造成了極大的恐慌椰于,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,807評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缠导,死亡現(xiàn)場離奇詭異,居然都是意外死亡溉痢,警方通過查閱死者的電腦和手機僻造,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評論 3 399
  • 文/潘曉璐 我一進店門憋他,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人髓削,你說我怎么就攤上這事竹挡。” “怎么了立膛?”我有些...
    開封第一講書人閱讀 169,589評論 0 363
  • 文/不壞的土叔 我叫張陵揪罕,是天一觀的道長。 經(jīng)常有香客問我宝泵,道長好啰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 60,188評論 1 300
  • 正文 為了忘掉前任儿奶,我火速辦了婚禮框往,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘闯捎。我一直安慰自己椰弊,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 69,185評論 6 398
  • 文/花漫 我一把揭開白布瓤鼻。 她就那樣靜靜地躺著秉版,像睡著了一般。 火紅的嫁衣襯著肌膚如雪茬祷。 梳的紋絲不亂的頭發(fā)上清焕,一...
    開封第一講書人閱讀 52,785評論 1 314
  • 那天,我揣著相機與錄音牲迫,去河邊找鬼耐朴。 笑死,一個胖子當(dāng)著我的面吹牛盹憎,可吹牛的內(nèi)容都是我干的筛峭。 我是一名探鬼主播,決...
    沈念sama閱讀 41,220評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼陪每,長吁一口氣:“原來是場噩夢啊……” “哼影晓!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起檩禾,我...
    開封第一講書人閱讀 40,167評論 0 277
  • 序言:老撾萬榮一對情侶失蹤挂签,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后盼产,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體饵婆,經(jīng)...
    沈念sama閱讀 46,698評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,767評論 3 343
  • 正文 我和宋清朗相戀三年戏售,在試婚紗的時候發(fā)現(xiàn)自己被綠了侨核。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片草穆。...
    茶點故事閱讀 40,912評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖搓译,靈堂內(nèi)的尸體忽然破棺而出悲柱,到底是詐尸還是另有隱情,我是刑警寧澤些己,帶...
    沈念sama閱讀 36,572評論 5 351
  • 正文 年R本政府宣布豌鸡,位于F島的核電站,受9級特大地震影響段标,放射性物質(zhì)發(fā)生泄漏涯冠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,254評論 3 336
  • 文/蒙蒙 一怀樟、第九天 我趴在偏房一處隱蔽的房頂上張望功偿。 院中可真熱鬧,春花似錦往堡、人聲如沸械荷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吨瞎。三九已至,卻和暖如春穆咐,著一層夾襖步出監(jiān)牢的瞬間颤诀,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評論 1 274
  • 我被黑心中介騙來泰國打工对湃, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留崖叫,地道東北人。 一個月前我還...
    沈念sama閱讀 49,359評論 3 379
  • 正文 我出身青樓拍柒,卻偏偏與公主長得像心傀,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子拆讯,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,922評論 2 361

推薦閱讀更多精彩內(nèi)容

  • 簡介 用簡單的話來定義tcpdump脂男,就是:dump the traffic on a network,根據(jù)使用者...
    JasonShi6306421閱讀 1,245評論 0 1
  • 簡介 用簡單的話來定義tcpdump种呐,就是:dump the traffic on a network宰翅,根據(jù)使用者...
    保川閱讀 5,963評論 1 13
  • MySQL讀取客戶端文件漏洞分析并使用Golang編寫簡易蜜罐 一、 原理概述 這并不是一個新鮮的漏洞爽室,我也是為了...
    孤城浪子55555閱讀 1,099評論 0 2
  • feisky云計算汁讼、虛擬化與Linux技術(shù)筆記posts - 1014, comments - 298, trac...
    不排版閱讀 3,867評論 0 5
  • 在你想念家人的時候,家人也在想念你,應(yīng)該是一種幸福吧嘿架。 因為工作卜录,因為生活,因為想要證明自己眶明,我...
    瑾灝閱讀 281評論 0 7