用Rust和Pingora轻松构建超越Nginx的高效负载均衡器
目录
- 什么是Pingora?
- 实现过程
- 初始化项目
- 编写负载均衡器代码
- 代码解析
- 部署
- 总结
1. 什么是Pingora?
Pingora
是一个高性能的 Rust
库,用于构建可负载均衡器的代理服务器,它的诞生是为了弥补 Nginx
存在的缺陷。
Pingora
提供了丰富的功能和高度的扩展性,适用于各种网络应用场景。其高效的性能、易于扩展的设计以及 Rust
语言本身的安全性和速度。使得 Pingora
能够处理大量并发请求,确保高可靠性和稳定性。本文将带您一步步使用 Pingora
构建一个基础的负载均衡器。
如果你还不了解 Pingora
的相关背景, 建议先阅读:《一天为用户节省434年握手时间!Rust编写的Pingora凭什么力压Nginx?》
2. 实现过程
2.1 初始化项目
首先,我们需要一个 Rust 项目,并添加必要的依赖项。在项目根目录下的 Cargo.toml
文件中添加以下内容:
[package]
name = "load_balancer"
version = "0.1.0"
edition = "2021"[dependencies]
async-trait = "0.1"
pingora = { version = "0.1", features = ["lb"] }
2.2 编写负载均衡器代码
在 src/main.rs
中编写负载均衡器的实现代码。以下是完整的代码示例:
use async_trait::async_trait;
use pingora::{prelude::*, services::Service};
use std::sync::Arc;fn main() {// 创建一个服务器实例,传入Some(Opt::default())代表使用默认配置,程序执行时支持接收命令行参数let mut my_server = Server::new(Some(Opt::default())).unwrap();// 初始化服务器my_server.bootstrap();// 创建一个负载均衡器,包含多个上游服务器let mut upstreams = LoadBalancer::try_from_iter(["10.0.0.1:8080", "10.0.0.2:8080", "10.0.0.3:8080"]).unwrap();// 进行健康检查,最终获得到可用的上游服务器let hc = TcpHealthCheck::new();upstreams.set_health_check(hc);upstreams.health_check_frequency = Some(std::time::Duration::from_secs(1));let background = background_service("health check", upstreams);let upstreams = background.task();// 创建一个HTTP代理服务,并传入服务器配置和负载均衡器let mut lb_service: pingora::services::listening::Service<pingora::proxy::HttpProxy<LB>> =http_proxy_service(&my_server.configuration, LB(upstreams));// 添加一个TCP监听地址,监听80端口lb_service.add_tcp("0.0.0.0:80");// 添加一个TLS监听地址,监听443端口println!("The cargo manifest dir is: {}", env!("CARGO_MANIFEST_DIR"));// 在项目目录下新增一个 keys 目录,对应证书文件放在该目录下let cert_path = format!("{}/keys/example.com.crt", env!("CARGO_MANIFEST_DIR"));let key_path = format!("{}/keys/example.com.key", env!("CARGO_MANIFEST_DIR"));let mut tls_settings =pingora::listeners::TlsSettings::intermediate(&cert_path, &key_path).unwrap();tls_settings.enable_h2();lb_service.add_tls_with_settings("0.0.0.0:443", None, tls_settings);// 定义服务列表,这个示例只有一个负载均衡服务,后续有需要可以添加更多,将服务列表添加到服务器中let services: Vec<Box<dyn Service>> = vec![Box::new(lb_service)];my_server.add_services(services);// 运行服务器,进入事件循环my_server.run_forever();
}// 定义一个包含负载均衡器的结构体LB,用于包装Arc指针以实现多线程共享
pub struct LB(Arc<LoadBalancer<RoundRobin>>);// 使用#[async_trait]宏,异步实现ProxyHttp trait。
#[async_trait]
impl ProxyHttp for LB {/// 定义上下文类型,这里使用空元组,对于这个小例子,我们不需要上下文存储type CTX = ();// 创建新的上下文实例,这里返回空元组fn new_ctx(&self) -> () {()}// 选择上游服务器并创建HTTP对等体async fn upstream_peer(&self, _session: &mut Session, _ctx: &mut ()) -> Result<Box<HttpPeer>> {// 使用轮询算法选择上游服务器let upstream = self.0.select(b"", 256) // 对于轮询,哈希不重要.unwrap();println!("上游对等体是:{upstream:?}");// 创建一个新的HTTP对等体,设置SNI为example.comlet peer: Box<HttpPeer> =Box::new(HttpPeer::new(upstream, false, "example.com".to_string()));Ok(peer)}// 在上游请求发送前,执行一些额外操作,例如将某些参数插入请求头,这里的示例是插入Host头部async fn upstream_request_filter(&self,_session: &mut Session,upstream_request: &mut RequestHeader,_ctx: &mut Self::CTX,) -> Result<()> {// 将Host头部设置为example.com,当然,在现实需求中,这一步可能是多余的upstream_request.insert_header("Host", "example.com").unwrap();Ok(())}
}
3. 代码解析
3.1 对等体健康检查
为了使我们的负载均衡器更可靠,我们添加了健康检查功能到我们的上游对等体。这样,如果有一个对等体已经出现异常,就可以快速停止将流量路由到该对等体。如下代码
fn main() {// ...// 以下对等体中包含一个异常的对等体let upstreams =LoadBalancer::try_from_iter(["10.0.0.1:8080", "10.0.0.2:8080", "10.0.0.3:8080"]).unwrap();// ...
}
现在如果我们再次运行我们的负载均衡器 cargo run
,并用以下命令测试它:
curl http://127.0.0.1 -svo /dev/null
如果去掉健康检查的代码片段,我们发现会出现 502: Bad Gateway
的失败情况,这是因为我们的对等体选择严格遵循我们给出的 RoundRobin
选择模式,而没有考虑该对等体是否健康。通过引入一个健康检查的功能来解决这个问题,进而排除掉不健康对等体。关键代码如下
fn main() {// ...// 健康检查let hc = TcpHealthCheck::new();upstreams.set_health_check(hc);upstreams.health_check_frequency = Some(std::time::Duration::from_secs(1));let background = background_service("health check", upstreams);let upstreams = background.task();// ...
}
3.2 接收命令行参数
在创建 pingora
服务时,传入了一个 Some(Opt::default())
参数,pingora
将会捕获我们运行的命令行参数,并使用这些参数来配置 pingora
服务。代码变更如下
fn main() {// ...let mut my_server = Server::new(Some(Opt::default())).unwrap();// ...
}
我们可以通过以下命令来看 pingora
负载均衡器的参数说明
cargo run -- -h
这时我们可以了解到 pingora
相关参数提供的功能,后续可以为我们的服务器实现更多的功能。
4. 部署
4.1 后台运行
通过传递 -d
或者 --daemon
参数,可以将 pingora
运行在后台。如果要优雅的停止 pingora
,可以使用 pkill
命令并且传递 SIGTERM
信号,那么在关闭的过程中,服务将停止接收新的请求,但是仍然会处理完当前请求再退出。命令如下
# 后台运行,我们使用release模式,因为debug模式下会生成调试信息,会影响性能
cargo run --release -- -d
# 优雅的停止
pkill -SIGTERM load_balancer
4.2 配置
Pingora
配置文件可以定义 Pingora
如何运行,以下定义了 Pingora
的版本、线程数、pid文件、错误日志文件、升级套接字文件的配置,文件名称命名为conf.yaml
---
version: 1
threads: 2
pid_file: /tmp/load_balancer.pid
error_log: /tmp/load_balancer_err.log
upgrade_sock: /tmp/load_balancer.sock
加载配置文件运行如下:
# 设置日志级别
RUST_LOG=INFO
# 启用
cargo run --release -- -c conf.yaml -d
4.3 优雅地升级
假设我们更改了负载均衡器的代码并重新编译了二进制文件,现在我们希望将正在后台运行的服务升级到这个新版本。如果我们简单地停止旧服务,然后启动新服务,那么在中间到达的一些请求可能会丢失。幸运的是,Pingora
提供了一种优雅的方式来升级服务。
首先,我们通过SIGQUIT
停止正在运行的服务,然后使用-u
或者--upgrade
参数来启动全新的程序,如下命令
pkill -SIGQUIT load_balancer && RUST_LOG=INFO cargo run --release -- -c conf.yaml -d -u
在升级过程中,Pingora
将会自动将请求路由到新的服务,而不会丢失任何请求。从客户端的角度来看,用户感觉不到任何变化。
5. 总结
到此为止,我们已经拥有了一个功能完备的负载均衡器。通过这个简单的示例,相信大家已经对 Pingora
有了一个初步的了解。不过,这是一个非常基础的负载均衡器。在实际应用中,负载均衡器的配置和功能可能会更加复杂,我们还需要根据实际需求来进行扩展和优化。
在后续,我也会分享一些关于 Pingora 以及新兴热门技术的更多内容,欢迎继续关注!
本文完整示例代码:https://github.com/phyuany/simple-pingora-reverse-proxy
相关文章:
![](https://www.ngui.cc/images/no-images.jpg)
用Rust和Pingora轻松构建超越Nginx的高效负载均衡器
目录 什么是Pingora?实现过程 初始化项目编写负载均衡器代码代码解析部署 总结 1. 什么是Pingora? Pingora 是一个高性能的 Rust 库,用于构建可负载均衡器的代理服务器,它的诞生是为了弥补 Nginx 存在的缺陷。 Pingora 提供了…...
![](https://img-blog.csdnimg.cn/direct/8be78a0ebc934de08aea9fec6219bc6a.png)
华为云与AWS负载均衡服务深度对比:性能、成本与可用性
随着云计算的迅速发展,企业对于云服务提供商的选择变得越来越关键。在选择云服务提供商时,负载均衡服务是企业关注的重点之一。我们九河云将深入比较两大知名云服务提供商华为云和AWS的负载均衡服务,从性能、成本和可用性等方面进行对比。 AW…...
![](https://img-blog.csdnimg.cn/direct/645337a79c1641a99f63aaa26d924f37.png)
Vue65-组件之间的传值
1、收数据 2、传数据 3、批量的数据替换 若是info里面有四个数据,传过来的dataObj里面有三个数据,则info里面也只有三个数据了 解决方式: 该写法还有一个优势:传参的时候,顺序可以随意!...
![](https://img-blog.csdnimg.cn/direct/08e1e8e9fcec47d78b6c6b7812ea8980.png)
Java零基础之多线程篇:线程生命周期
哈喽,各位小伙伴们,你们好呀,我是喵手。运营社区:C站/掘金/腾讯云;欢迎大家常来逛逛 今天我要给大家分享一些自己日常学习到的一些知识点,并以文字的形式跟大家一起交流,互相学习,一…...
![](https://img-blog.csdnimg.cn/direct/edf991a45a5847a286d2ee1dfb304e34.jpeg)
技术差异,应用场景;虚拟机可以当作云服务器吗
虚拟机和云服务器是现在市面上常见的两种计算资源提供方式,很多人把这两者看成可以相互转换或者替代的物品,实则不然,这两种资源提供方式有许多相似之处,但是也有不少区别,一篇文章教你识别两者的技术差异,…...
![](https://img-blog.csdnimg.cn/direct/bc50d3a119ab4f948687cc5169653cf8.png)
Qt Quick 教程(一)
文章目录 1.Qt Quick2.QML3.Day01 案例main.qml退出按钮,基于上面代码添加 4.使用Qt Design StudioQt Design Studio简介Qt Design Studio工具使用版本信息 1.Qt Quick Qt Quick 是一种现代的用户界面技术,将声明性用户界面设计和命令性编程逻辑分开。 …...
![](https://www.ngui.cc/images/no-images.jpg)
react钩子函数用法(useCallback、useMemo)
useMemo import { useMemo } from react; function MyComponent({ a, b }) { const memoizedValue useMemo(() > { // 进行一些昂贵的计算 return a b; }, [a, b]); // 当 a 或 b 发生变化时,memoizedValue 将被重新计算 return <div>{memoizedVa…...
![](https://img-blog.csdnimg.cn/direct/2958aa96ce46430282442f7382098724.png)
linux配置Vnc Server给Windows连接
1. linux 安装必要vnc server和桌面组件 sudo apt -y install tightvncserversudo apt install xfce4 xfce4-goodies2. linux 配置vncserver密码 #bash vncserver参考: https://cn.linux-console.net/?p21846#google_vignette 3. 将启动桌面命令写入.vnc/xstartup # .vnc/x…...
![](https://www.ngui.cc/images/no-images.jpg)
Android中的KeyEvent详解
介绍 在Android中,KeyEvent 是用来表示按键事件的类,可根据对应的事件来处理按键输入,具体包含了关于按键事件的信息,例如按键的代码、动作(按下或释放)以及事件的时间戳,KeyEvent 对象通常在用…...
![](https://img-blog.csdnimg.cn/direct/65e6d218d37b4a3ca456db30ee7b9113.png#pic_center)
移植案例与原理 - HDF驱动框架-驱动配置(2)
1.2.7 节点复制 节点复制可以实现在节点定义时从另一个节点先复制内容,用于定义内容相似的节点。语法如下,表示在定义"node"节点时将另一个节点"source_node"的属性复制过来。 node : source_node示例如下,编译后bar节点…...
![](https://img-blog.csdnimg.cn/img_convert/9dfac5902823d0fdba0088d9df502feb.png)
年终奖发放没几天,提离职领导指责我不厚道,我该怎么办?
“年终奖都发了,你还跳槽?太不厚道了吧!” “拿完年终奖就走人,这不是典型的‘骑驴找马’吗?” 每到岁末年初,关于“拿到年终奖后是否应该立即辞职”的话题总会引发热议。支持者认为,这是个人…...
![](https://www.ngui.cc/images/no-images.jpg)
多处理系统结构
目录 统一内存访问(UMA)多处理器系统结构 优点 缺点 应用场景 UMA 结构的架构示例 解决方案和改进 非统一内存访问(NUMA)多处理系统结构 概述 NUMA的优点 NUMA的缺点 NUMA系统的工作原理 NUMA优化策略 结论 现代计算…...
![](https://img-blog.csdnimg.cn/direct/c68aadf96af44619a3963779e802aa5d.gif)
创建进程的常用方式
自学python如何成为大佬(目录):https://blog.csdn.net/weixin_67859959/article/details/139049996?spm1001.2014.3001.5501 在Python中有多个模块可以创建进程,比较常用的有os.fork()函数、multiprocessing模块和Pool进程池。由于os.fork()函数只适用于Unix/Linu…...
![](https://img-blog.csdnimg.cn/direct/1b3929cbccaa43dcbae9e089ff9c4cfc.png#pic_center)
李宏毅2023机器学习作业HW06解析和代码分享
ML2023Spring - HW6 相关信息: 课程主页 课程视频 Sample code HW06 视频 HW06 PDF 个人完整代码分享: GitHub | Gitee | GitCode P.S. HW06 是在 Judgeboi 上提交的,出于学习目的这里会自定义两个度量的函数,不用深究,遵循 Sugge…...
![](https://www.ngui.cc/images/no-images.jpg)
专业技能篇--算法
文章目录 前言经典算法思想总结一、贪心算法二、动态规划三、回溯算法四、分治算法 前言 这篇简单理解一些常见的算法。如果面试的时候问到相关的算法,能够应付一二。 经典算法思想总结 一、贪心算法 思想:贪心算法是一种在每一步选择中都采取在当前状…...
![](https://www.ngui.cc/images/no-images.jpg)
Vue中CSS动态样式绑定
Vue中CSS动态样式绑定与注意事项_vue css动态绑定-CSDN博客 在 Vue 中,你不能直接在 CSS 中直接绑定 data 中的数据,因为 CSS 不是响应式的。但是,有几种方法可以实现根据 Vue 实例中的数据来动态地改变样式: 内联样式绑定&…...
![](https://img-blog.csdnimg.cn/direct/2dbef4e198d340568596f111de6e4b1a.png)
【漏洞复现】契约锁电子签章平台 add 远程命令执行漏洞(XVE-2023-23720)
0x01 产品简介 契约锁电子签章平台是上海亘岩网络科技有限公司推出的一套数字签章解决方案。契约锁为中大型组织提供“数字身份、电子签章、印章管控以及数据存证服务”于一体的数字可信基础解决方案,可无缝集成各类系统,让其具有电子化签署的能力,实现组织全程数字化办公。通…...
![](https://www.ngui.cc/images/no-images.jpg)
计算机专业是否仍是“万金油”?
身份角度一:一名曾经的计算机专业学生 随着高考的结束,我站在了人生的分岔路口,面临着大学专业的选择。在众多的选择中,计算机专业一直是我深思熟虑后的一个重要选项。然而,我并不清楚自己是否真的适合这个专业&…...
![](https://www.ngui.cc/images/no-images.jpg)
Spring 启动顺序
在 Spring 框架中,应用启动过程涉及多个步骤和组件的初始化。理解 Spring 启动顺序不仅有助于优化应用性能,还能帮助开发人员排查启动过程中可能出现的问题。本文将详细介绍 Spring 启动过程中的关键步骤和顺序。 1. Spring 启动过程概述 Spring 应用的…...
![](https://www.ngui.cc/images/no-images.jpg)
2024.06.19 刷题日记
41. 缺失的第一个正数 这个题目的通过率很低,是一道难题,类似于脑筋急转弯,确实不好想。实际上,对于一个长度为 N 的数组,其中没有出现的最小正整数只能在 [1,N1] 中。 这个结论并不好想,举个例子&#x…...
![](https://www.ngui.cc/images/no-images.jpg)
linux系统中,pwd获取当前路径,dirname获取上一层路径;不使用 ../获取上一层路径
在实际项目中,我们通常可以使用 pwd 来获取当前路径,但是如果需要获取上一层路径,有不想使用 …/ 的方式,可以尝试使用 dirname指令 测试shell脚本 #!/bin/bash# 获取当前路径 CURRENT_PATH$PWD echo "CURRENT_PATH$CURREN…...
![](https://img-blog.csdnimg.cn/direct/1b7c0ec0f2d440e3a590e0496de2a1e1.png)
DeepSpeed Monitoring Comm. Logging
Monitoring 支持多种后端:Tensorboard、WandB、Comet、CSV文件; TensorBoard例子: 自动监控:DeepSpeed自动把重要metric记录下来。只需在配置文件里enable相应的看板后端即可: {"tensorboard": {"enabl…...
![](https://img-blog.csdnimg.cn/direct/66d9aee731aa40c4830a5f6f0f6f5eaf.png)
关于INCA的几个实用功能
01--VUI窗口设计 这个可以按照自己的想法设计INCA观测或标定窗口 首先进入到INCA的环境内,点击实验→加载VUI窗口 选择空的窗口 打开后如下所示: 点击UI开发模式,如下图 如下: 添加标定量、观测量、示波器 窗口的大小需要在开发…...
![](https://img-blog.csdnimg.cn/direct/3ad539227d3f42f8959c05b034b275ce.png)
Mamaba3--RNN、状态方程、勒让德多项式
Mamaba3–RNN、状态方程、勒让德多项式 一、简单回顾 在Mamba1和Mamba2中分别介绍了RNN和状态方程。 下面从两个图和两个公式出发,对RNN和状态方程做简单的回顾: R N N : s t W s t − 1 U x t ; O t V s t RNN: s_t Ws_{t-1}Ux_t&…...
![](https://img-blog.csdnimg.cn/img_convert/0ed0b504ec0ff27a5cafa71380ac4c60.png)
PLC模拟量和数字量到底有什么区别?
PLC模拟量和数字量的区别 在工业自动化领域,可编程逻辑控制器(PLC)是控制各种机械设备和生产过程的核心组件。PLC通过处理模拟量和数字量来实现对工业过程的精确控制。了解模拟量和数字量的区别对于设计高效、可靠的自动化系统至关重要。 1. …...
![](https://www.ngui.cc/images/no-images.jpg)
html中如何写一个提示框,css画一个提示框
在HTML中,提示框通常使用<div>元素来创建,然后使用CSS进行样式化。以下是一个示例,展示如何在HTML中写一个提示框,并使用CSS来设计其外观。 HTML 首先,创建一个HTML文件,其中包含一个提示框的结构&…...
![](https://www.ngui.cc/images/no-images.jpg)
ExoPlayer 学习笔记
https://www.51cto.com/article/777840.html ExoPlayer支持多种媒体格式和流媒体协议的播放器 播放视频:player.play()暂停视频:player.pause()停止播放:player.stop() Media3 ExoPlayer | Android media | Android Developers implem…...
![](https://img-blog.csdnimg.cn/direct/436eff3b14834310ac7611d77710d8be.png)
汽车IVI中控开发入门及进阶(二十七):车载摄像头vehicle camera
前言: 在车载IVI、智能座舱系统中,有一个重要的应用场景就是视频。视频应用又可分为三种,一种是直接解码U盘、SD卡里面的视频文件进行播放,一种是手机投屏,就是把手机投屏软件已视频方式投屏到显示屏上显示,另外一种就是对视频采集设备(主要就是摄像头Camera)的视频源…...
![](https://img-blog.csdnimg.cn/direct/c4f4ef577e4e461a8a8741ed6f9dd340.png)
Transformer模型:未来的改进方向与潜在影响
Transformer模型:未来的改进方向与潜在影响 自从2017年Google的研究者们首次提出Transformer模型以来,它已经彻底改变了自然语言处理(NLP)领域的面貌。Transformer的核心优势在于其“自注意力(Self-Attention…...
![](https://www.ngui.cc/images/no-images.jpg)
ROS 激光雷达
ROS 激光雷达 基本工作原理 激光雷达(LIDAR,Light Detection and Ranging)是一种用于测量距离的远程感应技术。它通过向目标发射激光并分析反射回来的光来测量目标与激光发射源之间的距离。激光雷达广泛应用于多种领域,包括地理…...
![](https://img-blog.csdnimg.cn/20190614163913880.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM4MzY2MDYz,size_16,color_FFFFFF,t_70)
做商城网站公司/网页设计可以自学吗
放在resource下面的文件,maven编译打包时会出现损害,具体的话,没细研究,所以只要打包的时候排除指定后缀文件即可了: 下载代码: ResponseBodyRequestMapping(value "/downloadExample", method RequestMethod.GET)ApiOperation(value "模板下载")void…...
![](/images/no-images.jpg)
做网站找那个公司/淄博网站推广
def test():for i in range(4):yield i ttest() t1(i for i in t) #t1 就是把t这个生成器再次用表达式生成t1生成器 def test():for i in range(4):yield i ttest() #这个生成器里还没有值 只有执行了里面才有值 不next就没值for i in t:print(i)t1(i for i in t) print…...
![](https://img-blog.csdnimg.cn/img_convert/1d5179fd3c4dc5b1e7f281215fa5d82f.png)
国外域名注册哪个网站好/重庆排名优化整站优化
展开全部您好,如果您经常被骚扰电话困32313133353236313431303231363533e4b893e5b19e31333335313166扰,可以尝试安装腾讯手机管家进行骚扰电话拦截与举报喔。管家除了可以拦截骚扰电话外,还可以拦截垃圾短信,将讨厌的号码设为黑名…...
![](/images/no-images.jpg)
巩义网站建设方案表/ui设计公司
本次项目主要需要改进的方面: 1.界面 界面的优化是其中的一大项,群众和使用者第一眼看到的是软件的界面,能不能让大家感觉到眼前一亮的感觉是十分重要的,我们在界面上没有什么经验,不知道通过怎样的方式去进行修改&…...
![](https://img-blog.csdnimg.cn/img_convert/cd0b91b2e2f5bd257440faccd30797ef.png)
服务推广网站/搜索引擎优化涉及的内容
在本文中,我将描述Kafka中日志压缩数据结构。然后,我会向大家展示Kafka如何在内部将这些topic的状态保存在文件系统中。预备知识我假设大家已经熟悉Apache Kafka的基本概念,比如代理(broker)、主题(topic)、分区(partition)、消费者(consumer…...
![](https://img-blog.csdnimg.cn/img_convert/7422b8132539e56abba806ae4e5f23c2.png)
《网页设计与制作》实验报告/seo主要做什么
单条件查询:1.先要有一张表,显示出表中的数据:无标题文档编号姓名电话分组$db new mysqli("localhost","root","12345678","heiheihei");$sql "select * from contacts";$r $db->qu…...