开启负载均衡和重启自身
- 更换axum后台的意外
- 解决的尝试
- 在caddy反代,使用负载均衡,加多一个节点
- axum主程序 ip映射信息做全局共享
- axum重启自身刷新全局共享配置
前期刚实现了rust的后台关键业务.结果出现了两类大问题停止服务.在正用着的时候,出现很多意外,真是刺激…
更换axum后台的意外
1, ip2sta的配置没有在原flask服务重启后,没有导入到redis,导致rust后台无法取到,修改原flask初始redis的代码才解决, 停服一天,
2,rust服务,工作进程被我误退出了,结果所有的地点无法访问签到. 停服一天.
3,开启12小时观察到的,新的rust所在主机,没有使用东8区, 只是8点前无法使用业务数据.修改时区,未再造成停服.
下面说下负载均衡和动态监测可以解决这个问题,同时,
解决的尝试
在caddy反代,使用负载均衡,加多一个节点
更新了Caddyfile文件的handle_path改为handle,避免了一次无用的rewrite.
redir /ck/test /rk/test/0
handle /rk/* {
# handle_path /rk/*
# rewrite * /rk{path}
reverse_proxy {
header_up Host {host}
header_up X-Real-IP {remote}
health_uri /
health_interval 5s
health_timeout 1s
to 10.180.133.35:6055 192.168.11.179:3001
}
}
目测现在有两处提供服务,并且在一处断开后,只使用能用的那个.
axum主程序 ip映射信息做全局共享
上个文章
Android后端签到flask迁移到rust的axum的过程-签到性能和便携 ,ip2sta,加载到axum的启动配置.这样不要每次redis取值.
/**
* 连接connection_redis
*/
fn connection_redis() -> redis::RedisResult<Connection> {
let client = redis::Client::open(REDURL)?;
let con = client.get_connection()?;
Ok(con)
}
fn init_app_config() -> HashMap<String, String> {
let mut con = connection_redis().ok().unwrap();
// 测试是否成功连接Reids
let keys:Vec<String>= con.hkeys("ip2sta" ).ok().unwrap();
let mut map=HashMap::new();
for i in keys{
let v:String= con.hget("ip2sta", &i).ok().unwrap();
map.insert(i,v);
}
map
}
lazy_static! {
static ref IP2STA: HashMap<String,String> = init_app_config(); }
#[tokio::main]
async fn main() {
在main主任务启动以前加载一次.就可以如下使用
.route("/rk/test/",get(somehandle))
.......
async fn somehandle(){
match IP2STA.get(&cip) {
Some(sta)=> pobsta( State(pool.clone()),formatted,sta,person).await ,
None => Ok(Html(format!("请联系管理员{:?}未设置~!",&cip))),
}
这造成一个问题,ip2sta无法使用最新的数据.
虽然很久不会更新这个底层数据,但是手动重启不是合适的风格.必须要能让后台自动加载新信息…
axum重启自身刷新全局共享配置
https://zhuanlan.zhihu.com/p/649783802
Axum笔记:配置管理
这里提供了很多刷新的方式,其中state的方式已经被pool占有,lazy_static!是本文用的,剩下的我不理解,
下面是我提供的刷新方式,重启自身
在某个handle启动一个新spawn,即调用如下函数.
use tokio::time::{sleep, Duration};
use std::{process,env};
async fn restartme(){
let delay = Duration::from_millis(50);
// 在延时后启动新进程
tokio::spawn(async move {
// 等待延时
sleep(delay).await;
// 获取程序自身的路径
let me = env::current_exe().expect("Failed to get current exe path");
// 重启程序
let status = process::Command::new(me).spawn();
match status {
Ok(_child) => {
// 如果成功,则退出当前实例
std::process::exit(0);
}
Err(e) => {
// 如果重启失败,打印错误并退出
println!("Failed to restart: {}", e);
std::process::exit(1);
}
}
});
}
这样并不容易,因为当前process肯定占有了tcp端口. 所有子线程的成功判断,应该在tcp还未开始时.而且必须在父线程必须释放端口后再打开,可能tokia的axum 使用了,等待重试,和恰好的判断时机,让程序也就是web服务自己完成了配置加载和重启自身.