吹拉弹唱


  • Home
  • Archive
  • Categories
  • Tags
  • Books
  •  

© 2022 Kleon

Theme Typography by Makito

Proudly published with Hexo

烤面筋 - 后端

Posted at 2021-04-26Updated at 2021-05-19 面筋  面筋 

操作系统,网络,系统设计

# 生产服务

# 高可用

https://developer.aliyun.com/article/699892

服务稳定性保障

保障策略:限流,降级,隔离,超时,重试和集群

# 限流

  1. 防止系统高负荷运行
  2. 有效利用服务器资源

算法

  1. 漏桶算法
  2. 令牌桶算法

# 降级

系统上线之后总会遇到一些不稳定情况,比如redis挂了,MySQL挂了,系统如何保证继续提供这些服务

  1. 保障服务器基本可用
  2. 保障服务的核心服务可用

# 超时

合理设置超时时间

  1. 识别业务需要的服务响应时间
  2. 统计服务日常的响应时间
  3. 分清主次,即分出哪些是核心服务。因为核心服务一旦失败,整个链路便不可用,所以可以对核心服务的时间设置的宽松一些

# 隔离

  1. 秒杀场景,和正常业务分开,热点数据在数据库层面隔离
  2. 慢SQL隔离,资源隔离
  3. 机房隔离,一般大公司都会做多机房部署,其目的就是确保稳定性。确保稳定性时不要做跨机房调用,否则耦合度会比较高,假如 A 调 B,B 挂掉,A 服务也会受影响。一般确保稳定性都是做本机房的调用。而且本机房的调用性能也比较快
  4. 进程隔离,进程比线程更加稳定。
  5. 资源隔离,CPU,磁盘,docker cgroup

https://blog.kelu.org/tech/2019/10/11/kubernetes-Limit-iops-per-container.html

# 集群

对小公司而言,一台机器就提供一个服务,如果机器挂掉服务恢复就会成为一个问题。一般解决方法是做一个集群,从原来的一台机器提供服务变为可以用多台机器提供服务

  1. 主备
  2. 主从
  3. 多主

分布式锁

# 流程

# CR

# 压测

  1. 稳定性
  2. 最大QPS

首先,压测机器和被压测服务在同一网段,尽量避免因为网络原因导致压测的结果不准确。第二点是关注服务器的负载,注意不要把服务器压到 100%,服务器快要崩的时候,得到的值意义不大。应该是服务器负载达到 60%~70%的时候,看 QPS 是多少。另外,压测并发数据是逐步递增的过程,到一个点的时候,并发数据越多代表 QPS 越低。最后,根据测试环境的压测结果估算线上的承载能力。估算的公式是线上 QPS = 单机 QPS 机器数 0.7。后面会乘以一个系数(0.7)是因为线上 put 上去的时候总会存在一些损耗。

但有一些测试在测试环境下无法实现压测,所以现在发展成了全链路压测。全链路压测大概分成三个核心关注点。第一个是数据模型的构造。全链路压测是模拟线上真正的数据模型,比如说访问详情页的人数,下单的人数,人数比例,登陆人数等等参数,尽量按照真实数据模拟,构建仿真模型,这样才能真正的发现线上的一些问题。注意全链路压测不是在测试环境下实现,而是在线上压测。第二个是压测工具构建。可以是借助开源的压测工具,阿里自建了压测平台,根据数据模型提升流量。第三点是流量的隔离。对流量增加标识,保证不影响线上的数据,将全链路测试流量放到测试的存储中。比如生成一个订单 order 表,同时也会生成一个影子表 test_order。如果发现是来自于全链路压测的流量,就把这个数据写到影子表 test_order 里面,这样能够保证存储。无论是缓存还是数据库存储都能够进行流量隔离。

# 灰度

  1. 地区
  2. 用户属性
  3. 数据,一批用户中选取几个用户进行处理
  4. 平台,一般都发生在客户端场景下。客户端与服务端不同,服务端一般是针对这个平台,先指挥这个平台先发布新版本,反馈不错再推到整个全面平台。对于客户端的灰度技术的实现如下图,给客户端集中一个 Cookie,请求到了之后在 Nginx 中去检查 Cookie,根据不同的 Cookie 把情趣转到不同的组。比如组 A 有新特性,组 B 是老版本,根据不同的 Cookie 转到不同组,保证只有一部分人可以看到新的特性。

