【架构师训练营 1 期】第十一周作业

用户头像
诺乐
关注
发布于: 2020 年 12 月 07 日

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



系统不可用的常见原因(个人理解):

1、系统模块之间耦合度过高。

2、子系统/模块之间未隔离开。

3、大量的同步调用。

4、未做灾备、未做容灾策略(失效转移)

5、缺少重试机制。

6、未完善熔断、限流、降级机制(面对高并发时显得脆弱)。



以我公司为例,18年初为了快速上线预约订票业务,开发就像跟时间赛跑,班次、订单、评价、支付、发票等全部放在一个系统里,模块之间强耦合。在18年年底时因发票业务的故障导致整个系统无法订票。在19年春节时,又因为支付业务里使用了大量的同步调用,导致支付长时间等待阻塞,造成大量乘客订票无响应。后续发现数据库QPS一直居高不下,数据库节点服CPU时不时被打满,只能重启得以恢复。



针对前期的问题,我们进行了几次整改。将各业务模块拆分成各个子系统,互不干扰。各服务均采用异步调用,同时对高频查询的数据做了缓存处理,并对数据库进行读写分离。目前系统运行情况已大有改观,现还在持续升级逐步实现微服务化。



保障系统稳定高可用的方案(课程笔记+小结):

一、提升系统高可用性之——解耦

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

2、面向对象基本设计原则。

3、面向对象设计模式。

4、领域驱动设计建模。

 

二、提升系统高可用性之——隔离

1、业务与子系统隔离。

2、微服务与中台架构。

3、生产者与消费者隔离。

3、虚拟机与容器隔离。

 

三、提升系统高可用性之——异步

1、多线程编程。

2、反应式编程。

3、异步通信网络编程。

4、事件驱动异步架构。





四、提升系统高可用性之——备份

1、集群设计

2、数据库复制

(CAP原理)





五、提升系统高可用性之——Failover(失效转移)

1、数据库主主失效转移。

2、负载均衡失效转移。

(确认失效—>需要转移)

(设计无状态的服务)

 

六、提升系统高可用性之——幂等

一个请求多次(调用)处理的结果要相同。

 

七、提升系统高可用性之——事务补偿

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

 

八、提升系统高可用性之——重试

由于线程阻塞、垃圾回收或网络抖动,而无法及时返回,调用者可通过重试的方式修复单次调用的故障。(上游调用者超时时间要大于下游调用者超时时间之和。换言之上游超时时间要长一点,下游超时时间要段一段)





九、提升系统高可用性之——熔断

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

从而降低某一服务故障而对整个系统造成的影响。

 



十、提升系统高可用性之——限流

高并发场景下,若访问量超过了系统承受能力,可用通过对用户请求进行流量限制,即若访问量超过系统最大处理能力,则丢弃一部分请求,保证大部分用户可访问,(舍小顾全)进而提高整个系统的可用性。

限流算法:

1、计数器算法(固定窗口算法)(改进:滑动窗口算法)

2、令牌桶算法

3、漏桶算法(流量相对均匀)

4、自适应限流(实时自动评估QPS)





十一、提升系统高可用性之——降级

在高并发时,关闭一些非核心功能(降低服务等级),将资源留给核心业务。

 

十二、提升系统高可用性之——异地多活

在多个地区部署数据中心,每个数据中心都是活跃的。

难点:每个数据中心如何保障数据一致

 

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



/**
* 验证密文(MD5)
* @param userId 用户ID
* @param plainPwd 明文
* @param cipherPwd 密文
* @return 是否验证成功
* @throws NoSuchAlgorithmException 异常
*/
public Boolean checkPwdByMD5(String userId, String plainPwd, String cipherPwd)
throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance("MD5");
digest.update((userId + plainPwd).getBytes(StandardCharsets.UTF_8));
byte[] bytes = digest.digest();
return new BASE64Encoder().encode(bytes).equals(cipherPwd);
}
/**
* 验证密文(SHA1) (40位密文) (比MD5更加安全, 运行速度比MD5慢)
* @param userId 用户ID
* @param plainPwd 明文
* @param cipherPwd 密文
* @return 是否验证成功
* @throws NoSuchAlgorithmException 异常
*/
public Boolean checkPwdBySHA1(String userId, String plainPwd, String cipherPwd)
throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance("SHA-1");
digest.update((userId + plainPwd).getBytes(StandardCharsets.UTF_8));
byte[] bytes = digest.digest();
StringBuilder hexStr = new StringBuilder();
for (byte b : bytes) {
String shaHex = Integer.toHexString(b & 0xFF);
if (shaHex.length() < 2) {
hexStr.append(0);
}
hexStr.append(shaHex);
}
return hexStr.toString().equals(cipherPwd);
}
/**
* 验证密文(SHA256) (64位密文)
* @param userId 用户ID
* @param plainPwd 明文
* @param cipherPwd 密文
* @return 是否验证成功
* @throws NoSuchAlgorithmException 异常
*/
public Boolean checkPwdBySHA256(String userId, String plainPwd, String cipherPwd)
throws NoSuchAlgorithmException {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
digest.update((userId + plainPwd).getBytes(StandardCharsets.UTF_8));
byte[] bytes = digest.digest();
StringBuilder strBuf = new StringBuilder();
for (byte b : bytes) {
String temp = Integer.toHexString(b & 0xFF);
if (temp.length() == 1) {
strBuf.append("0");
}
strBuf.append(temp);
}
return strBuf.toString().equals(cipherPwd);
}



用户头像

诺乐

关注

还未添加个人签名 2018.12.01 加入

还未添加个人简介

评论

发布
暂无评论
【架构师训练营 1 期】第十一周作业