写点什么

第十一周作业

用户头像
changtai
关注
发布于: 2020 年 08 月 24 日

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

引起故障的原因:

  • 硬件故障

  • 软件bug

  • 系统发布

  • 并发压力

  • 网络攻击

  • 外部灾害



高可用的方案:

(1)高可用系统的架构

  • 解耦

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

面向对象基本设计原则;

面向对象设计模式;

领域驱动设计建模;

  • 隔离

业务与子系统隔离;

微服务与中台架构;

生产者与消费者隔离;

虚拟机与容器隔离;

  • 异步

多线程编程;

反应式编程;

异步通信网络编程;

事件驱动异步架构;

  • 备份

集群设计;

数据库复制;

  • failover(失效转移)

数据库猪猪失效转移;

负载均衡失效转移;

尽量设计无状态的服务;

失效状态的判断;

  • 幂等

服务重复调用有时候是无法避免的,必须保证服务重新调用和调用一次产生的结果相同,及服务具有幂等性。(可以通过交易编号等信息进行服务调用有效性检验

  • 事务补偿

传统事务ACID

分布式事务BASE

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

传统的事务由数据库的ACID保证,但是在分布式情况下,一次事务可能会涉及多个服务,多个数据库(XA事务等消耗过大,没有使用价值),这种情况下,短时间数据可能没有办法做到完全一致的,但是可以通过后期补偿,能保证最终的一致性。也可以使用一些分布式的事务框架,但是整体的架构就比较重了,对一致性要求不是太高的话,一般使用事务补偿。

  • 重试

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

  • 熔断

某个服务短时间不可用,可以使用断路器(如:Hystrix)进行保护,通过 关闭、打开、半开 三种状态切换,可以做到故障自动恢复

  • 限流

对进入系统的用户请求进行流量限制,如果访问量超过了系统的最大出力能力,就丢弃一部分的用户请求,保证整个系统可用,保证大部分用户是可以访问系统的。限流也是降级的一种方法。

常用的限流方法:计数器算法(固定窗口,滑动窗口),令牌桶,漏桶;

Guava Rate limiter 就是使用令牌桶

自适应限流

  • 降级

在高并发场景下为了保证核心业务的可用性,可以停掉非核心的功能,以节约资源

  • 异地多活

为了保证在极端情况下的系统的可用性,但是因为网络延迟,不能保证数据的完全一致性



(2)高可用系统的运维

  • CICD

  • 自动化测试

  • 预发布验证

  • 代码管理(可以参考git flow

  • 自动化发布

  • 灰度发布(金丝雀发布)

  • 完善的监控体系(服务器监控+系统监控+业务监控)

  • 监控管理



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

分析:

  • 密码的加密是一个单向操作,进行校验的时候,也是比较的密码密文是否相同,不需要密文的解密,所以可以采用单向散列加密

  • 常用的单向散列加密算法有:MD5、SHA、MAC、CRC,一般选用安全性更高SHA256

  • 虽然单向散列加密是不可以逆向的,但是只要攻击者知道加密的算法和密文,还是可以通过暴力破解的手段进行破解的(对照彩虹表等),所以需要对加密算法加盐

  • 为了保证安全性,对每个用户的密码进行加密所用的盐应该是不一样的,可以使用用户id作为盐,但是用户id会长短不一,而且容易被猜中,所以把用户id转成固定长度32 bytes



代码如下,其中sha256加密算法,直接使用了shiro中的方法:

/**
* 工具类
*
* @author zhaoct
* @date 2020-08-24 9:38
*/
public class LoginUtil {
/**
* 用户密码校验函数
* @param userId 用户id
* @param password 密码明文
* @param encryptedPwd 密码密文
* @return
*/
public static boolean checkPW(String userId,
String password,
String encryptedPwd){
//密码明文->sha256(password + salt) -> 密码密文
//为了提高安全性,将用户id转成固定长度32byte
String generatedEncryptedPwd = new Sha256Hash(password, getSalt(userId)).toHex();
if(encryptedPwd.equals(generatedEncryptedPwd)){
return true;
}
return false;
}
public static String getSalt(String str){
byte[] bytes = str.getBytes();
byte[] slatBytes = new byte[32];
//如果超过32byte,剩下的就不要了,如果不足32byte,就填充0
for(int i=0; i<bytes.length; i++){
if(i < slatBytes.length){
slatBytes[i] = bytes[i];
}
}
return new String(slatBytes);
}
public static void main(String[] args) {
boolean result = LoginUtil.checkPW("100",
"123456",
"2dba35df7c1343114faf78e4edf234883497686eeb6f336ed54d6d0139df6a2e");
System.out.println(result);
}
}



执行结果:



用户头像

changtai

关注

还未添加个人签名 2018.04.30 加入

还未添加个人简介

评论

发布
暂无评论
第十一周作业