# 监控

第一是全方面监控,系统和服务全部都要监控。
第二是报警分级,监控报警的系数设置的要合理。
最后一点是在真实环境下做数据收集。

首先确定对哪些指标进行监控。将整个指标的数据绘制出来,查看指标数据波动。一旦遇到问题,可以很方便的进行对比。另外要确定影响,将所有相关的指标聚合起来。比如供应商的团队操控系统经常会发生仓库操作卡顿,有很多因素都会导致卡顿,如 PC 端调用其它接口较慢,服务器 load 比较高等。仓库人员无法关注具体的细节,他们在影响界面查看指标影响值,一眼就可以知道是哪项指标不合格导致的卡顿。之后对造成的影响进行相应的处理,目前一般的行为有效报警或短信报警。

# SLA

https://www.cnblogs.com/imyalost/p/12952930.html

# 雪崩、降级与熔断

https://www.cnblogs.com/rjzheng/p/10340176.html

# 服务幂等

https://www.jianshu.com/p/c7a8444f2fc2

# 操作系统

# 并发 并行

并发:在操作系统中,某一时间段,几个程序在同一个CPU上运行,但在任意一个时间点上,只有一个程序在CPU上运行。

当有多个线程时,如果系统只有一个CPU,那么CPU不可能真正同时进行多个线程,CPU的运行时间会被划分成若干个时间段,每个时间段分配给各个线程去执行,一个时间段里某个线程运行时,其他线程处于挂起状态,这就是并发。并发解决了程序排队等待的问题,如果一个程序发生阻塞,其他程序仍然可以正常执行。

并行:当操作系统有多个CPU时,一个CPU处理A线程,另一个CPU处理B线程,两个线程互相不抢占CPU资源,可以同时进行,这种方式成为并行。

并发只是在宏观上给人感觉有多个程序在同时运行,但在实际的单CPU系统中,每一时刻只有一个程序在运行,微观上这些程序是分时交替执行。
在多CPU系统中,将这些并发执行的程序分配到不同的CPU上处理,每个CPU用来处理一个程序,这样多个程序便可以实现同时执行。

# 进程 线程 协程

# 基本概念与对比

https://www.cnblogs.com/Survivalist/p/11527949.html

超线程技术就是利用特殊的硬件指令,把一个物理芯片模拟成两个逻辑处理核心,让单个处理器都能使用线程级并行计算,进而兼容多线程操作系统和软件,减少了CPU的闲置时间,提高的CPU的运行效率。这种超线程技术(如双核四线程)由处理器硬件的决定,同时也需要操作系统的支持才能在计算机中表现出来。

程序一般不会直接去使用内核线程,而是去使用内核线程的一种高级接口——轻量级进程(Lightweight Process,LWP),轻量级进程就是我们通常意义上所讲的线程,也被叫做用户线程。由于每个轻量级进程都由一个内核线程支持,因此只有先支持内核线程,才能有轻量级进程。用户线程与内核线程的对应关系有三种模型:一对一模型、多对一模型、多对多模型,在这以4个内核线程、3个用户线程为例对三种模型进行说明。

context切换过程对比

# 孤儿进程

一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
由于孤儿进程会被init进程给收养,所以孤儿进程不会对系统造成危害

https://liubigbin.github.io/2016/03/11/Linux-之守护进程、僵死进程与孤儿进程/

# 僵尸进程

一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。

一个进程如果只复制fork子进程而不负责对子进程进行wait()或是waitpid()调用来释放其所占有资源的话,那么就会产生很多的僵死进程,如果要消灭系统中大量的僵死进程,只需要将其父进程杀死,此时所有的僵死进程就会编程孤儿进程,从而被init所收养,这样init就会释放所有的僵死进程所占有的资源,从而结束僵死进程。

进程优先级 时间片调度

https://blog.csdn.net/weixin_44029810/article/details/107444546

# 锁

https://www.cnblogs.com/xiaolincoding/p/13675202.html

