Golang为什么比别的语言跟擅长并发:

首先是因为Goroutine,算是go的一个最大的特色

是轻量级的线程,创建一个goroutine的开销非常小,大约几KB,且调度开销很低

并且goroutine的调度,并不依赖操作系统的线程调度器,而是使用了GMP模型

其次就是channel,也是go的特色

channel

通信机制:channel 算是锁的一个升级,可以避免显示锁的使用,channel可以传递数据,用于异步通信,降低并发编程的难度

提到了GMP模型讲一下

G:groutine

  • goroutine是go语言中的轻量级线程,每个goroutine都有自己的栈和执行状态
  • Goroutine的栈空间是动态扩展的,初始栈的空间很小几kb,可以根据需要自动增长和缩小

M:Machine

  • 每一个M对应一个内核线程,M是执行G的实体
  • 每个M绑定一个操作系统线程,负责执行G的代码

P:Processor

  • 管理G队列,每一个P维护一个运行队列,保存待执行的G
  • P是G调度的核心单位,M需要从P获取G才能执行
  • P一般与CPU核心数相同,可以在runtime.MAXPROCS(n)来设置P的数量

调度过程大致是:

G的创建与调度:

  • 当创建一个新的G时,它会被放入到某个P的本地队列
  • M从P的本地队列中获取G进行执行,如果P的本地队列为空,尝试从全局队列或者其他P的队列中窃取

M和P的绑定

  • M在运行时需要绑定一个P,才能从P的队列中获取g
  • 所有P都被占用,有额外的M需要执行,那么这些M会阻塞等待,直到某个P可用

P的数量控制

  • P的数量决定了可以同时并行执行G的最大数量
  • 通过runtime包中的GOMAXPROCS()来设置

调度的公平性和抢占式调度

  • 实现抢占式调度,可以在长时间运行的G中插入检查点,确保其他G也能获得执行机会
  • 通过抢占机制防止某个G长时间占用CPU,提高系统的公平性和响应性

工作窃取

  • 如果本地P为空则尝试从全局队列或者其他本地队列中获取G
  • 这样可以提高负载均衡,减少因局部队列空闲造成的资源浪费

 如何检测golang的内存泄漏

使用runtime包提供的一些对内存使用情况进行查看的方法

初步判断内存是否泄露

使用pprof工具进行分析 go tool pprof

使用pprof.WriteHeapProfile函数生成内存快照

然后使用 go tool pprof来进行分析

常见内存泄漏原因:

未关闭goroutine

未关闭文件或网络连接

缓存和数据结构:不必要的数据保存在全局变量或长生命周期的结构

内存泄漏是指程序运行过程中,已经不再需要使用的内存无法被释放,从而造成内存资源的良妃.内存泄漏会使得应用程序的内存使用量不断增加,最后可能导致系统内存耗尽,应用崩溃或者性能下降

得物-Golang-记一次线上服务的内存泄露排查_golang 解决线上问题-CSDN博客

 select和channel关键字

 select和channel是处理并发编程的两个重要工具

channels

是go语言提供的一种通信机制,用于在go之间传递数据,无需使用锁

类型:有缓冲的,无缓冲的

select

用于在多个channel中进行选择,类似于多路复用器

select会阻塞,直到其中一个case可以继续执行

default

select语句使得在多个channel上进行非阻塞和超时控制变得容易。

 关于Mysql的性能优化:

首先就是在资金充足的情况下,冲高性能服务器

在建表的时候:选择最合适的字段属性

尽量把字段设置为NOT NULL 这样查询的时候数据库不用比较NULL值

使用连接代替子查询 

  • MySQL以前是join几张表几个for循环嵌套,
  • 8.0做了优化将一张表存入内存减少循环嵌套
  • 子查询结果会在内存临时创建表存储,浪费资源

索引时使用最左前缀规则 (联合索引进行查询)

模糊查询不能利用索引

不要过多创建索引

  • 过多的索引会占用空间,且每次crud都会重建索引

索引长度尽量短

索引更新不能太频繁

避免使用select * 用什么查什么就好

合适的情况下,使用的合适的索引

数据量少的时候,全表扫描的速度比索引的速度快

开启慢查询日志

grpc是基于http几

http2,HTTP2提供了一些关键特性

多路复用:

  • 支持单个TCP连接上同时发送多个请求和响应,减少连接的开销和延迟

流量控制

  • 提供了更细粒度的流量控制,允许客户端和服务器控制数据流的速率和优先级,这对于高吞吐量和低延迟的通信非常的重要

头部压缩

  • http/2使用HPACK压缩算法对HTTP头部进行压缩,减少了请求和响应的大小,提高了传输效率

