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

导致系统不可用的原因,主要有以下一些方面

  • 硬件故障
  • 软件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)));
}


}