写点什么

架构师训练营第 1 期 - 第 11 周课后练习

用户头像
Anyou Liu
关注
发布于: 2020 年 12 月 06 日
  • 导致系统不可用的原因有哪些?保障系统稳定高可用的方案有哪些?请分别列举并简述。

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

答 - 1:

导致系统不可用的原因有:

  • 单点故障

比如服务器是单机,当服务器宕机或者发布时,没有其他服务器能够提供服务,通常采用集群部署的方式,当一台节点宕机时,其他节点还可以提供服务。

  • 数据库负载过高导致请求失败

当数据库负载过高时,数据库处理请求失败,无法响应。

  1. 增加缓存层,当应用请求数据时,先从缓存中取,缓存中不存在时,再从访问数据库,然后把数据放入到缓存中。使用缓存时要防止缓存穿透和缓存雪崩的情况。

  2. 主从复制,所有数据库的写请求都访问主库,所有数据库的读请求都访问从库,数据的更新通过主库的 binlog 同步到从库中。

  3. 分库分表,当数据量太大时,可以先采用分表的方式,把历史数据迁移到历史表中,当分表的方式无法满足时,可以采用分库的方式,通过指定的列进行分片,把数据访问压力分摊到每一个分库中。

  • 单个模块故障导致整个系统不可用

比如模块与模块捆绑在一起部署,单个模块访问压力过大,占用了系统大量的资源,导致其他模块可占用的资源变少,影响整个系统的可用性。可以把模块拆分成多个应用/子系统,彼此隔离,单独部署,这样某个模块发生故障时,不影响系统中其他模块的可用性。

  • 单个应用耗尽共享资源导致整个系统不可用

多个应用都部署在同一个机器上,单个应用占用大量机器资源时,导致其他应用可用资源变少,影响整个系统的可用性。可用通过虚拟机或者容器隔离技术,给每个应用指定独立的资源,这样单个应用发生故障时,不影响其他应用的可用性。

  • 共享一个线路的应用集群遭遇线路故障

当应用集群都部署在同一个机架上或者共享同一个线路,当线路出现故障时,会导致整个集群的不可用,可以把集群部署在不同的线路上,分配不同的资源进行物理隔离。

  • 大量线程同步等待导致系统无法响应

当线程同步等待一个耗时比较长的操作时,请求过多时,会导致系统中有大量线程等待,请求积压,系统无法响应。可以采用异步架构的方式,比如反应式编程异步处理请求,线程不用同步等待,而是把请求发送给下一个 actor,就返回给前台,后台 actor 异步处理。或者也可以采用消息队列的方式,把待处理的请求发送到消息队列中,消费者从队列中获取数据再进行处理,整个就是异步的过程。

  • 服务级联失效导致整个系统不可用

当下游服务出现故障响应变慢或者无法响应时,上游服务继续不停地调用下游服务,导致请求阻塞,资源消耗增加,上游服务也出现故障。这个时候可以采用熔断的机制,断路器关闭下游服务,等下游服务恢复后,再开启断路器。

  • 流量过大冲垮系统

在高并发场景时,系统的流量过大,超过了系统可以承受的范围,为保证系统不被流量冲垮,可以采用限流的方式,对超过流量限制的请求进行丢弃,保证大部分用户仍然可以使用系统。限流的算法有计数器算法、令牌通算法、漏桶算法。

  • 大促期间非核心功能影响核心功能使用

在大促期间,系统中一些非核心功能会对系统产生很大的压力,比如商品评价、确认收货等,为核心功能比如下单、支付等的可用,需要对系统进行降级处理,关闭一些非核心功能。

  • 数据中心不可用导致系统不可用

数据中心因为自然灾害或者光缆被挖断等原因,不能对外提供服务,导致整个系统的不可用。为解决这个问题,一般采用异地多活的方式,建立多个数据中心,当其中的一个数据中心无法正常提供服务时,可以切换到另一个数据中心,保证系统的可用。


答 - 2 :

  • 要求使用单向散列函数进行加密,要求是不可逆的,可以使用 MD5、SHA1、HMAC 等算法,考虑到算法安全性,使用 HMAC 可以指定密钥,可以选择 MD5/SHA1/SHA256/SHA384/SHA512 哈希算法中的一种,SHA 比 MD5 更安全,SHA256 的计算步骤相对较少,性能适中,综合考虑选择 HMACSHA256。

利用了 commons-codec 中的 HmacUtils 类

package secret;
import org.apache.commons.codec.digest.HmacUtils;
public class SecretUtils {
private static final String HMAC_KEY = "HMAC_KEY";
public static boolean checkPW(String userId, String pwd, String encryptedPwd) { String newEncryptedPwd = HmacUtils.hmacSha256Hex(pwd, HMAC_KEY); return newEncryptedPwd.equals(encryptedPwd); }}
复制代码

编写测试用例

package secret;
import org.apache.commons.codec.digest.HmacUtils;import org.junit.Test;
public class SecretUtilsTest {
@Test public void testCheckPW_correctEncrypted_returnTrue() { String pwd = "123"; String key = "HMAC_KEY"; String encrypted = HmacUtils.hmacSha256Hex(pwd, key);
assert SecretUtils.checkPW(null, pwd, encrypted); }
@Test public void checkPwd_incorrectEncrypted_returnFalse() { String pwd = "123"; String key = "HMAC_KEY"; String encrypted = HmacUtils.hmacSha256Hex(pwd, key);
assert !SecretUtils.checkPW(null, pwd, encrypted + "x"); }
@Test public void checkPwd_incorrectKey_returnFalse() { String pwd = "123"; String key = "HMAC_KEY2"; String encrypted = HmacUtils.hmacSha256Hex(pwd, key);
assert !SecretUtils.checkPW(null, pwd, encrypted); }}
复制代码


用户头像

Anyou Liu

关注

还未添加个人签名 2019.05.24 加入

还未添加个人简介

评论

发布
暂无评论
架构师训练营第 1 期 - 第 11 周课后练习