用Rust实现一个简单的KV Server: day5

332 阅读2分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第14天,点击查看活动详情

在上篇文章中,现在我们来实现服务器端的事件通知机制和优雅关机。现在我们来实现并发连接限制和测量监控。

并发连接限制

服务器端使用tokioSemaphore限制并发连接的最大数量。一旦达到限制数,服务器将停止接受新的连接,直到现有连接终止。

我们先在conf/server.json中加入连接数配置:

{
  "listen_address": {
    "address": "127.0.0.1:3000"
  },
  "sled_path": {
    "path": "tmp/kvserver"
  },
  "connects":{
    "max_conns":500
  },
}

修改src/config.rs,新增连接数配置:

//server端配置
#[derive(Debug, Serialize, Deserialize)]
pub struct ServerConfig {
    pub listen_address: ListenerAddress,
    pub sled_path: SledDbPath,
    pub connects: Connects,
}

// 最大连接数
#[derive(Debug, Serialize, Deserialize)]
pub struct Connects {
    pub max_conns: usize,
}

同时修改src/server.rs代码:

pub struct Server {
    ......
    max_conns: Arc<Semaphore>,  // 最大连接数
}
impl Server {
    pub fn new(listen_addr: String, service: Service, max_conns: usize) -> Self {
        Self {
            ......
            max_conns: Arc::new(Semaphore::new(max_conns)),
        }
    }
    // 与客户端建立连接
    async fn execute(&self, notify_shutdown: &broadcast::Sender<()>, shutdown_complete_tx: &mpsc::Sender<()>) -> Result<(), Box<dyn Error>> {
        let listener = TcpListener::bind(&self.listen_addr).await?;
        info!("Listening on {} ......", self.listen_addr);

        loop {
            let permit = self.max_conns.clone().acquire_owned().await.unwrap();

            ......

            tokio::spawn(async move {
                // 使用Frame的LengthDelimitedCodec进行编解码操作
                let mut stream = Framed::new(stream, LengthDelimitedCodec::new());
                drop(permit);

                ......
            });
        }
    }
}

测量监控

我们使用的性能监控和测量工具是 jaeger,在服务器端收集监控信息,发送给 jaeger 来查看执行流程及时间。

Cargo.toml文件中加入依赖:

tracing-appender = "0.1"
tracing-opentelemetry = "0.15"
opentelemetry-jaeger = "0.15"

修改src/bin/kv_server.rs代码:

let tracer = opentelemetry_jaeger::new_pipeline().with_service_name("kv_server").install_simple()?;
let tracing_layer = tracing_opentelemetry::layer().with_tracer(tracer);

tracing_subscriber::registry()
    .with(EnvFilter::from_default_env())
    .with(tracing_layer).init(); 

let root = span!(tracing::Level::INFO, "app_start", work_units = 2); 
let _enter = root.enter();

src/server.rs中加入instrument

#[instrument(name = "server_run", skip_all)]
pub async fn run(&self, shutdown: impl Future) -> Result<(), Box<dyn Error>> {
    ......
}

 #[instrument(name = "server_execute", skip_all)]
async fn execute(&self, notify_shutdown: &broadcast::Sender<()>, shutdown_complete_tx: &mpsc::Sender<()>) -> Result<(), Box<dyn Error>> {
    ......   
}

然后运行jaeger

docker run -d -p6831:6831/udp -p6832:6832/udp -p16686:16686 -p14268:14268 jaegertracing/all-in-one:latest

启动kv_server,然后运行kv_client执行多个命令,查看http://localhost:16686/