导致系统不可用的原因有哪些?保障系统稳定高可用的方案有哪些?请分别列举并简述。
导致系统不可用的原因,主要有以下一些方面
- 硬件故障
- 软件bug
- 系统发布
- 并发压力
- 网络攻击
- 外部灾害
主要方案:
高可用问题的解决思路,主要包括避免问题发生、故障转移、降低故障影响、快速恢复系统几个方面保证。
首先需要做计算和存储的冗余备份,包括主备、主从、集群和负载均衡等技术。
保证系统高可用的另一个策略是失败隔离,将失败限制在一个较小的范围之内,使故障影响范围不扩大。具体实现失败隔离的主要架构技术是消息队列。
限流和降级也是保护系统高可用的一种手段。在高并发场景下,如果系统的访问量超过了系统的承受能力,可以通过限流对系统进行保护。限流是指对进入系统的用户请求进行流量限制,如果访问量超过了系统的最大处理能力,就会丢弃一部分的用户请求,保证整个系统可用,保证大部分用户是可以访问系统的。
降级:系统抛弃部分不重要的功能,比如不发送短信通知,以此确保核心功能不受影响。
熔断:我们不去调用出问题的服务,让系统绕开故障点,就像电路的保险丝一样,自己熔断,切断通路,避免系统资源大量被占用。比如,用户下单时,如果积分服务出现问题,我们就先不送积分,后续再补偿。
功能禁用:针对具体的功能,我们设置好功能开关,让代码根据开关设置,灵活决定是否执行这部分逻辑。
采用幂等、错误重试、补偿等机制处理服务中的错误和异常。
异地多活架构,保证地区级别的服务不可用问题。
同时,要有完善的监控和运维机制处理各类情况。
请用你熟悉的编程语言写一个用户密码验证函数,Boolean checkPW(String 用户 ID,String 密码明文,String 密码密文)返回密码是否正确 boolean 值,密码加密算法使用你认为合适的加密算法。
package com.zhk.passwordencryption;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* @author zhuhk
* @create 2020-07-06 7:06 下午
* @Version 1.0
**/
public class HashUtil {
private static MessageDigest md5Digist;
private static final char[] hex = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
static {
try {
md5Digist = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
/*
* 构造md5 String
* @param key
* @return
*/
public static String md5(String key) {
if (key == null) {
key = "";
}
try {
MessageDigest messageDigest = (MessageDigest) md5Digist.clone();
messageDigest.update(key.getBytes());
byte[] b = messageDigest.digest();
char[] charArr = new char[32];
for (int i = 0; i < b.length; i++) {
charArr[i * 2] = hex[b[i] >>> 4 & 0xF];
charArr[i * 2 + 1] = hex[b[i] & 0xF];
}
return new String(charArr);
} catch (CloneNotSupportedException e) {
throw new RuntimeException("md5:" + e, e);
}
}
/**
* 使用MD5散列的hash code
*
* @param key
* @return
*/
public static int md5HashCode(String key) {
md5Digist.reset();
md5Digist.update(key.getBytes());
byte[] b = md5Digist.digest();
int rv = ((int) (b[3] & 0xFF) << 24) | ((int) (b[2] & 0xFF) << 16) | ((int) (b[1] & 0xFF) << 8) | (b[0] & 0xFF);
return rv > 0 ? rv : -rv;
}
}
package com.zhk.passwordencryption;
/**
* @Author zhk
* @Description 产生盐接口
* @Date 7:54 上午 2020/8/25
* @Param
* @return
**/
public interface Isalt {
public String salt();
}
package com.zhk.passwordencryption;
import java.util.Random;
/**
* @author zhuhk
* @Description 随机产生16位salt
* @create 2020-08-25 7:56 上午
* @Version 1.0
**/
public class Random16StringSalt implements Isalt{
private static char[] hex = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
@Override
public String salt() {
Random random = new Random();
StringBuilder sb = new StringBuilder(16);
for (int i = 0; i < sb.capacity(); i++) {
sb.append(hex[random.nextInt(16)]);
}
return sb.toString();
}
}
package com.zhk.passwordencryption;
/**
* @author zhuhk
* @create 2020-08-25 8:01 上午
* @Version 1.0
**/
public interface Iencrypt {
public String encryptPassword(String password);
}
package com.zhk.passwordencryption;
import java.security.MessageDigest;
/**
* @author zhuhk
* @create 2020-08-25 8:10 上午
* @Version 1.0
**/
public class MD5Encrypt implements Iencrypt{
private Isalt mySalt;
private String salt;
public MD5Encrypt(Isalt isalt) {
this.mySalt = isalt;
salt = mySalt.salt();
}
public String getSalt (){
return salt;
}
@Override
public String encryptPassword(String password) {
return HashUtil.md5(password + getSalt());
}
}
package com.zhk.passwordencryption;
public interface ICheckPassword {
boolean checkPW (String ID, String password, String encryptPassword);
}
package com.zhk.passwordencryption;
/**
* @author zhuhk
* @create 2020-08-26 11:12 上午
* @Version 1.0
**/
public class MD5CheckPassword implements ICheckPassword {
private RepositoryMock repositoryMock;
public MD5CheckPassword (RepositoryMock repositoryMock) {
this.repositoryMock = repositoryMock;
}
@Override
public boolean checkPW(String ID, String password, String encryptPassword) {
String salt = repositoryMock.getSalt(ID);
String encryptPasswordc = HashUtil.md5(password + salt);
return encryptPassword.equals(encryptPasswordc);
}
}
package com.zhk.passwordencryption;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author zhuhk
* @Description mock将用户id,加密密码,盐 存储到数据库中
* @create 2020-08-26 11:12 上午
* @Version 1.0
**/
public class RepositoryMock {
private Map<String,Map<String,String>> respority = new HashMap<>();
public void put (String ID,String Password,String salt) {
Map<String,String> pwAndsalt = new HashMap<>();
pwAndsalt.put("Password",Password);
pwAndsalt.put("salt",salt);
respority.put(ID,pwAndsalt);
}
public String getPassword(String ID) {
return respority.get(ID).get("Password");
}
public String getSalt(String ID){
return respority.get(ID).get("salt");
}
}
package test.com.zhk.passwordencryption;
import com.zhk.passwordencryption.*;
import org.junit.Assert;
import org.junit.Test;
import org.junit.Before;
import org.junit.After;
/**
* MD5CheckPassword Tester.
*
* @author <Authors name>
* @since <pre>8月 26, 2020</pre>
* @version 1.0
*/
/**
*
* Method: checkPW(String ID, String password, String encryptPassword)
*
*/
@Test
public void testCheckPW() throws Exception {
String ID = "id1";
String password = "password";
String wrongPassword = "password1";
Isalt mySalt = new Random16StringSalt();
RepositoryMock repositoryMock = new RepositoryMock();
MD5Encrypt md5Encrypt = new MD5Encrypt(mySalt);
String enCryptPassword = md5Encrypt.encryptPassword(password);
String salt = md5Encrypt.getSalt();
repositoryMock.put(ID,enCryptPassword,salt);
MD5CheckPassword md5CheckPassword = new MD5CheckPassword(repositoryMock);
Assert.assertTrue(md5CheckPassword.checkPW(ID,password,repositoryMock.getPassword(ID)));
// Assert.assertTrue(md5CheckPassword.checkPW(ID,wrongPassword,repositoryMock.getPassword(ID)));
}
}