写点什么

架构师训练营第 1 期第 11 周作业

用户头像
好吃不贵
关注
发布于: 2020 年 12 月 05 日
架构师训练营第 1 期第 11 周作业

1. 导致系统不可用的原因有哪些?保障系统稳定高可用的方案有哪些?请分别列举并简述。

引起故障的原因

  • 硬件故障

  • 软件 bug

  • 系统发布

  • 并发压力

  • 网络攻击

  • 外部灾害



解决方案如下:

解耦

  • 高内聚、低耦合的组件设计原则

  • 面向对象基本设计原则

  • 面向对象设计模式

  • 领域驱动设计建模



隔离

  • 业务与子系统隔离

  • 微服务与中台架构

  • 生产者消费者隔离

  • 虚拟机与容器隔离



异步

  • 多线程编程

  • 反应式编程

  • 异步通信网络编程

  • 事件驱动异步架构




备份

  • 集群设计

  • 数据库复制:CAP 原理


任何情况下都不能只用一台服务器提供服务,任何服务都要提供 2 个以上的服务器。

都要考虑当一台服务器不可用的时候,其它服务器可以替代使用。架构师在系统架构设计的时候,都要考虑这种异常情况。



Failover (失效转移)

  • 数据库主主失效转移。

  • 负责均衡失效转移。



如何确认失效,需要转移?



设计无状态的服务。



幂等

应用调用服务失败后,会将调用请求重新发送到其它服务器,但是这个失败可能是虚假的失败。比如服务以及处理成功,但是因为网络故障应用没有收到响应,这时应用重新提交请求就导致服务重复调用,如果这个服务是一个转账操作,就会产生严重的后果。



服务重复调用有时候是无法避免的,必须保证服务重复调用和调用一次产生的结果相同,即服务具有幂等性。有些服务天然具有幂等性,比如将用户性别设置为女性,不管设置多少次,结果都一样。但是对于交易等操作,问题就会比较复杂,需要通过交易编号等信息进行服务调用有效性校验,只有有效的操作才继续执行。



事务补偿

  • 传统事务的 ACID:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)。

  • 分布式事务的 BASE:基本可用(Basic Availability)、软状态(Soft-State)、最终一致性(Eventual Consistency)。



事务补偿:通过执行业务逻辑逆操作,使事务回滚到事务前状态。



重试

远程服务可能会由于线程阻塞、垃圾回收或者网络抖动,而无法及时返还响应,调用者可以通过重试的方式修复单词调用的故障。

  • 上游调用者超时时间要大于下游调用者超时时间之和。




熔断

当某个服务出现故障,响应延迟或者失败率增加,继续调用这个服务会导致调用者请求阻塞,资源消耗增加,进而出现服务级联失效,这种情况下使用断路器阻断对故障服务的调用。

  • 断路器三种状态:关闭,打开,半开。

  • Spring Cloud 断路器实现:Hystrix




限流

在高并发场景下,如果系统的访问量超过了系统的承受能力,可以通过限流对系统进行保护。限流是指对系统的用户请求进行流量限制,如果访问量超过了系统的最大处理能力,就会丢弃一部分的用户请求,保证整个系统可用,保证大部分用户是可以访问系统的。这样虽然有一部分用户的请求被丢弃,产生了部分不可用,但还是好过整个系统崩溃,所有的用户都不可用要好。



限流的几种方法:

  • 计数器算法(固定窗口,滑动窗口)

  • 令牌桶算法

  • 漏桶算法



降级



有一些系统功能是非核心的,但是它也给系统产生了非常大的压力,比如说在电商系统中又确认收货这个功能,即便我们不去确认收货,系统也会超时自动确认收货。



但是实际上确认收货这个操作是一个非常重的操作,因为它会对数据库产生很大的压力:它要进行更改订单状态,完成支付确认,并进行评价等一系列操作。如果在系统高并发的时候去完成这些操作,那么会对系统雪上加霜,使系统的处理能力更加恶化。



解决办法就是在系统高并发的时候,比如说像淘宝双 11 的时候,当前可能整天系统都处于一种极限的高并发访问压力之下,这时候就可以将确认收货、评价这些非核心的功能关闭,将宝贵的系统资源留下来,给正在购物的人,让他们去完成交易。



异地多活

如果整个数据中心都不可用,比如说数据中心所在城市遭遇了地震,机房遭遇了火灾或者停电,这样的话,不管我们的设计和系统多么的高可用,系统依然是不可用的。



为了解决这个问题,同时也为了提高系统的处理能力和改善用户体验,很多大型互联网应用都采用了异地多活的多机房机构策略,也就是说数据中心分布在多个不同地点的机房里,这些机房都可以对外提供服务,用户可以连接任何一个机房进行访问,这样每个机房都可以提供完整的系统服务,即使某一个机房不可使用,机房也不会宕机,依然保持可用。



异地多活的难点是数据一致。



2. 请用你熟悉的编程语言写一个用户密码验证函数,Boolean checkPW(String 用户 ID,String 密码明文,String 密码密文)返回密码是否正确 boolean 值,密码加密算法使用你认为合适的加密算法。

首先选择加密算法,最简单的是单向散列算法,再加些盐,比如用户 ID 作为盐,加在最前面,即 user_id + pwd_raw 得出散列值。是一个简单的玩具版本。


#include <iostream>#include <string>
using namespace std;
class CryptoHashCalculator { public: CryptoHashCalculator() {} ~CryptoHashCalculator() {}
bool is_equal(std::string& user_id, std::string& password, std::string& encrypted_password) { return do_encrypt(user_id, password) == encrypted_password; }
private: string do_encrypt(std::string& user_id, std::string& password) { auto str = user_id + password; std::size_t hash_value = std::hash<std::string>{}(str); return to_string(hash_value); }};
static void test__hash_calc_encrypt__expect_ok() { // GIVEN CryptoHashCalculator hash_calc;
std::string user_id = "user1"; std::string password = "CAFEBABE"; std::string encrypted_password = "10589327768887962238";
// WHEN auto equal = hash_calc.is_equal(user_id, password, encrypted_password);
// THEN std::string res = equal ? "OK" : "NOK"; std::cout << "res is " << res << std::endl;}
int main(){ test__hash_calc_encrypt__expect_ok();}
复制代码

复杂算法有 PBKDF2(Password-Based Key Derivation Function Version 2), 在 hash 基础上增加随机盐,并进行多次 hash 计算,使得彩虹表难度大幅增加,一次密码验证要进行 1000 次 hash 计算。目前没找到 CPP 的 PBKDF2 的库,写起来较为麻烦。附上别人写的代码链接:https://github.com/dbsystel/PBKDF2WinCTester/blob/master/PBKDF2.cpp


用户头像

好吃不贵

关注

还未添加个人签名 2018.11.20 加入

还未添加个人简介

评论

发布
暂无评论
架构师训练营第 1 期第 11 周作业