Serverless

Serverless=FaaS(函数即服务)+BaaS(后端即服务)

FaaS:拆分逻辑到函数层面,直接上传源码,由服务器对源码进行调度。个人认为微信小程序中的云函数大致是实现了这个FaaS。

BaaS:拆掉所有除了逻辑本身的服务,比如数据库、消息队列、对象存储等,让开发更专注于业务逻辑开发,提高开发效率。

Knative理念:Build(构建程序)+Serving(提供服务)+Event(事件处理),底层使用
Kubernetes进行分布式处理

服务路由策略:大致流程:Service->Router->负载灰度分发到不同的Pod,前端Service->Configure->发布程序到不同Pod。

Serverless冷启动:常驻服务设置,保持服务至少有一个正在运行,从而避免冷启动延迟问题
部署方式:镜像/Dockerfile/源码,容器化部署

生态:静态资源托管加速,动态资源流量驱动(云应用)

Docker

Docker&VM:Docker系统层模拟,复用Kernel来实现更高性能,实现相对的隔离,不过也导致了严重漏洞存在的可能性(CVE-2019-5736);VM虚拟化硬件,所有操作绝对隔离,安全性更高

Docker分层存储:镜像按层的方式存储,一层层覆盖,某层删除的文件依旧会在之前的存储层中被保留,可能带来安全性问题

Docker空白镜像:scrach,完全空白镜像

Docker EXPOSE:和-p不同,这个相当于开放容器的若干端口(没有映射),-p需要进行端口映射;运行时EXPOSE的端口在默认情况下会进行随机映射。

Docker HEALTHCHECK:相当于隔一段时间运行一个命令,主要用于健康检查,不过应该也能干别的事情。判断基准是根据是否响应和响应时间,在某些情况下可能功能过于简单(比如可访问但是404);可以用docker inspect查询输出状态。

Docker VOLUME:匿名卷,可以理解成设置对于某个文件夹不会被Docker记录用于下一层构建。

Docker ONBUILD:在基于基础情况构造下一层镜像时才执行命令。如果直接用这个镜像,该命令不会被执行。

Docker 多阶段构建:编译-打包分离(主要针对二进制文件),节省空间同时降低构建复杂度:在一个镜像中编译,在另一个镜像中发布,可以省空间。

Docker import&load:import导入镜像会丢弃历史记录,占用空间小;load导入镜像会导入历史记录,占用空间大。

Docker 数据卷:相当于mount挂载了一个文件夹,可以理解成搞了个U盘插入电脑。因为可以持久化且共享,应该可以保存一些需要持久化的信息

Docker 网络:利用Docker network来实现一个仅仅相互连接的内网,在网络安全中可以制作内网渗透镜像(多个docker联动)

Docker架构:C/S,由Docker主进程创建一堆客户端;

Docker 网络架构:本地-容器生成一对虚拟接口;本地->连接到指定网桥;容器->设置eth0,设置网桥为路由并分配ip地址。具体配置分为bridge(桥接),host(接管主机),
container(共享网络但不共享其他),none(然后配置)

Docker .dockerignore:类似.gitignore,构造镜像时排除符合规则的文件

数据库

数据库在使用中常常遇到许多问题,比如:缓存穿透、缓存击穿、雪崩、一致性。

缓存穿透:用户对于数据库中没有而缓存中也没有的数据进行大量访问,影响数据库性能(可能用户是攻击者)

传统解决方案:

1、 增加校验层,提前对用户权限进行校验

2、 对于数据库中不存在的数据,可以在缓存中设置key-value为id-null,同时设置很短的过期时间(比如5s),从而实现在缓存层面返回不存在,减少性能影响

缓存击穿:用户对于数据库中有而缓存中没有的数据进行大量访问,此时会造成对于数据库的大量取访问,影响数据库性能。

传统解决方案:

1、 热点数据不过期

2、 互斥锁,以降低访问效率为代价,减少对于数据库性能的影响

缓存雪崩:正如其名,这个东西是缓存击穿的升级版。缓存击穿针对的是一条数据,而缓存雪崩则是针对很多不同数据,这批数据一块被用户大量查询,从而影响数据库性能。

传统解决方案:

1、 缓存时间在基本情况的基础上加一些随机话的因素进去,从而缓解批量缓存到期的后果。

2、 热点数据均分在分布式数据库中

3、 热点数据不过期

一致性:数据库更新需要时间,这段时间可能会在缓存查到旧数据造成不同步。

某设计方案:冷热混合存储

1、 Proxy分发:分片查询,路由分发(理解:按照数据特性随机化分布式)

2、 Redis缓存:缓存Key,淘汰Value;限速(理解:冷热混合存储)

数据库更新一致性方案:

1、 先缓存后数据库:无法保证均成功,数据库更新失败会导致缓存和数据库不同步

2、 先数据库后缓存:多线程下缓存设置可能会导致新缓存被旧缓存更新

3、 先写库后删缓存:删缓存失败不一致,非原子操作

4、 先删缓存后写库:删完缓存写库前接受查询,查到旧信息后设置旧缓存

传统策略:

1、 延时双删策略:删缓存后写库,写完休眠后再次删除缓存(删掉查到旧信息后写库的缓存),缺点是休眠影响性能且可能第二次删缓存失败

2、 异步更新:删缓存后写库,binlog->消息队列,分布式更新缓存库,缺点是消息队列导致延迟相对高。

新策略:

1、版本化Redis:消息带版本号

2、全量Key缓存:避免了上面说的缓存穿透问题

3、限速:阻塞用户写,保证一致性。

4、增量RDB:类似Git的控制系统,增量更新缓存而非直接全量发送重建。

个人的理解总结:使用了类似Git的版本控制,解决了全量更新一致性时影响的性能;同时使用了阻塞,以降低用户访问请求速度为代价,保证很高的一致性。不过全量Key缓存可能对存储空间有一定影响。

思考:具体分布式存储数据时可以针对数据做hash,根据hash值分配分布式服务器,保证数据尽量均匀;热点数据需要每个服务器进行缓存,可以用HTTP慢连接进行更新。

It is my final heart.
最后更新于 2022-07-24