《THE ART OF SCALABILITY》中描述了一个非常有用的扩展模型:扩展立方(也叫AKF扩展立方)。
这个模型把应用比作立方体,为了支持应用的发展和演进,我们可以通过x,y,z三个方向对它进行扩展。

X轴扩展

在负载均衡之后运行应用的多个拷贝。这是最简单最常用的扩展方式。

缺陷:

  • 每个拷贝需要访问所有的数据,对缓存机制要求很高,数据库很可能成为瓶颈。
  • 不会减少日益增长的开发复杂度。

Y轴扩展

把整个应用切分为不同的服务,每个服务负责一个或少量几个关系相近的函数。

有好几种解耦拆分方式。一种是按照动词分割,一种是按照名词分割。

以购物网站为例:按照动词分割就是按照操作分割,服务1只负责购买流程,服务2只负责售后流程,服务3只负责广告投放流程;
按照名词分割就是按照对象类型分割,服务1只负责商品信息;服务2只负责用户信息。

两种扩展经常是同时使用的!

微服务化就是Y轴扩展的一个重要方式。

Z轴扩展

Z轴扩展和X轴扩展很像,但是在Z轴扩展中,每个服务只跑特定的一部分代码或数据集。

Z轴扩展一般用来扩展数据库。(数据库分片)
在做某些查询的时候,查询指令被送给每一个分片,然后分别查询,最终获得的结果聚合之后返回。
做写入的时候,只需要按照分片键,找到对应的实例进行写入即可。

Z轴扩展的优势:

  • 每个服务器只处理一部分数据
  • 优化了缓存的利用率,减少内存使用和I/O
  • 增强了事务的扩展性
  • 故障隔离

劣势:

  • 增加了整体的复杂度。
  • 需要实现分片机制。万一有重新分片的需求的话,令人头大。
  • 增加复杂度的同事,并没有降低开发的复杂度,这个需要Y轴扩展配合解决。

参考:
The Scale Cube | Microservice Architecture

JWT

JSON Web Tokens

CSRF

跨站请求伪造Cross-site request forgery(简称CSRF, 读作 [sea-surf])是一种典型的利用cookie-session漏洞的攻击,这里借用spring-security的一个例子来解释CSRF:

假设你经常使用bank.example.com进行网上转账,在你提交转账请求时bank.example.com的前端代码会提交一个HTTP请求:

1
2
3
4
5
6
POST /transfer HTTP/1.1
Host: bank.example.com
cookie: JsessionID=randomid; Domain=bank.example.com; Secure; HttpOnly
Content-Type: application/x-www-form-urlencoded
amount=100.00&routingNumber=1234&account=9876

你图方便没有登出bank.example.com,随后又访问了一个恶意网站,该网站的HTML页面包含了这样一个表单:

1
2
3
4
5
6
<form action="https://bank.example.com/transfer" method="post">
<input type="hidden" name="amount" value="100.00"/>
<input type="hidden" name="routingNumber" value="evilsRoutingNumber"/>
<input type="hidden" name="account" value="evilsAccountNumber"/>
<input type="submit" value="点击就送!"/>
</form>

你被“点击就送”吸引了,当你点了提交按钮时你已经向攻击者的账号转了100元。现实中的攻击可能更隐蔽,恶意网站的页面可能使用Javascript自动完成提交。尽管恶意网站没有办法盗取你的session cookie(从而假冒你的身份),但恶意网站向bank.example.com发起请求时,你的cookie会被自动发送过去。

因此,有些人认为前端代码将JWT通过HTTP header发送给服务端(而不是通过cookie自动发送)可以有效防护CSRF。在这种方案中,服务端代码在完成认证后,会在HTTP response的header中返回JWT,前端代码将该JWT存放到Local Storage里待用,或是服务端直接在cookie中保存HttpOnly=false的JWT。