悲观锁

自旋锁(Spin)

互斥锁(Mutex)

读写锁(RW)

读锁,写锁,读优先锁,写优先锁,公平读写锁

乐观锁

只有在冲突概率非常低,且加锁成本非常高的场景时,才考虑使用乐观锁

# 分布式锁

https://zhuanlan.zhihu.com/p/42056183

  • 可以保证在分布式部署的应用集群中,同一个方法在同一时间只能被一台机器上的一个线程执行。
  • 这把锁要是一把可重入锁(避免死锁)
  • 这把锁最好是一把阻塞锁(根据业务需求考虑要不要这条)
  • 这把锁最好是一把公平锁(根据业务需求考虑要不要这条)
  • 有高可用的获取锁和释放锁功能
  • 获取锁和释放锁的性能要好

# 基于数据库做分布式锁

基于乐观锁

  • 基于表主键唯一做分布式锁
  • 基于表字段版本号做分布式锁

基于悲观锁

  • 基于数据库排他锁做分布式锁

# 基于Redis做分布式锁

  • 基于 redis 的 setnx()、expire() 方法做分布式锁
  • 基于 redis 的 setnx()、get()、getset()方法做分布式锁
  • 基于 Redlock 做分布式锁
  • 基于 redisson 做分布式锁

# 基于ZooKeeper做分布式锁

# 基于 Consul 做分布式锁

# 死锁

https://zhuanlan.zhihu.com/p/78135409

# 用户态与内核态

https://zhuanlan.zhihu.com/p/69554144

内核态:cpu可以访问内存的所有数据,包括外围设备,例如硬盘,网卡,cpu也可以将自己从一个程序切换到另一个程序。

用户态:只能受限的访问内存,且不允许访问外围设备,占用cpu的能力被剥夺,cpu资源可以被其他程序获取。

由于需要限制不同的程序之间的访问能力, 防止他们获取别的程序的内存数据, 或者获取外围设备的数据, 并发送到网络, CPU划分出两个权限等级 – 用户态和内核态。

系统调用,陷阱指令

# Select/epoll🌟

IO多路复用,底层数据结构,epoll的几个函数,两种模式

Linux IO模式及 select、poll、epoll详解

https://segmentfault.com/a/1190000003063859

IO multiplexing就是我们说的select,poll,epoll,有些地方也称这种IO方式为event driven IO。select/epoll的好处就在于单个process就可以同时处理多个网络连接的IO。它的基本原理就是select,poll,epoll这个function会不断的轮询所负责的所有socket,当某个socket有数据到达了,就通知用户进程。

select,poll,epoll都是IO多路复用的机制。I/O多路复用就是通过一种机制,一个进程可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作。但select,poll,epoll本质上都是同步I/O,因为他们都需要在读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的,而异步I/O则无需自己负责进行读写,异步I/O的实现会负责把数据从内核拷贝到用户空间。(这里啰嗦下)

# select

1
int select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

select 函数监视的文件描述符分3类,分别是writefds、readfds、和exceptfds。调用后select函数会阻塞,直到有描述副就绪(有数据 可读、可写、或者有except),或者超时(timeout指定等待时间,如果立即返回设为null即可),函数返回。当select函数返回后,可以 通过遍历fdset,来找到就绪的描述符。

select目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点。select的一 个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在Linux上一般为1024,可以通过修改宏定义甚至重新编译内核的方式提升这一限制,但 是这样也会造成效率的降低。

# poll

1
int poll (struct pollfd *fds, unsigned int nfds, int timeout);

不同与select使用三个位图来表示三个fdset的方式,poll使用一个 pollfd的指针实现。

1
2
3
4
5
struct pollfd {
int fd; /* file descriptor */
short events; /* requested events to watch */
short revents; /* returned events witnessed */
};

pollfd结构包含了要监视的event和发生的event,不再使用select“参数-值”传递的方式。同时,pollfd并没有最大数量限制(但是数量过大后性能也是会下降)。 和select函数一样,poll返回后,需要轮询pollfd来获取就绪的描述符。