服务器推送

  • 可以在服务器请求之前发送资源

 介绍一下http1.0/http1.1/http2/http3

1.0

  • 单个请求响应模型
  • 无状态
  • 基本的缓存控制
  • 缺乏持久连接

1.1

  • 持久连接
  • 管道化
  • 更好的缓存控制
  • 分块传输编码
  • 带宽优化和内容协商

有队头阻塞问题

多请求复用单连接效果有限

2

  • 二进制分帧
  • 多路复用
  • 头部压缩
  • 服务器推送

3

  • 基于QUIC协议
  • 减少连接建立时间
  • 消除队头阻塞
  • 更快的握手过程
  • 改进丢包的处理

HTTP/1.0:简单的单请求-响应模型,适合早期Web应用。

HTTP/1.1:引入持久连接和更好的缓存机制,但仍存在队头阻塞问题。

HTTP/2:二进制分帧、多路复用和头部压缩显著提升性能。

HTTP/3:基于QUIC协议,通过UDP实现更快速和可靠的连接,进一步优化传输性能

 访问网页全过程:

用户输入url

DNS 解析:

  • 浏览器缓存
  • 操作系统缓存
  • 本地hosts文件
  • 递归DNS查询

TCP连接建立

三次握手

发送HTTP请求

服务器处理请求

请求解析

生成响应

服务器发送响应

  • 分片发送
  • 数据包处理

浏览器接收和渲染

数据包处理细节

  • ip数据包处理
  • TCP数据包处理
  • 数据包重组

TLS和SSL

如果是加密的三次握手之后要加上:

  • 客户端发送client Hello消息,包含支持加密算法和TLS版本
  • 服务器回应severHello消息,选择加密算法和TLS版本,并发送服务器证书
  • 客户端验证证书,发送Pre-Master Secret,双方生成会话密钥
  • 双方使用会话密钥进行加密通信

 常用的docker命令:

docker version

docker pull

docker exec -it bin/bash

docker-compose up

docker-compose down

docker-compose logs

docker-compose ps

docker ps

docker network ls

docker images

docker pull

docker push

docker build -t

docker rmi

docker run

docker start

restart stop rm logs

容器和镜像的关系,容器是镜像的一个实例

容器异常排查异常原因:

docker logs

dockers ps -a

进入容器进行查看

检查docker事件

docker events --since "1h"

显示过去一小时内的dockers事件日志

k8s管理docker

Docker 负责容器的创建、运行和管理,是容器化应用的基础。

Kubernetes 负责容器的编排和集群管理,提供了自动化部署、扩展和管理的功能。

k8s的基本概念

Master Node

  • Master Node

    :位于图的上方中央,用于管理和协调整个 Kubernetes 集群。它包含以下组件:

    • API Server:处理所有的 API 请求。
    • Scheduler:负责将 Pod 分配到适当的 Node。
    • Controller Manager:管理控制循环,确保集群处于期望状态。
    • etcd:存储集群的所有数据。

Node

  • Node

    :实际运行应用程序的工作节点。图中展示了三个 Node(Node 1、Node 2、Node N),每个 Node 上运行以下组件:

    • kubelet:管理该 Node 上的 Pod 和容器。
    • kube-proxy:处理 Pod 网络规则。
    • 容器运行时(如 Docker 或 containerd):实际运行容器。

Pod

  • Pod:Kubernetes 中的最小部署单元,每个 Node 上可以运行多个 Pod。图中展示了每个 Node 上运行的 Pod。

Namespace

  • Namespace:用于逻辑上隔离和组织资源的机制。图中展示了一个包含所有 Node 和 Pod 的虚线框表示的 Namespace。

Controller

  • Controller(如 Deployment、StatefulSet 等):通过自动化的控制循环管理 Pod 的生命周期。图中用箭头和文字标示在 Master Node 下方。

HPA (Horizontal Pod Autoscaler)

  • HPA:根据负载自动调整 Pod 的副本数,图中在中央用箭头和文字标示。

Service

  • Service:定义了一组 Pod 的逻辑集合,并提供稳定的访问方式。图中在右侧用箭头和文字标示。

 tcp拥塞控制

