到目前为止我们完成了邮件订阅的第一个迭代,但是我们目前还没有创建一个包含HTML表单的网页来实际测试端到端的流程。不过,我们已经完成了一些黑盒集成测试,这些测试主要关注两个基本场景:
- 当提交有效的表单数据时(如提供姓名和电子邮件),数据会被正确地保存到数据库中。
- 如果表单数据不完整(例如,缺少电子邮件、姓名或两者皆无),API会返回400状态码。
尽管如此,我们尚未准备好让软件在生产环境中稳定运行。实际上,我们还处于‘盲目’的状态:一方面,应用程序本身还未经过全面的检测;另一方面,我们也没有实施任何遥测数据的收集机制,这意味着我们对应用可能面临的未知风险缺乏了解。
为了应对由未知未知引起的故障或错误,我们可以采取哪些措施?
生产级应用需要考虑的问题
1. 监控和日志记录
- 实施全面监控:使用监控工具跟踪应用程序的健康和性能,包括系统指标、数据库查询和网络流量。这有助于早期发现异常。
- 详细日志记录:确保应用程序记录详细的运行信息,特别是关键路径和错误处理。日志应包括时间戳、用户ID、请求详情和错误消息。
2. 错误处理和弹性设计
- 优雅降级:设计应用程序以优雅地处理故障。例如,如果数据库连接丢失,应用程序应能够重试连接或向用户提供有意义的错误消息。
- 断路器:实现断路器以防止级联故障。如果服务开始失败,断路器可以暂时停止向其发送请求,允许其恢复。
- 速率限制和节流:实施速率限制以保护应用程序免受突然的流量高峰影响,防止资源过载。
3. 测试和验证
- 负载测试:定期进行负载测试,模拟高流量场景,识别潜在瓶颈。
- 模糊测试:使用模糊测试通过发送意外或格式错误的输入来识别漏洞。
- 混沌工程:通过有意引入故障来练习混沌工程,测试系统的弹性。工具如Chaos Monkey可以帮助实现这一点。
4. 应急响应计划
- 制定应急响应计划:制定明确简洁的应急响应计划,包括角色和责任、沟通协议和诊断及解决问题的步骤。
- 事后分析:在事件发生后进行事后分析,了解问题所在及如何防止类似问题再次发生。与团队分享发现,提高集体知识水平。
5. 持续学习和改进
- 保持信息更新:及时了解最新安全补丁、最佳实践和您技术栈中的新兴威胁。
- 定期代码审查:定期进行代码审查,提前发现潜在问题,确保代码质量。
- 安全审计:定期进行安全审计,识别并修复漏洞。
6. 文档和培训
- 维护关键系统文档:维护系统的最新文档,包括架构图、部署流程和故障排除指南。
- 培训和演练:培训团队成员熟悉应急响应计划,并定期进行演练,确保每个人在故障发生时知道自己的职责。
7. 社区和外部资源
- 利用社区知识:参与开发者社区和论坛,学习他人的经验和最佳实践。
- 咨询外部专家:考虑咨询外部专家或使用托管服务,以获得额外的见解和支持。
通过实施这些策略,您可以更好地准备您的团队和系统,以应对未知未知,减少故障和错误的发生概率和影响。
日志
在 Rust 中,最常用的日志库是 log
。log
提供了五个宏:trace
、debug
、info
、warn
和 error
。这些宏都做同样的事情——生成一条日志记录,但每个宏使用不同的日志级别,正如其名称所暗示的那样。
-
trace
是最低级别的日志:跟踪级别的日志通常非常冗长,信噪比较低(例如,每当 Web 服务器接收到一个 TCP 数据包时,生成一条跟踪级别的日志记录)。 - 接下来按严重程度递增顺序依次是
debug
、info
、warn
和error
。 -
error
级别的日志用于报告可能影响用户的严重故障(例如,处理传入请求失败或数据库查询超时)。
让我们来看一个简单的使用示例:
rust深色版本
use log::{trace, debug, info, warn, error};
fn main() {
// 初始化日志记录器
env_logger::init();
// 示例日志记录
trace!("This is a trace-level log message");
debug!("This is a debug-level log message");
info!("This is an info-level log message");
warn!("This is a warn-level log message");
error!("This is an error-level log message");
}
在这个示例中,我们使用 env_logger
来初始化日志记录器。env_logger
是一个流行的日志记录后端,可以根据环境变量配置日志级别。默认情况下,env_logger
会打印 info
及以上级别的日志消息。
在main.rs 里面添加日志
Cargo.toml 添加依赖
[dependencies]
env_logger = "0.9"
使用"info"
作为默认值作为日志级别,并启动日志记录功能
//!main.rs
#[tokio::main]
async fn main() -> std::io::Result<()> {
env_logger::Builder::from_env(Env::default().default_filter_or("info")).init();
//...
}
日志数据结果
#[2024-11-23T00:30:29Z INFO actix_server::builder] starting 8 workers
[2024-11-23T00:30:29Z INFO actix_server::server] Tokio runtime found; starting in existing Tokio runtime
[2024-11-23T00:30:29Z INFO actix_server::server] starting service: "actix-web-service-127.0.0.1:8000", workers: 8, listening on: 127.0.0.1:8000
给subscription.rs 也添加上日志
use core::result::Result::{Err, Ok};
use actix_web::{web, HttpResponse};
use chrono::Utc;
use sqlx::PgPool;
use uuid::Uuid;
#[derive(serde::Deserialize)]
pub struct FormData {
email: String,
name: String,
}
pub async fn subscribe(form: web::Form<FormData>, pool: web::Data<PgPool>) -> HttpResponse {
log::info!("[subscriptions].subscribe() save new details in the database");
match sqlx::query!(
r#"insert into subscriptions (id,email,name,subscribed_at) values($1,$2,$3,$4)"#,
Uuid::new_v4(),
form.email,
form.name,
Utc::now()
)
.execute(pool.as_ref())
.await
{
Ok(_) => {
use core::result::Result::{Err, Ok};
use actix_web::{web, HttpResponse};
use chrono::Utc;
use sqlx::PgPool;
use uuid::Uuid;
#[derive(serde::Deserialize)]
pub struct FormData {
email: String,
name: String,
}
pub async fn subscribe(form: web::Form<FormData>, pool: web::Data<PgPool>) -> HttpResponse {
log::info!("[subscriptions].subscribe() save new details in the database");
match sqlx::query!(
r#"insert into subscriptions (id,email,name,subscribed_at) values($1,$2,$3,$4)"#,
Uuid::new_v4(),
form.email,
form.name,
Utc::now()
)
.execute(pool.as_ref())
.await
{
Ok(_) => {
log::info!("[subscriptions].subscribe() new subscriptions has been saved");
HttpResponse::Ok().finish()
}
Err(e) => {
print!("Failed to execute query:{}", e);
HttpResponse::InternalServerError().finish()
}
}
}
HttpResponse::Ok().finish()
}
Err(e) => {
print!("Failed to execute query:{}", e);
HttpResponse::InternalServerError().finish()
}
}
}
总结:
这一节比较简单,主要学习了日志的级别,和项目中如何使用,日志在整个项目的开发周期都起着至关重要的作用,同时也希望在学习和工作当中把重要的信息都记录到日志
注:各位亲爱的小伙伴们,今年是我从事软件行业的第20年,通过博客记录的方式将我知道的、理解的、有帮助的都分享给大家。同时,也提供就业指导,专业简历优化服务。你们的支持是我最大的动力