从上面看,select和poll都需要在返回后,通过遍历文件描述符来获取已经就绪的socket。事实上,同时连接的大量客户端在一时刻可能只有很少的处于就绪状态,因此随着监视的描述符数量的增长,其效率也会线性下降。

# epoll

epoll是在2.6内核中提出的,是之前的select和poll的增强版本。相对于select和poll来说,epoll更加灵活,没有描述符限制。epoll使用一个文件描述符管理多个描述符,将用户关系的文件描述符的事件存放到内核的一个事件表中,这样在用户空间和内核空间的copy只需一次。

epoll操作过程需要三个接口,分别如下:

1
2
3
int epoll_create(int size);//创建一个epoll的句柄,size用来告诉内核这个监听的数目一共有多大
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
  1. int epoll_create(int size);
    创建一个epoll的句柄,size用来告诉内核这个监听的数目一共有多大,这个参数不同于select()中的第一个参数,给出最大监听的fd+1的值,参数size并不是限制了epoll所能监听的描述符最大个数,只是对内核初始分配内部数据结构的一个建议。
    当创建好epoll句柄后,它就会占用一个fd值,在linux下如果查看/proc/进程id/fd/,是能够看到这个fd的,所以在使用完epoll后,必须调用close()关闭,否则可能导致fd被耗尽。

  2. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
    函数是对指定描述符fd执行op操作。

  • epfd:是epoll_create()的返回值。
  • op:表示op操作,用三个宏来表示:添加EPOLL_CTL_ADD,删除EPOLL_CTL_DEL,修改EPOLL_CTL_MOD。分别添加、删除和修改对fd的监听事件。
  • fd:是需要监听的fd(文件描述符)
  • epoll_event:是告诉内核需要监听什么事,struct epoll_event结构如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
struct epoll_event {
__uint32_t events; /* Epoll events */
epoll_data_t data; /* User data variable */
};

//events可以是以下几个宏的集合:
EPOLLIN :表示对应的文件描述符可以读(包括对端SOCKET正常关闭);
EPOLLOUT:表示对应的文件描述符可以写;
EPOLLPRI:表示对应的文件描述符有紧急的数据可读(这里应该表示有带外数据到来);
EPOLLERR:表示对应的文件描述符发生错误;
EPOLLHUP:表示对应的文件描述符被挂断;
EPOLLET: 将EPOLL设为边缘触发(Edge Triggered)模式,这是相对于水平触发(Level Triggered)来说的。
EPOLLONESHOT:只监听一次事件,当监听完这次事件之后,如果还需要继续监听这个socket的话,需要再次把这个socket加入到EPOLL队列里
  1. int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
    等待epfd上的io事件,最多返回maxevents个事件。
    参数events用来从内核得到事件的集合,maxevents告之内核这个events有多大,这个maxevents的值不能大于创建epoll_create()时的size,参数timeout是超时时间(毫秒,0会立即返回,-1将不确定,也有说法说是永久阻塞)。该函数返回需要处理的事件数目,如返回0表示已超时。

# 缓存

HashMap,Guava cache

https://blog.csdn.net/Box_clf/article/details/84404759

https://blog.csdn.net/zgsxhdzxl/article/details/104362897

一致性

雪崩

穿透攻击

# Nginx

https://juejin.cn/post/6844904125784653837

# 配置

# 负载均衡

# 项目

  • 遇到过内存溢出吗?怎么解决

主要了解有没有处理过内存泄漏导致的问题,C/C++定位内存泄漏问题;Golang和JAVA主要与GC的工作机制有关,堆内存一直增长,导致应用内存溢出等。

  • 布隆过滤器怎么设置m,n,k的值,怎么合理安排key(用户和item越来越多,怎么保证内存不会爆)

m,n,k 网上有实践经验,可参考。item越来越多的话,进行item的拆分,拆分本质是不要将 Hash(Key) 之后的请求分散在多个节点的多个小 bitmap 上,而是应该拆分成多个小 bitmap 之后,对一个 Key 的所有哈希函数都落在这一个小 bitmap 上。

  • 服务雪崩怎么处理,怎么解决保证不影响线上

限流,降级,熔断方面措施,结合后端系统架构阐述,如网关的限流和快速失败。

  • redis和mysql数据一致性怎么保证