TCP拥塞控制是TCP协议中的一个重要功能,用于在网络拥塞时调整数据传输的速率,以避免网络拥塞进一步加剧或导致丢包。TCP拥塞控制主要通过四个算法来实现:

  1. 慢启动(Slow Start):TCP连接刚建立时,发送方会将拥塞窗口(Congestion Window)初始化为一个较小的值,然后随着时间的推移,拥塞窗口逐渐增加,指数增长,直到达到一个阈值(慢启动阈值)。
  2. 拥塞避免(Congestion Avoidance):一旦拥塞窗口的大小达到了慢启动阈值,TCP发送方就会进入拥塞避免阶段。在这个阶段,拥塞窗口的增长速率变为线性增长,而不再是指数增长,以避免过快地向网络注入数据。
  3. 快重传(Fast Retransmit):当发送方连续收到三个重复的确认(ACK)时,它会认为有一个数据包丢失,并立即重传该数据包,而不必等待超时发生。
  4. 快恢复(Fast Recovery):在快重传之后,TCP连接进入快恢复状态,拥塞窗口的大小会减半,然后采用拥塞避免的方式逐渐增加。

这些算法共同作用,使得TCP连接可以根据网络拥塞情况动态调整发送速率,从而维持网络的稳定性和公平性。

 进程线程协程三者

进程(Process)、线程(Thread)和协程(Coroutine)是计算机中用于实现并发执行的重要概念,它们分别在不同的层次和场景下提供了并发执行的机制。

  1. 进程(Process)

    • 进程是操作系统进行资源分配和调度的基本单位,每个进程有自己独立的地址空间和系统资源,包括内存、文件句柄、CPU时间等。
    • 进程之间通常是独立的,彼此隔离,不能直接访问对方的资源,通信需要通过进程间通信(IPC)机制来实现,比如管道、消息队列、共享内存等。
    • 创建和销毁进程的开销相对较大,因为需要为每个进程分配独立的地址空间和系统资源。
  2. 线程(Thread)

    • 线程是进程内的一个独立执行单元,多个线程共享相同的地址空间和系统资源,包括内存、文件句柄等。
    • 线程之间可以通过共享内存等方式进行通信,但需要考虑同步和互斥问题,以避免数据竞争和资源争用。
    • 创建和销毁线程的开销相对较小,因为它们共享所属进程的资源。
  3. 协程(Coroutine)

    • 协程是一种轻量级的线程,它可以在同一个线程中实现并发执行,通过协作式调度实现多个任务之间的切换。
    • 不同于线程的抢占式调度,协程是通过程序员主动让出执行权给其他协程来实现的,因此不需要进行显式的同步和互斥操作。
    • 协程通常用于高效的异步编程,可以有效地利用单个线程的资源,实现大规模并发,提高系统的响应速度和性能。

在实际应用中,开发者需要根据具体的需求和场景选择合适的并发模型。通常情况下,进程适用于需要隔离和安全性较高的场景,线程适用于需要共享资源和较小开销的场景,而协程适用于需要高效利用单个线程资源和实现大规模并发的场景。

三者区别:

进程(Process)、线程(Thread)和协程(Coroutine)都是用于并发执行的概念,它们之间有一些关键区别:

  1. 并发模型

    • 进程:进程是操作系统进行资源分配和调度的基本单位,每个进程有自己独立的地址空间和系统资源。进程之间通常通过进程间通信(IPC)进行通信。
    • 线程:线程是进程内的一个独立执行单元,多个线程共享相同的地址空间和系统资源。线程之间可以通过共享内存等方式进行通信,但需要考虑同步和互斥问题。
    • 协程:协程是一种轻量级的线程,它可以在同一个线程中实现并发执行。不同于线程的抢占式调度,协程是通过协作式调度实现的,即协程主动让出执行权给其他协程。
  2. 资源消耗

    • 进程:每个进程有自己独立的地址空间和系统资源,创建和销毁进程的开销较大。
    • 线程:线程共享所属进程的资源,包括内存、文件句柄等,创建和销毁线程的开销相对较小。
    • 协程:协程是在同一个线程内部执行,因此创建和销毁协程的开销很小。
  3. 并发性和并行性

    • 进程:不同进程之间是独立的,可以在多核处理器上实现真正的并行执行。
    • 线程:线程是进程内的执行单元,在单核处理器上通过线程切换实现并发执行,在多核处理器上也可以实现并行执行。
    • 协程:协程在同一个线程内部执行,不能利用多核处理器实现真正的并行执行,但通过协作式调度可以实现并发执行。
  4. 通信机制

    • 进程:进程之间通信通常通过进程间通信(IPC)机制,如管道、消息队列、共享内存等。
    • 线程:线程之间可以通过共享内存等方式进行通信,但需要考虑同步和互斥问题。
    • 协程:协程之间通常通过消息传递或共享数据进行通信,但由于是在同一个线程内部执行,通常不需要考虑同步和互斥问题。

总的来说,进程、线程和协程都是用于实现并发执行的机制,但它们的设计思想和适用场景有所不同,开发者需要根据具体的需求和场景选择合适的并发模型。