疾速入门:负载均衡器
介绍
本疾速入门展现了如何应用 pingora 和 pingora-proxy 构建一个简略的负载均衡器。
负载均衡器的指标是对于每个传入的 HTTP 申请,以循环形式抉择两个后端之一: https://1.1.1.1和https://1.0.0.1 。
构建根本的负载均衡器
为咱们的负载均衡器创立一个新的 Cargo 我的项目。名称为 load_balancer
cargo new load_balancer
包含 Pingora Crate 和根本依赖项
在您的我的项目cargo.toml
文件中将以下内容增加到您的依赖项中
async-trait="0.1"pingora = { version = "0.1", features = [ "lb" ] }
创立 pingora 服务器
首先,让咱们创立一个 pingora 服务器Server
。Server
是一个能够托管一个或多个服务的过程。Server
负责配置和 CLI 参数解析、守护过程、信号处理以及失常重启或敞开。
Server
首选用法是在main()
函数中初始化,应用run_forever()
生成所有运行时线程并阻塞主线程,直到服务器退出。
use async_trait::async_trait;use pingora::prelude::*;use std::sync::Arc;fn main() { let mut my_server = Server::new(None).unwrap(); my_server.bootstrap(); my_server.run_forever();}
这将编译并运行,但它不会做任何乏味的事件。
创立负载均衡器代理
接下来让咱们创立一个负载均衡器。咱们的负载均衡器保留上游 IP 的动态列表。pingora-load-balancing
crate曾经提供了构造体LoadBalancer
,并提供了常见的抉择算法,例如循环法和散列法。所以咱们就用它吧。如果用例更简单或须要定制服务器抉择逻辑,用户能够简略地在此办法中自行实现。
pub struct LB(Arc<LoadBalancer<RoundRobin>>);
为了使服务器成为代理,咱们须要为其实现ProxyHttp
特色。
任何实现ProxyHttp
特色的对象实质上定义了如何在代理中解决申请。ProxyHttp
特色中惟一须要的办法是upstream_peer()
,该办法用于返回申请应代理到的地址。
在upstream_peer()办法中,咱们应用LoadBalancer
的select()
办法来轮询上游IP。在这个例子中,咱们应用HTTPS连贯到后端,所以咱们还须要指定 use_tls
,并在构建Peer对象时设置SNI。
#[async_trait]impl ProxyHttp for LB { /// For this small example, we don't need context storage type CTX = (); fn new_ctx(&self) -> () { () } async fn upstream_peer(&self, _session: &mut Session, _ctx: &mut ()) -> Result<Box<HttpPeer>> { let upstream = self.0 .select(b"", 256) // hash doesn't matter for round robin .unwrap(); println!("upstream peer is: {:upstream?}"); // Set SNI to one.one.one.one let peer = Box::new(HttpPeer::new(upstream, true, "one.one.one.one".to_string())); Ok(peer) }}
为了让 1.1.1.1 后端承受咱们的申请,必须存在主机申请头。增加申请头能够在upstream_request_filter()
回调中实现,该回调会在与后端建设连贯之后、发送申请头之前批改申请头。
impl ProxyHttp for LB { // ... async fn upstream_request_filter( &self, _session: &mut Session, upstream_request: &mut RequestHeader, _ctx: &mut Self::CTX, ) -> Result<()> { upstream_request.insert_header("Host", "one.one.one.one").unwrap(); Ok(()) }}
创立 pingora-proxy 服务
接下来,让咱们创立一个遵循下面负载均衡器批示的代理服务。
一个 Service
监听一个或多个(TCP 或 Unix 域套接字)端点。当建设新连贯时,会将Service
连贯移交给其“应用程序”。pingora-proxy
就是这样一个应用程序,它将 HTTP 申请代理到下面配置的给定后端。
在上面的示例中,咱们创立一个具备1.1.1.1:443
和1.0.0.1:443
两个后端的LB
实例。咱们通过 调用http_proxy_service()
办法将该LB
实例放入代理Service
,而后通知咱们 托管该代理 Service
。
fn main() { let mut my_server = Server::new(None).unwrap(); my_server.bootstrap(); let upstreams = LoadBalancer::try_from_iter(["1.1.1.1:443", "1.0.0.1:443"]).unwrap(); let mut lb = http_proxy_service(&my_server.configuration, LB(Arc::new(upstreams))); lb.add_tcp("0.0.0.0:6188"); my_server.add_service(lb); my_server.run_forever();}
运行
当初咱们曾经将负载均衡器增加到服务中,咱们能够应用以下命令运行咱们的新我的项目
cargo run
要测试它,只需应用以下命令向服务器发送一些申请:
curl 127.0.0.1:6188 -svo /dev/null
您还能够将浏览器导航至http://localhost:6188
以下输入显示负载均衡器正在执行均衡两个后端的工作:
upstream peer is: Backend { addr: Inet(1.0.0.1:443), weight: 1 }upstream peer is: Backend { addr: Inet(1.1.1.1:443), weight: 1 }upstream peer is: Backend { addr: Inet(1.0.0.1:443), weight: 1 }upstream peer is: Backend { addr: Inet(1.1.1.1:443), weight: 1 }upstream peer is: Backend { addr: Inet(1.0.0.1:443), weight: 1 }...
做得好!此时,您就有了一个性能失常的负载均衡器。不过,它是一个十分 根本的负载均衡器,因而下一节将疏导您理解如何应用一些内置的 pingora 工具使其更加强壮。
增加性能
Pingora 提供了一些有用的性能,只需几行代码即可启用和配置这些性能。这些范畴包含从简略的对等健康检查到零服务中断无缝更新正在运行的二进制文件的能力。
对等健康检查
为了进步咱们负载均衡器的可靠性,咱们心愿向上游对等方增加一些健康检查。这样,如果有一个对等方呈现故障,咱们能够迅速进行将流量路由到该对等方。
首先,让咱们看看当其中一个对等体呈现故障时,咱们的简略负载均衡器会如何体现。为了做到这一点,咱们将更新对等体列表,包含一个必定会出问题的对等体。
fn main() { // ... let upstreams = LoadBalancer::try_from_iter(["1.1.1.1:443", "1.0.0.1:443", "127.0.0.1:343"]).unwrap(); // ...}
当初,如果咱们再次应用cargo run
运行,并用命令测试
curl 127.0.0.1:6188 -svo /dev/null
咱们能够看到,每 3 个申请中就有 1 个502: Bad Gateway
申请失败。这是因为咱们的对等方抉择严格遵循咱们给出的RoundRobin
抉择模式,而不思考该对等方是否衰弱。咱们能够通过增加根本的健康检查服务来解决这个问题。
fn main() { let mut my_server = Server::new(None).unwrap(); my_server.bootstrap(); // Note that upstreams needs to be declared as `mut` now let mut upstreams = LoadBalancer::try_from_iter(["1.1.1.1:443", "1.0.0.1:443", "127.0.0.1:343"]).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(); // `upstreams` no longer need to be wrapped in an arc let mut lb = http_proxy_service(&my_server.configuration, LB(upstreams)); lb.add_tcp("0.0.0.0:6188"); my_server.add_service(background); my_server.add_service(lb); my_server.run_forever();}
当初,如果咱们再次运行并测试负载均衡器,咱们会看到所有申请都胜利,并且永远不会应用损坏的对等方。依据咱们应用的配置,如果该对等方再次变得衰弱,它将在 1 秒内再次从新蕴含在循环中。
命令行选项
Server
类型提供了许多内置性能,咱们能够通过单行更改来利用这些性能。
fn main() { let mut my_server = Server::new(Some(Opt::default())).unwrap(); ...}
通过此更改,传递给负载均衡器的命令行参数将被 Pingora 应用。咱们能够通过运行来测试:
cargo run -- -h
咱们当初应该能看到一个帮忙菜单,列出了咱们能够应用的参数列表。在接下来的局部中,咱们将利用这些参数为咱们的负载均衡器做更多事件。
在后盾运行
传递参数-d
or--daemon
将通知程序在后盾运行。
cargo run -- -d
要进行此服务,您能够向其发送SIGTERM
信号以进行失常敞开,其中该服务将进行承受新申请,但在退出之前尝试实现所有正在进行的申请。
pkill -SIGTERM load_balancer
(SIGTERM
是pkill
的默认信号。)
配置
Pingora 配置文件帮忙定义如何运行服务。上面是一个示例配置文件,它定义了服务能够有多少个线程、pid 文件的地位、谬误日志文件和降级协调套接字(咱们将在稍后解释)。复制以下内容并将其放入load_balancer
我的项目目录中名为conf.yaml
的文件中。
---version: 1threads: 2pid_file: /tmp/load_balancer.piderror_log: /tmp/load_balancer_err.logupgrade_sock: /tmp/load_balancer.sock
应用这个 conf 文件:
RUST_LOG=INFO cargo run -- -c conf.yaml -d
RUST_LOG=INFO
以便服务理论填充谬误日志。
当初您能够找到该服务的 pid。
cat /tmp/load_balancer.pid
服务优雅降级
(仅限 Linux)
假如咱们更改了负载均衡器的代码,从新编译了二进制文件。当初咱们要将后盾运行的服务降级到这个新版本。
如果咱们只是进行旧服务,而后启动新服务,则两头达到的一些申请可能会失落。侥幸的是,Pingora 提供了一种优雅的形式来降级服务。
这是通过首先向正在运行的服务器发送SIGQUIT
信号,而后应用参数-u
\`--upgrade`启动新服务器来实现的。
pkill -SIGQUIT load_balancer &&\RUST_LOG=INFO cargo run -- -c conf.yaml -d -u
在此过程中,旧的正在运行的服务器将期待并将其侦听套接字移交给新服务器。旧服务器会运行直到所有正在进行的申请实现时。
从客户端的角度来看,服务始终在运行,因为侦听套接字永远不会敞开。
残缺示例
此示例的残缺代码可在以下仓库中找到
pingora-proxy/examples/load_balancer.rs
您可能会发现有用的其余示例也能够在这里找到
pingora-proxy/examples/ pingora/examples
翻译自官网文档:https://github.com/cloudflare/pingora/blob/main/docs/quick_start.md
本文由博客一文多发平台 OpenWrite 公布!