重点考虑业务逻辑上写和数据的流程(异常和错误处理等),结合MQ做异步重试处理。

  • 分布式锁应用场景,哪些坑

锁过期了,业务还没执行完;分布式锁,redis主从同步的坑;获取到锁后,线程异常。

  • 流量激增

# 网络

https://juejin.cn/post/6844904125692379143

# cookie/session/JWT

response的header里有有个set-cookies字段,告知浏览器,存储cookies

# TCP

  • 三次握手
  • 四次握手
  • 可靠
  • 流控
  • 拥塞控制

# HTTP

HTTP vs HTTPS

# https的建立过程

一、客户端发起HTTPS连接
二、服务端发送证书 …
1、验证证书 …
2、生成随机数(此随机数就是后面用的对称加密的私钥) …
3、生成握手信息 …
四、服务端接收随机数加密的信息,并解密得到随机数,验证握手信息是否被篡改。 …
五、客户端验证服务端发送回来的握手信息,完成握手

https://zhuanlan.zhihu.com/p/107573461

# HTTP2

# websocket

  • 异常关闭

# client 长连接

# GET vs HEAD

# 401 vs 403

# keep-alive

# HTTP 一次连接多次请求,不等后端返回

# TCP vs UDP

# time-wait

# 三次握手和四次挥手,说一下 time_wait。

# Docker

# 微服务

# 分布式

# Python

# 装饰器

# 闭包

# django vs flask

# MongoDB

# Web Framework

# Linux基本操作

https://juejin.cn/post/6844904127059738637

# git 基本操作

git checkout -b
git rebase

# less more sed

# ps

# linux命令,查看端口占用,cpu负载,内存占用,如何发送信号给一个进程

# 函数式 面向对象 面向过程编程

# rust

# API 安全

# 设计模式

https://juejin.cn/post/6844904125721772039

# oop的三大原则

# 系统设计

# 设计步骤

# 约束

  1. 谁会使用它?
  2. 他们会怎样使用它?
  3. 有多少用户?
  4. 系统的作用是什么?
  5. 系统的输入输出分别是什么?
  6. 我们希望处理多少数据?
  7. 我们希望每秒钟处理多少请求?
  8. 我们希望的读写比率?

# 高层级设计

# 核心组件

# 扩展

# 可扩展性

  • 垂直扩展(Vertical scaling)
  • 水平扩展(Horizontal scaling)
  • 缓存
  • 负载均衡
  • 数据库复制
  • 数据库分区
  • 异步

# CAP

在一个分布式计算系统中,只能同时满足下列的两点:

  • 一致性 ─ 每次访问都能获得最新数据但可能会收到错误响应
  • 可用性 ─ 每次访问都能收到非错响应,但不保证获取到最新数据
  • 分区容错性 ─ 在任意分区网络故障的情况下系统仍能继续运行

# 海量评论系统

# 微信朋友圈系统

表结构, 基础功能,聊天列表

# 类似于设计一个长链接转短链接,不过需要考虑高并发,回答了分库分表。

# 设计一个海量日志写入系统

# 过程模拟

# 打开一个 URL 的过程

# JD

1、负责推荐、画像、搜索,广告、风控引擎等相关体系的服务接口开发;

2、负责基础应用框架的维护和迭代,完善和优化服务治理系统,参与技术文档的编写;

3、支持业务超过 10 个场景,高维度向量检索,支持特征检索,图像检索,embedding 向量检索等多种场景。

# 矩阵乘法

  • 多线程写稀疏矩阵*稠密矩阵

https://www.licc.tech/article?id=63
在Eigen中实现稀疏矩阵的多线程乘法

# 云,中间件,系统

http://blog.itpub.net/31555484/viewspace-2650133/

# 分布式ID

解决分库分表主键问题

https://segmentfault.com/a/1190000010978305

snowflake

https://www.jianshu.com/p/9a9eeb24c144

# 延时、丢包,抖动

https://zhuanlan.zhihu.com/p/21968527

Share 

 Previous post: 烤面筋 - 链接 Next post: 烤面筋 - Go 

© 2022 Kleon

Theme Typography by Makito

Proudly published with Hexo