保证session一致性

session:服务器为每个用户创建一个会话,存储用户的相关信息,以便多次请求能够定位到同一个上下文。

常见方法:

  • session文件同步法:多台 web-server 相互同步数据
  • 客户端同步法:一个用户只存储自己的数据
  • 反向代理hash一致性:四层hash还是七层hash都可以做,保证一个用户的请求落在一台web-server上
  • 后台统一存储:web-server重启和扩容,session也不会丢失,推荐redis存储

web层、service层无状态是大规模分布式系统设计原则之一,session属于状态,不宜放在web层,所以推荐后台统一存储

降低第三方服务挂了的影响

首先,可以将第三方接口,收口到一个服务内。好处:

  1. 解除调用方与第三方接口的耦合;
  2. 当第三方的接口变动时,只有服务需要修改,而不是所有调用方均修改;
  3. 方便服务降级

跨公网调用第三方,可能存在的问题:

  1. 公网抖动,第三方服务不稳定,影响自身服务;
  2. 一个接口超时,占住工作线程,影响其他接口;

降低影响的优化方案:

  1. 增大工作线程,降低对其他接口的影响;
  2. 降低接口超时时间;
  3. 服务垂直拆分;

结合业务的解决方案:

  1. 业务能接受旧数据:读取本地数据,异步代理定期更新数据;
    • 通过OpendID实时获取微信用户基本信息,先拿本地数据,再异步获取数据,更新本地数据
    • 实名认证
  2. 有多个第三方服务提供商:多个第三方互备;
    • 短信网关,可以购买多个短信网关,调用失败后调用另一个
    • 邮件服务、电子合同
  3. 向第三方同步数据:本地写成功就算成功,异步向第三方同步数据;
    • 外卖平台下单,平台再通知商家

改配置不用重启

  1. 发信号触发配置重载;
  2. 检测配置文件变化(文件md5值或last_modify_time),自动重新载入;
  3. 注册中心或配置中心,Apollo分布式配置中心;

TCP接入层的负载均衡+高可用架构

互联网架构中,web-server接入一般使用nginx来做反向代理,实施负载均衡。整个架构分三层:

  1. 上游调用层,一般是browser或者APP;
  2. 中间反向代理层,nginx;
  3. 下游真实接入集群,web-server,常见web-server的有tomcat,apache;

那整个访问过程是怎么样的?

  1. browser向目标网址发起请求;
  2. DNS将目标网址解析为外网IP(1.2.3.4);
  3. browser通过外网IP(1.2.3.4)访问nginx;
  4. nginx实施负载均衡策略,常见策略有轮询,随机,IP-hash等;
  5. nginx将请求转发给内网IP(192.168.0.1)的web-server;

由于http短连接,以及web应用无状态的特性,理论上任何一个http请求落在任意一台web-server都应该得到正常处理。 画外音:如果必须落在一台,说明架构可能不合理,难以水平扩展。

问题来了,tcp是有状态的连接,客户端和服务端一旦建立连接,一个client发起的请求必须落在同一台tcp-server上,此时如何做负载均衡,如何保证水平扩展呢?

方案一:单机法tcp-server

无法保证高可用。

方案二:集群法tcp-server

可以通过搭建tcp-server集群来保证高可用,客户端来实现负载均衡:

“IP直通车”有什么新问题? 将IP写死在客户端,在客户端实施负载均衡,扩展性很差:

  1. 如果原有IP发生变化,客户端得不到实时通知;
  2. 如果新增IP,即tcp-sever扩容,客户端也得不到实时通知;
  3. 如果负载均衡策略变化,需要升级客户端;

方案三:服务端实施负载均衡 只有将复杂的策略下沉到服务端,才能根本上解决扩展性的问题。

DNS,居然还能这么用?

一个http请求,典型的执行流程是怎么样的呢?

可以看到,典型流程为:

  1. 客户端请求dns-server,发起域名解析;
  2. dns-server返回域名对应的外网ip(1.2.3.4);
  3. 客户端通过外网ip(1.2.3.4),访问反向代理;
  4. 反向代理通过内网ip(192.168.x.x),将请求分发给web-server;
  5. web-server对请求进行处理;

除了域名解析,在架构设计时,还能利用DNS做一些什么事情呢?

  1. 用户就近访问 “智能DNS”

  2. 反向代理水平扩展

典型的互联网架构中,可以通过增加web-server来扩充web层的性能,但反向代理nginx仍是整个系统的唯一入口,如果系统吞吐超过nginx的性能极限,难以扩容,此时就需要dns-server来配合水平扩展。

具体做法是:在dns-server对于同一个域名可以配置多个nginx的外网ip,每次DNS解析请求,轮询返回不同的ip,这样就能实现nginx的水平扩展,这个方法叫“DNS轮询”。

  1. 利用DNS实施负载均衡

架构设计中,除了域名解析,DNS还有其他用武之地:

  1. 智能DNS,根据用户ip来就近访问服务器;
  2. DNS轮询,水平扩展反向代理层;
  3. 利用DNS实施负载均衡;

无锁缓存,每秒10万并发,怎么实现?

业务场景:

  1. 超高吞吐量,每秒要处理海量请求;
  2. 写多读少,大部分请求是对数据进行修改,少部分请求对数据进行读取;

解决方案:

  1. Map <key,val> 加锁(库级别锁);
  2. 减小锁粒度,key 取余后 加锁,或每个key单独加锁,但资源开销大(行级别锁);
  3. 无锁缓存,对数据签名(比如crc32)放到数据末尾,高并发下多线程写数据可能每个数据只写成功一半,读取时校验签名,不匹配丢弃再从数据库拉取;

P站,架构实践

Vanilla JS 框架