架构师训练营 - 系统安全与高可用
软件组织原则
软件的复杂度和它的规模成指数关系
一个复杂度为100的软件系统,如果能拆分成两个互不相关、同等规模的子系统,那么每个子系统的复杂度应该是25,而不是50。如果让你来设计一个淘宝,你会一头雾水,但是如果让你来做一个登录页面,你就会非常清晰了。
组件内聚原则
组件内聚原则主要讨论哪些类应该聚合在同一个组件中,以便组件既能提供相对完整的功能,又不至于太过庞大。(复用发布等同原则、共同封闭原则、共同复用原则)
复用发布等同原则
软件复用的最小粒度应该等同于其发布的最小粒度。也就是说,如果你希望别人以怎样的粒度复用你的软件,你就应该以怎样的粒度发布你的软件。比如,Spring早期的版本把所有功能整合在一个jar包里面,使用者必须完全依赖整个jar包,而后面的版本进行了细粒度的拆分,以便用户可以更细粒度地进行依赖。
版本号约定建议
版本号格式:主版本号.次版本号.修订号。比如:1.2.3。
主版本号升级,表示组件发生了不向前兼容的重大修订。
次版本号升级,表示组件进行了重要功能修订或者bug修复,但是组件是向前兼容的。
修订号升级,表示组件进行了不重要的功能修订或bug修复。
共同封闭原则
我们应该将那些会同时修改,并且为了相同目的而修改的类放到同一组件中。而将不会同时修改,并且不会为了相同目的而修改的类放到不同的组件中。比如:某个组件修改了,而我的组件和被修改组件不相干,不应该受到牵连。
共同复用原则
共同复用原则是说,不要强迫一个组件的用户依赖他们不需要的东西。也就是说,我们应该将互相依赖,共同复用的类放在一个组件中。共同复用和共同封闭原则是相互冲突的。
组件耦合原则
组件内聚原则讨论的是组件应该包含哪些功能和类,而组件耦合原则讨论组件之间的耦合关系应该如何设计。(无循环依赖原则、稳定依赖原则、稳定抽象原则)
无循环依赖原则
无循环依赖原则说,组件依赖关系中不应该出现环。如果组件A依赖组件B,组件B依赖组件C,组件C又依赖组件A,就形成了循环依赖。
稳定依赖原则
组件的依赖关系必须指向更稳定的方向。较少变更的组件是稳定的,也就是说,经常变更的组件是不稳定的。根据稳定依赖原则,不稳定的组件应该依赖稳定组件,而不是反过来。
稳定抽象原则
一个组件的抽象化程度应该与其稳定性程度一致。也就是说,一个稳定的组件应该是抽象的,而不稳定的组件应该是具体的。
系统安全
常见攻击
XSS攻击
防御手段:消毒,过滤恶意字符。
SQL注入攻击
防御手段:消毒,过滤非法字符是一种简单粗暴的手段。预编译。
黑客获取表结构的手段:错误回显、盲注、开源
CSRF攻击
防御手段:表单token,Referer检查,验证码(识别出来到底是人还是机器人)
防御手段
Web应用防火墙
开源实现ModSecurity,最宝贵的就是识别攻击的正则表达式。
网站安全漏洞扫描
和电脑安全漏洞扫描一样,网站也需要安全漏洞扫描。
加密
单向散列加密
密文不可逆的,相当于一个指纹。常用在用户密码的保护。我们并不需要知道原始密码到底是什么,我们只要知道密码对不对就行了。
任何一个系统都不能做到取回密码的功能,只能做到重置密码。能做到取回密码的功能的网站,说明系统本身就是脆弱的了。
对称加密
场景:电商支持信用卡支付,电商网站需要跟银行进行交互,此时需要通过对称加密保存信用卡号、手机号和安全码。
非对称加密
场景:https握手、数字签名、区块链
秘钥安全管理与加解密服务系统架构
秘钥管理,比如写在配置文件或者代码里面,是非常不安全的,对于有源码权限的人来说,加密算法、秘钥都是可见的,那就没有秘密可言了。主要是为了防自己人,真的出了问题了,也能自证清白。
反垃圾邮件
先批量通过人工标记的方式标注一批邮件,再经过分类算法进行训练,得到分类模型。分类算法加载最新分类模型,对待处理邮件进行处理,就可以得出邮件是正常邮件或垃圾邮件的概率。主要是利用贝叶斯分类算法进行分类,如根据“茶叶”这个词分别出现在垃圾邮件和非垃圾邮件的概率,可以推断出一封邮件包含了“茶叶”关键字,这封邮件是垃圾邮件的概率。分类算法训练,就是要计算出这些:P(A|B)、P(A)、P(B)。
布隆过滤器黑名单
电子商务风险控制
反欺诈、反黄牛、反洗钱、反黑客盗号、反竞争对手恶意下单占用库存等等。风控的手段包括机器自动识别和人工识别。机器自动识别的方式主要有规则引擎和机器学习。
规则引擎
当交易某些指标满足一定条件的时候,就会被认为具有高风险的欺诈可能性。比如:
用户来自欺诈高发地区
交易金额超过某个数值
和上次登录地址距离差距很大
用户登录地与收货地不符
用户第一次交易
大型网站在运营过程中,结合业界最新发现,会总结出数以千计此类高风险交易的规则。如果来业务逻辑中进行实现,会充沛大量的if-else,并且要经常修改发布。
机器学习
规则引擎技术虽然简单,但是随着规则逐渐增加,出现规则冲突,难以维护的情况,而且随着规则数量的增多,性能越来越差。大型互联网应用更倾向于使用机器学习模型进行风控。
系统高可用
可用性指标
网站年度可用性指标=(1-网站不可用时间/年度总时间)X 100%
网站不可用时间(故障时间)= 故障修复时间点 - 故障发现(报告)时间点
故障分管理
故障处理流程及考核
引起故障的原因
硬件故障
软件bug
系统发布
并发压力
网络攻击
外部灾难
高可用系统架构思路
解耦
高内聚、低耦合的组件设计原则
面向对象基本设计原则
面向对象设计模式
领域驱动设计建模
隔离
业务与子系统隔离
微服务与中台架构
生产者与消费者隔离
虚拟机与容器隔离
异步
多线程编程
反应式编程
异步通信网络编程
事件驱动异步架构
重试
备份(冗余)
集群设计
数据库复制(CAP原理)
Failover(失效转移)
数据库主主失效转移
负载均衡失效转移
失效转移的情况,需要关注的点是幂等
事务补偿
传统事务的ACID
分布式事务BASE
事务补偿:通过执行业务逻辑逆操作,使得事务回滚到事务前的状态
熔断
断路器三状态:关闭(服务正常调用)、打开(服务直接返回失败)、半开(部分正常调用)。
限流
限流是指对进入系统的用户请求进行流量限制,如果访问量超过了系统的最大处理能力,就会丢弃一部分的用户请求,保证整个系统可用,保证大部分用户是可以访问系统的。
限流的几种算法:
计数器(固定窗口、滑动窗口)
令牌桶算法
漏桶算法
计数器(固定窗口)算法:
计数器(滑动窗口)算法:
令牌桶算法:
漏桶算法:
请求进来先放到漏桶里面,有个另外的线程以固定速度从漏桶取出请求进行处理。
自适应限流
没有提前人工评估,实时自动评估QPS。业务流量的不确定性与技术方案的自适应性天生一对。
降级
有一些系统功能是非核心的,但是它却给系统产生了非常大的压力,比如电商里面的确认收货这个功能,即便我们不去确认收货,系统也会超时自动确认收货。但实际上确认收货这个操作逻辑非常重,因为它会给数据库造成非常大的压力,它要修改订单状态,完成支付确认,并进行评价等一系列操作。比如淘宝双11的时候,就可以将确认收货、评价这些非核心的功能暂时关闭。将宝贵的机器资源留给正在购物的人。资源有限的情况下,尽量把机器资源留给那些高价值的操作(比如:下单购物)去。
异地多活
将数据中心分布在多个不同地点的机房里,这些机房都可以对外提供服务,用户连接任何一个机房都能得到正常的服务。异地多活的难点是数据一致性。
高可用系统的运维策略
发布高可用
自动化测试
在系统演化的早期,功能不确定,系统也不稳定,自动化测试的各种准备也不足,此时手工测试比较合适。但是随着时间推移,系统不断演化变得稳定了,此时采用自动化测试成本就比较低了。
自动化部署
持续部署三步走:
1)持续集成,向公共分支提交代码并触发自动化测试。
2)持续交付,除了跑单元测试及打包,持续交付还会将软件部署到测试环境。
3)持续部署,代码在没有人工干预的情况下,被测试、构建、部署并推送生产环境。
持续部署的流程:
预发布验证
即使经过非常严格的测试,软件部署到线上还是不可避免地会出现各种问题,甚至服务启动失败。
自动化发布
对于单体系统来说比较重要,对于微服务而言,一般来说各发布各的,比较灵活。
灰度发布
对于大规模的服务集群比较有用。
网站运行监控
绝对不允许没有监控的系统裸奔上线。(监控数据采集、用户行为日志采集、服务器性能监控、业务运行数据报告)当指标异常时,可以通过告警和自动控制的方式进行处理。
监控系统架构
高可用价值观
保持简单,使问题易于发现,快速解决。
目标明确,解决特定环境下的具体问题。
价值回归,成本收益要合理。
作业
导致系统不可用的原因有哪些?保障系统稳定高可用的方案有哪些?请分别列举并简述。
原因和方案见上文中系统高可用部分
导致系统不可用原因
硬件故障
软件bug
系统发布
并发压力
网络攻击
外部灾难
请用你熟悉的编程语言写一个用户密码验证函数,Boolean checkPW(String 用户 ID,String 密码明文,String 密码密文)返回密码是否正确 boolean 值,密码加密算法使用你认为合适的加密算法。
评论