一区二区三区三上|欧美在线视频五区|国产午夜无码在线观看视频|亚洲国产裸体网站|无码成年人影视|亚洲AV亚洲AV|成人开心激情五月|欧美性爱内射视频|超碰人人干人人上|一区二区无码三区亚洲人区久久精品

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

文盤Rust--r2d2實(shí)現(xiàn)redis連接池

jf_wN0SrCdH ? 來源:京東云開發(fā)者 ? 作者:賈世聞 ? 2022-12-12 10:32 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

我們?cè)陂_發(fā)應(yīng)用后端系統(tǒng)的時(shí)候經(jīng)常要和各種數(shù)據(jù)庫、緩存等資源打交道。這一期,我們聊聊如何訪問redis 并將資源池化。

在一個(gè)應(yīng)用后端程序訪問redis主要要做的工作有兩個(gè),單例和池化。

在后端應(yīng)用集成redis,我們主要用到以下幾個(gè)crate:[once_cell](https://github.com/matklad/once_cell)、[redis-rs](https://github.com/redis-rs/redis-rs)、[r2d2](https://github.com/sfackler/r2d2).once_cell 實(shí)現(xiàn)單例;redis-rs 是 redis的 rust 驅(qū)動(dòng);r2d2 是一個(gè)池化連接的工具包。本期代碼均出現(xiàn)在[fullstack-rs](https://github.com/jiashiwen/fullstack-rs)項(xiàng)目中。[fullstack-rs](https://github.com/jiashiwen/fullstack-rs)是我新開的一個(gè)實(shí)驗(yàn)性項(xiàng)目,目標(biāo)是做一個(gè)類似[gin-vue-admin](https://github.com/flipped-aurora/gin-vue-admin)的集成開發(fā)框架。

redis資源的定義主要是在https://github.com/jiashiwen/fullstack-rs/blob/main/backend/src/resources/redis_resource.rs 中實(shí)現(xiàn)的。

一、redis-rs 封裝

在實(shí)際開發(fā)中,我們面對(duì)的redis資源可能是單實(shí)例也有可能是集群,在這里我們對(duì)redis-rs進(jìn)行了簡(jiǎn)單封裝,便于適應(yīng)這兩種情況。

```rust
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, Clone)]
#[serde(rename_all = "lowercase")]
pub struct RedisInstance {
    #[serde(default = "RedisInstance::urls_default")]
    pub urls: Vec,
    #[serde(default = "RedisInstance::password_default")]
    pub password: String,
    #[serde(default = "RedisInstance::instance_type_default")]
    pub instance_type: InstanceType,
}
```
RedisInstance,定義redis資源的描述,與配置文件相對(duì)應(yīng)。詳細(xì)的配置描述可以參考 https://github.com/jiashiwen/fullstack-rs/blob/main/backend/src/configure/config_global.rs 文件中 RedisConfig 和 RedisPool 兩個(gè) struct 描述。
```rust
#[derive(Clone)]
pub enum RedisClient {
    Single(redis::Client),
    Cluster(redis::ClusterClient),
}




impl RedisClient {
    pub fn get_redis_connection(&self) -> RedisResult {
        return match self {
            RedisClient::Single(s) => {
                let conn = s.get_connection()?;
                Ok(RedisConnection::new(conn)))
            }
            RedisClient::Cluster(c) => {
                let conn = c.get_connection()?;
                Ok(RedisConnection::new(conn)))
            }
        };
    }
}




pub enum RedisConnection {
    Single(Box),
    Cluster(Box),
}




impl RedisConnection {
    pub fn is_open(&self) -> bool {
        return match self {
            RedisConnection::Single(sc) => sc.is_open(),
            RedisConnection::Cluster(cc) => cc.is_open(),
        };
    }




    pub fn query(&mut self, cmd: &redis::Cmd) -> RedisResult {
        return match self {
            RedisConnection::Single(sc) => match sc.as_mut().req_command(cmd) {
                Ok(val) => from_redis_value(&val),
                Err(e) => Err(e),
            },
            RedisConnection::Cluster(cc) => match cc.req_command(cmd) {
                Ok(val) => from_redis_value(&val),
                Err(e) => Err(e),
            },
        };
    }
}
```

RedisClient 和 RedisConnection 對(duì)redis 的鏈接進(jìn)行了封裝,用來實(shí)現(xiàn)統(tǒng)一的調(diào)用接口。

二、基于 r2d2 實(shí)現(xiàn) redis 連接池

以上,基本完成的reids資源的準(zhǔn)備工作,下面來實(shí)現(xiàn)一個(gè)redis鏈接池。

```rust
#[derive(Clone)]
pub struct RedisConnectionManager {
    pub redis_client: RedisClient,
}




impl r2d2::ManageConnection for RedisConnectionManager {
    type Connection = RedisConnection;
    type Error = RedisError;




    fn connect(&self) -> Result {
        let conn = self.redis_client.get_redis_connection()?;
        Ok(conn)
    }




    fn is_valid(&self, conn: &mut RedisConnection) -> Result<(), Self::Error> {
        match conn {
            RedisConnection::Single(sc) => {
                redis::cmd("PING").query(sc)?;
            }
            RedisConnection::Cluster(cc) => {
                redis::cmd("PING").query(cc)?;
            }
        }
        Ok(())
    }




    fn has_broken(&self, conn: &mut RedisConnection) -> bool {
        !conn.is_open()
    }
}
```
利用 r2d2 來實(shí)現(xiàn)連接池需要實(shí)現(xiàn) r2d2::ManageConnection trait。connect 函數(shù)獲取連接;is_valid 函數(shù)校驗(yàn)連通性;has_broken 判斷連接是否崩潰不可用。
```Rust
pub fn gen_redis_conn_pool() -> Result> {
    let config = get_config()?;
    let redis_client = config.redis.instance.to_redis_client()?;
    let manager = RedisConnectionManager { redis_client };
    let pool = r2d2::Pool::builder()
        .max_size(config.redis.pool.max_size as u32)
        .min_idle(Some(config.redis.pool.mini_idle as u32))
        .connection_timeout(Duration::from_secs(
            config.redis.pool.connection_timeout as u64,
        ))
        .build(manager)?;
    Ok(pool)
}
```

gen_redis_conn_pool 函數(shù)用來生成一個(gè) redis 的連接池,根據(jù)配置文件來指定連接池的最大連接數(shù),最小閑置連接以及連接超時(shí)時(shí)長(zhǎng)。

三、連接池單例實(shí)現(xiàn)

在后端開發(fā)中,對(duì)于單一資源一般采取單例模式避免重復(fù)產(chǎn)生實(shí)例的開銷。下面來聊一聊如果構(gòu)建一個(gè)全局的 redis 資源。

這一部分代碼在https://github.com/jiashiwen/fullstack-rs/blob/main/backend/src/resources/init_resources.rs 文件中。

```rust
pub static GLOBAL_REDIS_POOL: OnceCell> = OnceCell::new();
```

利用 OnceCell 構(gòu)建全局靜態(tài)變量。

```rust
fn init_global_redis() {
    GLOBAL_REDIS_POOL.get_or_init(|| {
        let pool = match gen_redis_conn_pool() {
            Ok(it) => it,
            Err(err) => panic!("{}", err.to_string()),
        };
        pool
    });
}
```

init_global_redis 函數(shù),用來初始化 GLOBAL_REDIS_POOL 全局靜態(tài)變量。在一般的后端程序中,資源是強(qiáng)依賴,所以,初始化簡(jiǎn)單粗暴,要么成功要么 panic。

四、資源調(diào)用

準(zhǔn)備好 redis 資源后,我們聊聊如何調(diào)用。

調(diào)用例子在這里https://github.com/jiashiwen/fullstack-rs/blob/main/backend/src/httpserver/service/service_redis.rs

```rust
pub fn put(kv: KV) -> Result<()> {
    let conn = GLOBAL_REDIS_POOL.get();
    return match conn {
        Some(c) => {
            c.get()?
                .query(redis::cmd("set").arg(kv.Key).arg(kv.Value))?;
            Ok(())
        }
        None => Err(anyhow!("redis pool not init")),
    };
}
```

https://github.com/jiashiwen/fullstack-rs/tree/main/backend 這個(gè)工程里有從http入口開始到寫入redis的完整流程,http server 不在本文討論之列,就不贅述了,有興趣的同學(xué)可以去github看看。

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 數(shù)據(jù)庫
    +關(guān)注

    關(guān)注

    7

    文章

    3926

    瀏覽量

    66211
  • 資源
    +關(guān)注

    關(guān)注

    0

    文章

    59

    瀏覽量

    18172
  • Redis
    +關(guān)注

    關(guān)注

    0

    文章

    387

    瀏覽量

    11444
  • Rust
    +關(guān)注

    關(guān)注

    1

    文章

    234

    瀏覽量

    7096

原文標(biāo)題:文盤Rust -- r2d2 實(shí)現(xiàn)redis連接池

文章出處:【微信號(hào):Rust語言中文社區(qū),微信公眾號(hào):Rust語言中文社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    如何使用Rust連接Redis

    Redis是一款快速、開源、鍵值存儲(chǔ)數(shù)據(jù)庫,被廣泛應(yīng)用于緩存、發(fā)布/訂閱系統(tǒng)、定時(shí)任務(wù)等場(chǎng)景中。Rust提供了很多Redis的客戶端庫,本教程將會(huì)介紹如何使用Rust
    的頭像 發(fā)表于 09-19 16:22 ?2938次閱讀

    淺析c3p0連接池

    【JavaWeb】c3p0連接池與MySQL
    發(fā)表于 09-11 11:37

    關(guān)于數(shù)據(jù)庫連接池總結(jié)

    數(shù)據(jù)庫連接池小結(jié)
    發(fā)表于 04-30 08:07

    數(shù)據(jù)庫連接池C3p0的使用方法

    數(shù)據(jù)庫連接池C3p0的使用
    發(fā)表于 06-04 17:31

    java原生程序redis連接怎么選擇

    java原生程序redis連接連接池長(zhǎng)連接和短連接)選擇問題
    發(fā)表于 06-10 16:33

    什么是數(shù)據(jù)庫連接池

    什么是數(shù)據(jù)庫連接池       數(shù)據(jù)庫連接是一種關(guān)鍵的有限的昂貴的資源,這一點(diǎn)在多用戶的網(wǎng)頁應(yīng)用程序中體現(xiàn)得尤
    發(fā)表于 06-17 07:42 ?1318次閱讀

    c3p0-0.9.1.2 c3p0連接池jar包

    c3p0連接池jar包.......................................
    發(fā)表于 02-25 11:54 ?0次下載

    關(guān)于 Redis連接池解析

    一、關(guān)于連接池 一個(gè)數(shù)據(jù)庫服務(wù)器只擁有有限的資源,并且如果你沒有充分使用這些資源,你可以通過使用更多的連接來提高吞吐量。一旦所有的資源都在使用,那么你就不能通過增加更多的連接來提高吞吐量。事實(shí)上
    發(fā)表于 10-12 16:02 ?0次下載

    連接池工作原理

    連接池技術(shù)的核心思想是連接復(fù)用,通過建立一個(gè)數(shù)據(jù)庫連接池以及一套連接使用、分配和管理策略,使得該連接池中的
    的頭像 發(fā)表于 03-22 16:16 ?8006次閱讀

    數(shù)據(jù)庫連接池的優(yōu)點(diǎn)

    本視頻主要詳細(xì)介紹了數(shù)據(jù)庫連接池的優(yōu)點(diǎn),分別是資源重用、更快的系統(tǒng)響應(yīng)速度、統(tǒng)一的連接管理,避免數(shù)據(jù)庫連接泄漏、新的資源分配手段。
    的頭像 發(fā)表于 03-22 16:24 ?1.1w次閱讀

    數(shù)據(jù)庫連接池的設(shè)置怎么確定大小

    數(shù)據(jù)庫連接池的配置是開發(fā)者們常常搞出坑的地方,在配置數(shù)據(jù)庫連接池時(shí),有幾個(gè)可以說是和直覺背道而馳的原則需要明確。
    的頭像 發(fā)表于 05-04 14:23 ?3056次閱讀
    數(shù)據(jù)庫<b class='flag-5'>連接池</b>的設(shè)置怎么確定大小

    Rust語言中r2d2基礎(chǔ)用法

    r2d2Rust語言的一個(gè)連接池模塊,可以用于管理和復(fù)用數(shù)據(jù)庫連接。它可以與多種數(shù)據(jù)庫進(jìn)行交互,包括MySQL、PostgreSQL、SQLite等等。使用
    的頭像 發(fā)表于 09-19 16:25 ?3847次閱讀

    了解連接池、線程、內(nèi)存、異步請(qǐng)求

    可被重復(fù)使用像常見的線程、內(nèi)存、連接池、對(duì)象都具有以上的共同特點(diǎn)。 連接池 什么是數(shù)據(jù)庫連接池
    的頭像 發(fā)表于 11-09 14:44 ?1838次閱讀
    了解<b class='flag-5'>連接池</b>、線程<b class='flag-5'>池</b>、內(nèi)存<b class='flag-5'>池</b>、異步請(qǐng)求<b class='flag-5'>池</b>

    MySQL與Redis數(shù)據(jù)庫連接池應(yīng)用

    一、概念 數(shù)據(jù)庫連接池(Connection pooling)是程序啟動(dòng)時(shí)建立足夠的數(shù)據(jù)庫連接,并將這些連接組成一個(gè)連接池,由程序動(dòng)態(tài)地對(duì)池中的連接
    的頭像 發(fā)表于 11-10 16:40 ?809次閱讀
    MySQL與<b class='flag-5'>Redis</b>數(shù)據(jù)庫<b class='flag-5'>連接池</b>應(yīng)用

    Java redis鎖怎么實(shí)現(xiàn)

    在Java中實(shí)現(xiàn)Redis鎖涉及到以下幾個(gè)方面:Redis的安裝配置、Redis連接池的使用、Redis
    的頭像 發(fā)表于 12-04 10:47 ?1477次閱讀