当前位置:   article > 正文

golang后端面试题总结_后端面试go

后端面试go

什么是goroutine?

Goroutine是Go语言中的轻量级线程,可以轻松地实现并发编程。Goroutine的调度是由Go语言运行时(runtime)进行管理的,可以自动地在多个线程之间分配任务。

什么是Go语言的协程(goroutine)?它与线程的区别是什么?

协程是一种轻量级的线程,它由Go语言内置的调度器进行管理。与传统的线程相比,协程的优势在于其轻量级、高效等特点。
在Go语言中,通过关键字go可以启动一个协程,它会自动地被调度器管理。协程之间的切换由调度器自动完成,无需用户手动干预。与传统线程不同,协程可以在不同的时间点进行中断和恢复,从而实现更灵活的并发。

什么是通道?

通道是一种在goroutines之间进行通信的机制,用于通过传输数据来同步两个或多个goroutine的执行。通道可以阻塞等待数据到来或被读取,提供了一种可靠的同步和数据传输方式。
channel底层实现:
channel 底层为环形队列(缓冲区),发送队列,接收队列,Mutex,close
channel使用场景:
协程间通信
停止信号
任务定时
解耦生产者和发送者
控制并发数
channel使用注意事项:
1、对未初始化(make)的 channel 进行读写操作,会产生死锁deadlock,关闭panic
2、当 for range 遍历 channel 时,如果发送者没有关闭 channel 或在 range 之后关闭,会导致 死锁
3、对于无缓冲区channel,读取和写入要配对出现,并且不能在同一个 goroutine 里
4、对于有缓冲区的channel,读写操作如果在同一个 goroutine 里,写数据操作一定在读数据操作前
在这里插入图片描述
添加链接描述

如何优化goroutine的性能?

为了优化goroutine的性能,可以使用有缓冲的通道、池化技术和调整goroutine数量等方式。有缓冲的通道可以减少通道的阻塞等待,池化技术可以减少goroutine的创建和销毁的开销,适当调整goroutine数量可以获得更好的并发性能。

避免创建过多的goroutine,可以通过池化技术来重用goroutine。
避免goroutine的阻塞,可以使用非阻塞的IO操作、使用带缓冲的通道、使用超时机制等方式来避免阻塞。
避免共享变量的竞争,可以使用sync包中的工具、使用原子操作、使用通道等方式来避免竞争。
避免过度调度,可以使用runtime包中的GOMAXPROCS函数来设置协程的最大数量,避免过度调度导致性能下降。
避免使用过多的锁,可以使用无锁数据结构、使用读写锁等方式来减少锁的竞争。

解释Go中race condition问题?

Race condition是指多个goroutine同时访问共享资源时可能会导致数据竞争和不确定的结果。在Go语言中可以使用互斥锁、条件变量和原子操作等机制来避免race condition的问题。

解释Go中的select语句?

select语句是Go语言中用于处理多路复用的工具,可以监视多个通道的状态,哪个通道有数据就从哪个通道中读取数据。
select语句由多个case语句组成,每个case语句对应一个通道的读取操作。当有多个通道都有数据时,select语句会随机选择一个通道读取数据。如果所有通道都没有数据,select语句会阻塞等待,直到有数据可读。
select语句可以用于实现超时控制、取消操作等场景,是Go语言中非常重要的语言特性之一。

解释mutex和rwmutex?

mutex是一种互斥锁,只能由一个协程持有,防止数据在多个协程间同时被修改而发生竞争问题。mutex基于操作系统的原子操作实现,因此效率较高,但只能用于单写多读的场景。在Go语言中,mutex可以通过sync包中的Mutex结构体来实现。
rwmutex是读写锁,允许多个协程同时读数据,但只能由一个协程写数据。读写锁通过读写锁计数器实现,读取时增加计数器,写入时需要等待计数器清零。在Go语言中,读写锁可以通过sync包中的RWMutex结构体来实现。

请解释WaitGroup?

WaitGroup是Go语言中用于等待一组协程执行完成的工具,可以用来同步协程之间的执行。WaitGroup包含一个计数器,当计数器的值为0时,表示所有协程已经执行完成,可以继续执行下一步操作。每个协程执行前需要调用Add方法增加计数器的值,执行完成后需要调用Done方法减少计数器的值。主协程通过调用Wait方法来等待计数器的值变为0。

Golang的map发生并发写会怎样?

golang 自带的map不是并发安全的,并发读写会报错
如果有并发场景需要自己加锁,或者使用sync包里的Map。

map查询时间复杂度如何分析

装载因子=填入表中的元素个数/散列表的长度,装载因子越大,说明空闲位置越少,冲突越多,散列表的性能会下降。

比较高八位:
为了提高哈希冲突时比较的速度,因为比较1个字节要比比较一个很长的key快,这时查找key的过程是先通过计算得到的哈希值定位到桶,然后依次遍历tophash和计算hash值的高8位是否相等,如果相等则说明元素大概率是找到了,这个时候再详细比较key是否完全一致即可
扩容条件
(1)负载因子 > 6.5时,也即平均每个bucket存储的键值对达到6.5个。
(2)当溢出桶过多时:

当 B < 15 时,如果overflow的bucket数量超过 2^B。
当 B >= 15 时,overflow的bucket数量超过 2^15
满足以上条件均会触发扩容机制。
扩容方案

等量扩容:

当一个桶中多次删除和增加数据之后,多次的hash冲突可能导致bmap的溢出桶很多,链表长度的增加导致扫描map的时间变长,而且浪费了大量存储空间。等量扩容实际上是针对这种情况对桶中数据做整理,把溢出桶中的数据向链表头搬迁,并删除空出来的overflow链表。这种情况下,元素会发生重排,但不会换桶。

增量扩容:

这种扩容发生在桶数量不够用时。具体步骤如下:

计算新的桶的数量:当键值对数量小于 1024 时,每次扩容增加一倍的桶;当键值对数量大于等于 1024 时,每次扩容增加 25%的桶。这个策略可以保证 map 在性能和空间利用率之间取得一个平衡;
为新的桶分配内存空间:使用 Go 的内存分配器(memory allocator)为新的桶分配内存空间;
将原来的桶中的键值对重新分配到新的桶中:对于每个桶,遍历桶中存储的所有键值对,计算键的哈希值,并根据新的桶数量计算出键对应的桶的位置;
插入键值对到新的桶中:将键值对插入到新的桶中,形成新的链表,并将新的链表连接到哈希表中;
释放原来的桶占用的内存空间:释放原来的桶占用的内存空间,这里需要注意的是,由于 Go 使用了指针指向键值对,所以在释放内存空间时需要注意先释放键值对,再释放链表,最后再释放桶。
考虑到如果map存储了数以亿计的key-value,一次性搬迁将会造成比较大的延时,Go采用逐步搬迁策略,即每次访问map时都会触发一次搬迁

删除
删除某个key的操作与分配类似,由于hashmap的存储结构是数组+链表,所以真正删除key仅仅是将对应的slot设置为empty,并没有减少内存在这里插入图片描述
在这里插入图片描述

Golang map Rehash的策略是怎样的?什么时机会发生Rehash

Rehash具体会影响什么?哈希结果会受到什么影响
Rehash过程中存放在旧桶的元素如何迁移

并发环境共享同一个map是安全的吗

不安全
加锁存在什么问题呢
sync.Map比加锁的方案好在哪里,底层数据结构什么样

如果想实现map线程安全,有两种方式:
方式一:使用读写锁 map + sync.RWMutex

方式二:使用golang提供的 sync.Map

sync.Map是用读写分离实现的,其思想是空间换时间。和map+RWLock的实现方式相比,它做了一些优化:可以无锁访问read map,而且会优先操作read map,倘若只操作read map就可以满足要求(增删改查遍历),那就不用去操作write map(它的读写都要加锁),所以在某些特定场景中它发生锁竞争的频率会远远小于map+RWLock的实现方式。

sync.Map

sync.map 使用场景
分析了sync.map我们发现,在读多写少的情况下,还是比较优秀的,相比常规map加锁那种肯定是更好的,但是写多读少的情况下,并不适合,因为还是涉及到频繁的加锁、read和dirty交换等开销,搞不好还比常规的map加锁性能更差。

在map的扩容(具体的扩容过程自行百度)中,会产生新桶并且会逐步的删除旧桶,在并发的读写map时极易导致程序读到已删除的旧桶,go的创始人预见了这种情况,所以严格的限制了对map的并发读写。那么有没有办法解决这种情况呢?也有,最简单的办法就是在读写的时候加锁,但是这样在并发量大的情况下会严重影响运行速度。
这时就可以用到sync.map了。

添加链接描述

Map的panic能被recover掉吗?了解panic和recover的机制吗

实际上不可以,看下map并发读写抛出的是什么,是不是普通的panic

添加链接描述
添加链接描述
添加链接描述

添加链接描述

sync.Map使用场景

sync.Map适用于读多写少的场景,因为写的次数过多会导致read map缓存失效,需要加锁,进而导致冲突变多;而且由于未命中read map次数过多,导致dirty map提升为read map,这是一个O(n)的操作,会进一步降低性能。

Map怎么知道自己处于竞争状态?是Go编码实现的还是底层硬件实现的?

通过结构体中的标志位实现的,可能是通过cas操作的

添加链接描述
添加链接描述

CAS具体怎么实现的

CAS,存在什么问题

添加链接描述

添加链接描述

请解释Go语言的堆栈大小?

栈默认:2k
Go 在 1.3 版本开始使用连续堆栈策略

添加链接描述
添加链接描述

请解释atomic包?

当我们想要对某个变量并发安全的修改,除了使用官方提供的 mutex,还可以使用 sync/atomic 包的原子操作,它能够保证对变量的读取或修改期间不被其他的协程所影响。

atomic 包的原子操作是通过 CPU 指令,也就是在硬件层次去实现的,性能较好,不需要像 mutex 那样记录很多状态。 当然,mutex 不止是对变量的并发控制,更多的是对代码块的并发控制,2 者侧重点不一样。

atomic 这些功能需要非常小心才能正确使用。 除了特殊的低级应用程序外,最好使用通道或同步包的工具来完成同步。 通过通信共享内存; 不要通过共享内存进行通信。

atomic 包有几种原子操作,主要是 Add、CompareAndSwap、Load、Store、Swap

添加链接描述
添加链接描述
添加链接描述

golang:实现并发控制的方法有哪些?比如waitGroup、context、channel,他们之间的区别和特点?

context如何实现的并发控制?具体怎么用?
Channel: 使用channel控制子协程,WaitGroup : 使用信号量机制控制子协程,Context: 使用上下文控制子协程。使用这三种机制中的一种或者多种可以达到并发控制很好的效果。

添加链接描述
添加链接描述

请解释context包?

Go 的 Context 的数据结构包含 Deadline,Done,Err,Value,Deadline 方法返回一个 time.Time,表示当前 Context 应该结束的时间,ok 则表示有结束时间,Done 方法当 Context 被取消或者超时时候返回的一个 close 的 channel,告诉给 context 相关的函数要停止当前工作然后返回了,Err 表示 context 被取消的原因,Value 方法表示 context 实现共享数据存储的地方,是协程安全的。context 在业务中是经常被使用的
其主要的应用 :

1:上下文控制,2:多个 goroutine 之间的数据交互等,3:超时控制:到某个时间点超时,过多久超时。
添加链接描述
添加链接描述

golang string是线程安全的吗?

不是
原文添加链接描述

Golang的make和new的区别和用法?

  1. new 和 make 都用于分配内存;
  2. new 和 make 都是在堆上分配内存;
  3. new 对指针类型分配内存,返回值是分配类型的指针,new也可以对 slice 、map、channel 分配内存;
  4. make 仅用于 slice、map和 channel 的初始化,返回值为类型本身,而不是指针;
    添加链接描述
    添加链接描述

defer

作用:defer延迟函数,释放资源,收尾工作;如释放锁,关闭文件,关闭链接;捕获panic;

避坑指南:defer函数紧跟在资源打开后面,否则defer可能得不到执行,导致内存泄露。

多个 defer 调用顺序是 LIFO(后入先出),defer后的操作可以理解为压入栈中

defer可以修改函数最终返回值,修改时机:有名返回值或者函数返回指针

defer、return、返回值三者的执行逻辑应该是:
return最先执行,return负责将结果写入返回值中;
接着defer开始执行一些收尾工作;
最后函数携带当前返回值(可能和最初的返回值不相同)退出。

golang发生panic退出时,实际上发生了什么

添加链接描述

golang的panic和error的区别和使用场景?发生panic如何捕获?捕获的范围是怎样的?

Golang有两种错误处理机制,分别是error和panic。

error一般是程序员可预知的,在意料之中的错误,会进行合适的处理,如打开件失败、检测输入是否合法等。而panic是不应该出现问题的地方出现了问题,程序员无法预知的异常,例如空指针或数组越界等。
添加链接描述
添加链接描述

GOMAXPROCS为什么设置的是P的数量?

添加链接描述
添加链接描述

golang 原生包json的序列化和反序列化有什么问题和坑点吗?

添加链接描述
添加链接描述
添加链接描述

GMP是怎么调度,channel是怎么收发消息的,channel的recq和g是怎么建立关系的

golang的GMP模型?M的数量有限制吗?P的数量?

work stealing机制
当M没有可运行的 G 时,尝试从其他线程M绑定的 P 偷取一半的G过来,而不是销毁线程。

work stealing机制触发:当前M线程的P本地队列中没有可运行的G时 并且 全局队列G中也没有可运行的G时,则会执行workstealing机制.

即:本地队列→ 全局队列→窃取
添加链接描述

gc算法有哪些

gc是在清理什么内容?堆还是栈?具体干了啥?

可达性分析

判断gcroots的原则是什么:
被栈上的指针引用
被全局变量指针引用
被寄存器中的指针引用

在这里插入图片描述
Go 的 GC 回收有三次演进过程,

Go V1.3 之前普通标记清除(mark and sweep)方法,整体过程需要启动 STW,效率极低。
GoV1.5 三色标记法,堆空间启动写屏障,栈空间不启动,全部扫描之后,需要重新扫描一次栈(需要 STW),效率普通。
GoV1.8 三色标记法+混合写屏障机制:栈空间不启动(全部标记成黑色),堆空间启用写屏障,整个过程不要 STW,效率高。
1.GC开始将栈上的对象全部扫描并标记为黑色(之后不再进行二次扫描,无需STW)
2.GC期间,任何在栈上创建的新对象,均为黑色
3.被删除的对象标记为灰色(不管堆还是栈)
4.被添加的对象标记为灰色

GC触发时机:分为系统触发和主动触发。
1)gcTriggerHeap:当所分配的堆大小达到阈值(由控制器计算的触发堆的大小)时,将会触发。
2)gcTriggerTime:当距离上一个 GC 周期的时间超过一定时间时,将会触发。时间周期以runtime.forcegcperiod 变量为准,默认 2 分钟。
3)gcTriggerCycle:如果没有开启 GC,则启动 GC。
4)手动触发的 runtime.GC 方法。

golang切片的扩容机制

如果期望容量大于当前容量的2倍,使用期望容量
如果当前切片长度小于1024,将容量翻倍
如果当前切片的长度大于1024,每次增加25%
切片扩容时,并发不安全,要加锁
添加链接描述
添加链接描述

读程序写结果

x := []int{1, 2, 3}
y := x[:2]
fmt.Println(len(y), cap(y)) //2 3
y = append(y, 50)
y = append(y, 60)
fmt.Println(x)
y[0] = 101
fmt.Println(x)
结果:
[1 2 50]
[1 2 50]

func main() {
aaa := make([]int, 2, 4)
test(aaa)
fmt.Println(aaa) //[100 0]
}
func test(slice []int) {
slice = append(slice, 1)
slice = append(slice, 2)
slice[0] = 100
fmt.Println(“1”, slice) // [100 0 1 2]

slice = append(slice, 3)
fmt.Println("3", slice) // [100 0 1 2 3]

slice[0] = 200
  • 1
  • 2
  • 3
  • 4

}

func main() {
aaa := make([]int, 2, 4)

fmt.Println(aaa) //[0 0]
aaa = append(aaa, 1)
aaa = append(aaa, 2)
fmt.Println(aaa) //[0 0 1 2]
bbb := aaa
aaa[0] = 100
fmt.Println(aaa) //[100 0 1 2]
fmt.Println(bbb) //[100 0 1 2]
aaa = append(aaa, 3)
aaa = append(aaa, 4)
aaa[1] = 200
fmt.Println(aaa) //[100 200  1 2 3 4]
fmt.Println(bbb) //[100 0 1 2]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

}

func main() {
a := make([]int, 3)
b := a
fmt.Printf(“address of slice %p \n”, &a) //address of slice 0xc0000a4018
fmt.Printf(“address of slice %p \n”, &b) //address of slice 0xc0000a4030
}

gin的内核与原理,所以说http.Request使用时语言注意什么?

1.gin框架路由使用前缀树,路由注册的过程是构造前缀树的过程,路由匹配的过程就是查找前缀树的过程。
2.gin框架的中间件函数和处理函数是以切片形式的调用链条存在的,我们可以顺序调用也可以借助c.Next()方法实现嵌套调用。
3.借助c.Set()和c.Get()方法我们能够在不同的中间件函数中传递数据。
原文添加链接描述

前缀树

在这里插入图片描述

谈谈内存泄露,什么情况下内存会泄露?怎么定位排查内存泄漏问题?

添加链接描述
添加链接描述
添加链接描述

golang,map,channel,用channel实现一个锁?实现一个并发安全map?数据库,熟悉底层吗?索引结构,数据库索引为什么是自增健?消息队列,怎么保证有序的?redis,熟悉底层吗?渐进式map了解吗?了解管道吗?

channel实现读写锁
添加链接描述

添加链接描述
添加链接描述
添加链接描述

Go 语言中不同的类型如何比较是否相等

在这里插入图片描述

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

Go 中 uintptr 和 unsafe.Pointer 的区别

unsafe.Pointer只是单纯的通用指针类型,用于转换不同类型的指针
它不可以参与指针运算;
不能读取内存存储的值,必须转换到某一类型的普通指针。

uintptr用于指针运算,GC 不把 uintptr 当指针,即 uintptr 无法持有对象, uintptr 类型的目标会被回收;
unsafe.Pointer 可以和 普通指针 进行相互转换;
unsafe.Pointer 可以和 uintptr 进行相互转换。

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

golang java python GC 对比

添加链接描述
添加链接描述
添加链接描述

解释型语言和编译型语言的区别?除了运行速度别的角度?生产效率?

添加链接描述
添加链接描述
添加链接描述

快排的原理;数组(奇数偶数)对于快排的影响,快排的空间复杂度

快速排序的时间复杂度,什么时候是性能最优的
原理:添加链接描述
通过一趟排序将要排序的数据分割成独立的两部分,其中一部分所有数据都比另一部分所有数据小,再按此方法对这两部分数分别进行快排(递归),使整个数据变为有序序列
时间复杂度:O(nlogn) ,不稳定的排序算法

package main
import(
 "fmt"
)
func main(){
 arr := []int{7,5,4,12,78,8,9,6,10,1,11}
 // arr := []int{5,3,2}
 fmt.Println("排序前数组:", arr)
 arr1 := quickSortFunc(arr, 0, len(arr)-1)
 fmt.Println("排序后数组:", arr1)
}

func quickSortFunc(arr []int, start int, end int) []int{
 if start < end{
  i,j := start, end
  index := arr[(start+end)/2]
  for i<=j {
   for arr[j] > index{
    j--
   }
   for arr[i] < index{
    i++
   }
   if i <= j{
    arr[i],arr[j] = arr[j], arr[i]
    i++
    j--
   }
  }
  if start < j{ //向左递归
   quickSortFunc(arr, start, j)
  }
  if end > i {//向右递归
   quickSortFunc(arr, i, end)
  }
 }
 return arr
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

快排的问题
最好的情况是枢纽元选取得当,每次都能均匀的划分序列。时间复杂度O(nlogn)
最坏情况是枢纽元为最大或者最小数字,那么所有数都划分到一个序列去了时间复杂度为O(n^2)

添加链接描述
添加链接描述
添加链接描述
添加链接描述

归并排序的应用场景、空间复杂度,又是多少?

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

手写堆排序

堆排序原理,如何在o(N)复杂度下建好堆
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

mysql面试题总结

添加链接描述

索引失效及联合索引生效总结

= 呢?
添加链接描述
添加链接描述
添加链接描述
在这里插入图片描述

MyISAM与InnoDB 的区别

1.InnoDB支持事务,MyISAM不支持
2. InnoDB支持外键,而MyISAM不支持。对一个包含外键的InnoDB表转为MYISAM会失败
3. InnoDB是聚集索引,使用B+Tree作为索引结构,数据文件是和(主键)索引绑在一起的(表数据文件本身就是按B+Tree组织的一个索引结构),必须要有主键,通过主键索引效率很高。但是辅助索引需要两次查询,先查询到主键,然后再通过主键查询到数据。因此,主键不应该过大,因为主键太大,其他索引也都会很大。
MyISAM是非聚集索引,也是使用B+Tree作为索引结构,索引和数据文件是分离的,索引保存的是数据文件的指针。主键索引和辅助索引是独立的
4. InnoDB支持表、行(默认)级锁,而MyISAM支持表级锁
InnoDB的行锁是实现在索引上的,而不是锁在物理行记录上。潜台词是,如果访问没有命中索引,也无法使用行锁,将要退化为表锁。
5.InnoDB表必须有唯一索引(如主键)(用户没有指定的话会自己找/生产一个隐藏列Row_id来充当默认主键),而MyISAM可以没有
6.InnoDB 不保存表的具体行数,执行 select count(*) from table 时需要全表扫描。
而MyISAM 用一个变量保存了整个表的行数,执行上述语句时只需要读出该变量即可,速度很快。
7.InnoDB 最小的锁粒度是行锁,MyISAM 最小的锁粒度是表锁。一个更新语句会锁住整张表,导致其他查询和更新都会被阻塞,因此并发访问受限。这也是 MySQL 将默认存储引擎从 MyISAM 变成 InnoDB 的重要原因之一

Mysql引擎,索引,b+树的结构,为什么b+树查询速度快

mysql索引?为什么用b+树?最左匹配?

b+树是怎么组织数据的,数据的顺序一定是从左到右递增的么

B+ 树的优点
1.由于B+树在非叶子结点上不包含真正的数据,只当做索引使用,因此在内存相同的情况下,能够存放更多的key;

2.B+树的叶子结点都是相连的,因此对整棵树的遍历只需要一次线性遍历叶子结点即可。而且由于数据顺序排列并且相连,所以便于区间查找和搜索。而B树则需要进行每一层的递归遍历。
B树的优点
由于B树的每一个节点都包含key和value,因此我们根据key查找value时,只需要找到key所在的位置,就能找到value,但B+树只有叶子结点存储数据,索引每一次查找,都必须一次一次,一直找到树的最大深度处,也就是叶子结点的深度,才能找到value。

B+树中的节点不存储数据,只是索引(即数据全部在叶子节点上),而B树中的节点存储数据
B树中的叶子节点,没有使用链表指针链接

B+树与B树相比,所有的数据都是放在叶子结点上的,这导致了:

(1)非叶子结点仅仅用于标识范围,所以查找过程不会像B树那样有可能在中途结束,而是每次必须查找到叶子结点。所以说,B+树比B树稳定。

(2)非叶子结点上不存储数据,所以盘块(存一个结点)上可以存储更多的向下索引。因此,B+树比B树更加矮胖,I/O次数会更少,这也是B+树查找性能优于B树的其中一个重要原因。
在这里插入图片描述

MyISAM 和 InnoDB 的区别
添加链接描述
Innodb索引
添加链接描述
b+树的结构
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
为什么b+树查找速度快
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

b和b+树的区别

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

聚簇索引和非聚簇索引区别

在 MySQL 的 InnoDB 引擎中,每个索引都会对应一颗 B+ 树,而聚簇索引和非聚簇索引最大的区别在于叶子节点存储的数据不同,聚簇索引叶子节点存储的是行数据,因此通过聚簇索引可以直接找到真正的行数据;而非聚簇索引叶子节点存储的是主键信息,所以使用非聚簇索引还需要回表查询,因此我们可以得出聚簇索引和非聚簇索引的区别主要有以下几个:

聚簇索引叶子节点存储的是行数据;而非聚簇索引叶子节点存储的是聚簇索引(通常是主键 ID)。
聚簇索引查询效率更高,而非聚簇索引需要进行回表查询,因此性能不如聚簇索引。
聚簇索引一般为主键索引,而主键一个表中只能有一个,因此聚簇索引一个表中也只能有一个,而非聚簇索引则没有数量上的限制。

添加链接描述

索引覆盖

覆盖索引(covering index ,或称为索引覆盖)即从非主键索引中就能查到的记录,而不需要查询主键索引中的记录,避免了回表的产生减少了树的搜索次数,显著提升性能。
如果一个索引包含(或覆盖)所有需要查询的字段的值,称为‘覆盖索引’。即只需扫描索引而无须回表。

MySQL两列,一列id一列A,范围查询A和id,哪个快?

我说id是主键,对应聚簇索引,包含整行数据,想要整行数据id快。如果只想要A的值,查询A快,通过A索引直接索引覆盖,就得到A单列数据了,但是通过聚簇索引的话会返回整行数据就会慢一些。

回表是什么

添加链接描述
添加链接描述
添加链接描述
添加链接描述

Myisam和Innodb索引上的区别

添加链接描述
添加链接描述
添加链接描述
添加链接描述

mysql的索引有哪些?innodb和其他myisam等引擎的区别

innodb与myisam区别及对应的使用场景

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

其他区别
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

SQL优化,优化方案,以及实际的优化

慢查询如何解决,索引优化

Mysql优化手段有哪些

慢查询怎么优化

(自动/手动)类型转换

(字符串类型必须带’'引号才能使索引生效)
字段是varchar,用整型进行查询时,无法走索引,如select * from user where phone = 13030303030;

Mysql 在执行上述语句时,会把字段转换为数字再进行比较,所以上面那条语句就相当于:select * from user where CAST(phone AS signed int) = 13030303030; CAST 函数是作用在了 phone 字段,而 phone 字段是索引,也就是对索引使用了函数!所以索引失效

字段是int,用string进行查询时,mysql会自动转化,可以走索引,如:select * from user where id = ‘1’;

MySQL 在遇到字符串和数字比较的时候,会自动把字符串转为数字,然后再进行比较。以上这条语句相当于:select * from user where id = CAST(“1” AS signed int),索引字段并没有用任何函数,CAST 函数是用在了输入参数,因此是可以走索引扫描的。

存储引擎不能使用索引中范围条件右边的列。

如这样的sql: select * from user where username=‘123’ and age>20 and phone=‘1390012345’,其中username, age, phone都有索引,只有username和age会生效,phone的索引没有用到。
SQL 性能优化 explain 中的 type:至少要达到 range 级别,要求是 ref 级别,如果可以是 consts 最好。

consts:单表中最多只有一个匹配行(主键或者唯一索引),在优化阶段即可读取到数据。

ref:使用普通的索引

range:对索引进行范围检索。

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

一条sql执行慢如何处理?

1、先设置慢查询(my.ini或数据库命令)

2、分析慢查询日志

3、定位低效率sql(show processlist)

4、explain分析执行计划(是否索引失效,用到索引没,用了哪些)
explain
在这里插入图片描述

5、优化(索引+sql语句+数据库结构优化+优化器优化+架构优化)

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

MySQL给你个SQL如何调优,有什么思路?

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

innodb为什么并发读取性能高

(1)常见并发控制保证数据一致性的方法有锁,数据多版本;

(2)普通锁串行,读写锁读读并行,数据多版本读写并行;

(3)redo日志保证已提交事务的ACID特性,设计思路是,通过顺序写替代随机写,提高并发;

(4)undo日志用来回滚未提交的事务,它存储在回滚段里;

(5)InnoDB是基于MVCC的存储引擎,它利用了存储在回滚段里的undo日志,即数据的旧版本,提高并发;

(6)InnoDB之所以并发高,快照读不加锁;

(7)InnoDB所有普通select都是快照读;
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

事务的隔离级别,分别解决的哪些问题

mysql隔离级别?可重复读是否解决了幻读问题?

Mysql事物的级别,哪种隔离级别会导致幻读

MySQL的事务隔离级别?每个级别如何实现的?

幻读举个例子

innodb如何解决幻读
1.脏读指的是一个事务读取到了另一个事务未提交的修改值;
2.不可重复读指的是一个事务对同一条数据,两次前后读取到的值不一样,这是因为在此期间有其他事务更新了该条数据;
3.幻读指的是一个事务,后一次的查询比前一次查询看到的数据多了,它特指读到了新的数据,需要与不可重复读的现象区分开来。
为了解决这些问题,SQL 标准(注意:这里说的是 SQL 标准)中定义了 4 种事务的隔离级来应对这些现象,分别是:读未提交、读提交、可重复读、串行化,它们的强度也依次递增。在这四种隔离级别下,它们的表现如下:
在这里插入图片描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

MySQL索引的数据结构,为啥B+树,不是B树?

b+树节点具体存的是什么

b+树什么样子为什么能实现范围查找

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

MySQL的日志有哪些?分别如何工作的?

MySQL的Redo Log和binLog的写入顺序?

redo-log、undo-log原理

undo里面具体存的是什么

redo log和binlog区别
redo log是属于innoDB层面,binlog属于MySQL Server层面的,这样在数据库用别的存储引擎时可以达到一致性的要求。
redo log是物理日志,记录该数据页更新的内容;binlog是逻辑日志,记录的是这个更新语句的原始逻辑
redo log是循环写,日志空间大小固定;binlog是追加写,是指一份写到一定大小的时候会更换下一个文件,不会覆盖。
binlog可以作为恢复数据使用,主从复制搭建,redo log作为异常宕机或者介质故障后的数据恢复使用。

undo log用于处理事务的回滚操作,同时可以提供多版本并发控制下的读(MVCC)。

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

数据库自增主键可能的问题

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

select * 会有什么问题

  1. 不需要的列会增加数据传输时间和网络开销

  2. 对于无用的大字段,如 varchar、blob、text,会增加 io 操作

  3. 失去MySQL优化器“覆盖索引”策略优化的可能性
    添加链接描述

MySQL server端命令用过什么

添加链接描述
添加链接描述

Mysql一页最大能存多少数据

添加链接描述
添加链接描述

数据库的事务是怎么实现的?

添加链接描述
添加链接描述
添加链接描述
添加链接描述

MVCC的实现原理

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

MySQL的版本、事务隔离级别,串行化的使用场景

MySQL 3.0:MySQL的早期版本,主要用于小型网站或简单的应用程序。它支持基本的SQL语句和索引,效率较低。
MySQL 4.0:MySQL的第一次重大更新,引入了存储过程、视图和触发器等高级功能,加快了数据的处理速度。
MySQL 5.0:MySQL的重大更新,引入了事务处理、ACID兼容性、存储过程和视图等功能,进一步提升了性能和安全性。
MySQL 5.1:MySQL的重要更新,提供了半同步复制、InnoDB存储引擎和分区等高级特性,同时提高了性能和可靠性。
MySQL 5.5:MySQL的稳定版本之一,引入了互联性API、查询性能优化、InnoDB存储引擎的更新、分区索引等特性,以提高性能和可靠性。
MySQL 5.6:MySQL的主要更新,引入了GIS、安全性、动态行等高级特性,为MySQL的未来提供了支持。
MySQL 5.7:MySQL的最新版本,引入了JSON数据格式支持、多源复制、性能和优化改进等关键特性,为开发人员提供了更好的工具和体验。

mysql版本
添加链接描述
添加链接描述
添加链接描述
串行化场景
添加链接描述

数据库的ACID讲一下

ACID一致性如何保证?

事务的(ACID)特性是由关系数据库管理系统(RDBMS,数据库系统)来实现的。数据库管理系统采用日志来保证事务的原子性、一致性和持久性。日志记录了事务对数据库所做的更新,如果某个事务在执行过程中发生错误,就可以根据日志,撤销事务对数据库已做的更新,使数据库退回到执行事务前的初始状态。

数据库管理系统采用锁机制来实现事务的隔离性。当多个事务同时更新数据库中相同的数据时,只允许持有锁的事务能更新该数据,其他事务必须等待,直到前一个事务释放了锁,其他事务才有机会更新该数据。
添加链接描述
添加链接描述

读锁和写锁区别

添加链接描述
添加链接描述

MySQL把2000W规模数据库内备份、库间备份的方式

添加链接描述
添加链接描述
添加链接描述

MySQL建表时,不指定主键,能否建表成功?

添加链接描述

外键的优缺点

添加链接描述

可重复读Innodb怎么实现的,Innodb有哪些索引,怎么建立的

可重复读怎么实现的
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

一千万数据大概多少次io

添加链接描述
添加链接描述

索引为什么能加快查询效率

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

乐观锁悲观锁互斥锁以及读写锁

乐观锁悲观锁区别?乐观锁如果出现了并发冲突一般怎么解决?(重试)自旋锁?(思路相似)

乐观锁悲观锁 乐观锁的锁机制(版本控制)

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

插入sql会使用到那些锁

添加链接描述

你们建表会定义自增id么,为什么,自增id用完了怎么办

添加链接描述

主从复制延时怎么解决

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

1000万的db数据分页怎么处理?

1.查询所有字段会导致主键索引多次访问数据块造成的I/O操作。

2.因此先查出偏移后的主键,再根据主键索引查询数据块的所有内容即可优化。
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

是否有遇到过锁表,说一次锁表的原因与如何解决的过程

添加链接描述
添加链接描述

如何预估一个mysql语句的性能

添加链接描述
添加链接描述

数据库会死锁吗,举一个死锁的例子mysql怎么解决死锁

mysql死锁问题排查思路

什么情况下产生死锁,怎么排查,怎么解决

死锁是并发系统中常见的问题,同样也会出现在数据库MySQL的并发读写请求场景中。当两个及以上的事务,双方都在等待对方释放已经持有的锁或因为加锁顺序不一致造成循环等待锁资源,就会出现“死锁”。

对于数据库的多表操作时,尽量按照相同的顺序进行处理,尽量避免同时锁定两个资源,如操作A和B两张表时,总是按先A后B的顺序处理, 必须同时锁定两个资源时,要保证在任何时刻都应该按照相同的顺序来锁定资源。

把SELECT放在Update语句前

SQL语句中不要使用太复杂的关联多表的查询;使用“执行计划”对SQL语句进行分析,对于有全表扫描的SQL语句,建立相应的索引进行优化。

所有的update和delete操作必须走唯一索引

避免事务中的用户等待交互
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

mysql删除数据,是立马就删除了吗

不是. delete 只是对数据做了删除标记, 之后异步线程会定时对数据做真实删除, 这么做的考虑是为了性能, 减少 io 操作.
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

mysql主从复制原理及常见问题和解决方案

从库生成两个线程,一个I/O线程,一个SQL线程;
i/o线程去请求主库 的binlog,并将得到的binlog日志写到relay log(中继日志) 文件中;
主库会生成一个 log dump 线程,用来给从库 i/o线程传binlog;
SQL 线程,会读取relay log文件中的日志,并解析成具体操作,来实现主从的操作一致,而最终数据一致;

1、异步复制
Mysql复制默认是异步的,主库在执行完客户端提交的事物后会立即将结果返回给客户端
数据安全性不高
2、半同步复制
介于异步复制和全同步复制之间,主库在执行完客户端提交的事物后不是立即返回给客户端,而是等待至少一个从库接收到并写到relaylog中才返回给客户端
3、全同步复制
当主库执行完一个事物,然后所有的从库都复制了该事物并成功执行完才返回成功信息给客户端

因为要等待所有从库执行完该事物才能返回成功信息,所有全同步复制的性能必然会受到严重的影响

添加链接描述
添加链接描述
添加链接描述
添加链接描述

mysql order by底层排序算法

添加链接描述
添加链接描述
添加链接描述
添加链接描述

间隙锁是什么,具体什么时候会加锁

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

MySQL怎么分页Offset过大有什么问题,怎么解决?

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

mysql多事物执行会产生哪些问题,怎么解决这些问题

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

MySQL数据库表数据量级

MySQL的使用的什么模式?主从还是集群模式?
添加链接描述
添加链接描述
添加链接描述
添加链接描述

插入一条数据发生了什么

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

Left join是怎么执行的

1、Left Join即保存左表的所有数据,然后和右表做连接操作,筛选出符合条件的数据,若右表中不存在左表对应的数据行,则该行右表相关字段置为空。

2、其实即执行原理可以视作,从左表(驱动表)逐行取出数据与右表(被驱动表)进行匹配,筛选出合理的数据。从这就可以看出,左表始终是逐行扫描的,但是右表却可以优化,如果在右表中的该连接字段上加了索引的话,那会极大的地提升执行速度。

3、所以引出了sql优化原则,小表驱动大表,被驱动表尽量带索引的原则。比如带有 in 的 sql 语句也是如此。

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

mysql数据量过大怎么办

当 MySQL 数据库中的单个表数据量变得过大时,有以下几种解决方法:

分表:将一个表拆分为多个表,并在应用程序中维护数据的一致性。

使用分区:将表数据按照某个字段值分成多个区间,每个区间存储在不同的文件中。

使用缓存:在应用程序中使用缓存技术来缓存经常使用的数据,减少对数据库的请求。

使用数据库集群:使用数据库集群技术来水平分布数据,减少单个数据库的压力。

使用预处理技术:对数据进行预处理,提高数据的查询效率。

以上是一些常见的解决方法,但并不适用于所有情况,根据实际情况选择合适的解决方法是非常重要的。
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

mysql多表联查的内连接外连接,join属于什么
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

数据库分库分表,横向与纵向的优缺点,横向分表后又该如何查询多表数据

分库分表

分表策略

聊一聊数据库分库分表,横向与纵向的优缺点,横向分表后又该如何查询多表数据

怎么分库分表才能均匀

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

文章下面的评论,按点赞数排序,SQL 怎么写

添加链接描述

把所有评论放到内存里,怎么设计数据结构,存储并排序

添加链接描述

where a > 1 and b = 2 and c<3怎么建立索引

拿bac和bca建立索引有什么区别吗

MySQL有一个SQL,A、B建立了联合索引,查询A=‘aaa’ 会用到索引吗? 查询A != ‘xxx’ 呢?

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

为什么有了MVCC还需要行级锁

limit(500,1000),什么样的原理?怎么优化?

用limit的时候我们要结合业务去优化,比方说我们可以利用limit的一些条件值筛选调大部分的数据比方说利用id>1000或者时间过滤
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

关系型数据库和非关系型数据库的区别

关系型数据库直接的差别是什么
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

Mysql的索引对比

mysql的索引类型 普通索引 主键 唯一索引 组合索引 全文索引 各自区别

索引作用优缺点

  1. 主键索引(Primary Key Index):主键索引是一种唯一索引,用于唯一标识一条记录。它是一种聚簇索引,数据行存储在主键索引的叶子节点上。主键索引可以提高查询速度和数据检索的效率。与其他索引相比,主键索引的查询速度最快,但它的缺点是它只能有一个主键。
  2. 唯一索引(Unique Index):唯一索引是一种索引,它确保索引列的值是唯一的。与主键索引不同,唯一索引允许 NULL 值。唯一索引的查询速度比普通索引快,但比主键索引慢一些。
  3. 普通索引(Normal Index):普通索引是最常见的索引类型。它可以加速查询,但不会强制要求唯一性或非空。普通索引可以用来加速 WHERE、JOIN 和 ORDER BY 子句。与唯一索引和主键索引相比,普通索引的查询速度较慢。
  4. 组合索引(Composite Index):组合索引是一种包含多个列的索引。它可以提高查询速度,尤其是在多个列上进行查询时。组合索引的查询速度比普通索引快,但比主键索引和唯一索引慢。

主键索引>唯一索引>组合索引>普通索引
总的来说,索引的类型和使用方式取决于具体的业务需求和数据结构。在设计索引时,需要考虑查询的频率、数据的大小、数据的更新频率等因素。

MySQL单表数据到达2000w,为什么就需要考虑分表?

Mysql数据为啥在千万级别会有性能问题?为啥不是百万级别?

数据量太大的话,SQL的查询就会变慢。如果一个查询SQL没命中索引,千百万数据量的表可能会拖垮这个数据库。
即使SQL命中了索引,如果表的数据量超过一千万的话,查询也是会明显变慢的。这是因为索引一般是B+树结构,数据千万级别的话,B+树的高度会增高,查询就变慢啦。
在InnoDB存储引擎中,B+树的高度一般为1-3层,就可以满足千万级数据的存储。
原文:添加链接描述

如何优化mysql的查询效率

原文添加链接描述

设计一个redis的存储,怎么能高访问量,且不丢失,还快

redis为什么会快

redis优点(为什么更快)基于内存,速度优于磁盘、网络模块单线程操作、I/O多路复用

1、基于内存实现
基于内存运行,数据都存储在内存里,减少了一些不必要的 I/O 操作,性能高效;
2、高效的数据结构
底层多种数据结构支持不同的数据类型,支持 Redis 存储不同的数据;
不同数据结构的设计,使得数据存储时间复杂度降到最低。
3、单线程在执行过程中不需要进行上下文切换,减少了耗时。也避免了线程竞争产生的死锁等问题。
4、使用I/O多路复用模型,同时监听客户端连接。

Redis运行在16核跟32核的机器上,性能有区别吗?

在这里插入图片描述
CPU 多核的场景下,用 taskset 命令把 Redis 实例和一个核绑定,可以减少 Redis 实例在不同核上被来回调度执行的开销,避免较高的尾延迟;
多 CPU 的 NUMA 架构下,把 Redis 实例和网络中断程序绑在同一个 CPU Socket 的不同核上,避免 Redis 跨 CPU Socket 访问内存中的网络数据的时间开销。

除了主线程,Redis 还有用于 RDB 和 AOF 重写的子进程,以及 4.0 版本之后提供的用于惰性删除的后台线程。Redis 实例和一个逻辑核绑定后,这些子进程和后台线程会和主线程竞争 CPU 资源,也会对 Redis 性能造成影响。
建议:
把按一个 Redis 实例一个物理核方式进行绑定,Redis 的主线程、子进程和后台线程可以共享使用一个物理核上的两个逻辑核。
在源码中增加绑核操作,把子进程和后台线程绑到不同的核上,避免对主线程的 CPU 资源竞争。Redis 6.0 支持 CPU 核绑定的配置操作了。

添加链接描述

Redis的持久化的方式?AOF是具体是怎样持久化日志的?RDB呢?用户反复修改一个数据,会怎样?AOF会不会膨胀?

Redis的持久化的方式?AOF和RDB是什么?结合实际思考有什么优缺点?

RDB:
bgsave会异步的执行备份,其实是fork出了一个子进程,用子进程去执行快照持久化操作,将数据保存在一个.rdb文件中。

子进程刚刚产生的时候,是和父进程共享内存中的数据的,但是子进程做持久化时,是不会修改数据的,而父进程是要持续提供服务的,所以父进程就会持续的修改内存中的数据,这个时候父进程就会将内存中的数据,Copy出一份来进行修改。(写时复制技术)

AOF重写:
AOF日志文件,随着时间的推移,会越来越大,所以就需要进行重写瘦身。AOF重写的原理就是,fork一个子进程,对内存进行遍历,然后生成一系列的Redis指令,然后序列化到一个新的aof文件中。然后再将遍历内存阶段的增量日志,追加到新的aof文件中,追加完成后立即替换旧的aof文件,这样就完成了AOF的瘦身重写。
重写的过程总结为“一个拷贝,两处日志”。
“一个拷贝”:
每次执行重写时,主线程 fork 出后台的 bgrewriteaof 子进程。此时,fork 会把主线程的内存拷贝一份给 bgrewriteaof 子进程,这里面就包含了数据库的最新数据。然后,bgrewriteaof 子进程就可以在不影响主线程的情况下,逐一把拷贝的数据写成操作,记入重写日志。
“两处日志”:
因为主线程未阻塞,仍然可以处理新来的操作。此时,如果有写操作,第一处日志就是指正在使用的 AOF 日志,Redis 会把这个操作写到它的缓冲区。这样一来,即使宕机了,这个 AOF 日志的操作仍然是齐全的,可以用于恢复。而第二处日志,就是指新的 AOF 重写日志。这个操作也会被写到重写日志的缓冲区。这样,重写日志也不会丢失最新的操作。等到拷贝数据的所有操作记录重写完成后,重写日志记录的这些最新操作也会写入新的 AOF 文件,以保证数据库最新状态的记录。此时,我们就可以用新的 AOF 文件替代旧文件了。

每次 AOF 重写时,Redis 会先执行一个内存拷贝,用于重写;然后,使用两个日志保证在重写过程中,新写入的数据不会丢失。而且,因为 Redis 采用额外的线程进行数据重写,所以,这个过程并不会阻塞主线程。

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

写时复制是如何实现的,原理

1、一般用于读多写少的情况,用于提高读取数据的效率
2、注意的是,读数据并不能保证实时性,因为读取时,读取的是旧数组的数据
3、缺点是:占用内存(每添加一次就需要复制一个数据)和数据一致性问题(不能保证实时数据)

写的时候会复制一份数据,等处理完毕会把新数组覆盖旧数组。

添加链接描述

主从复制原理

复制流程:
slave服务器连接到master服务器,便开始进行数据同步,发送psync命令。
master服务器收到psync命令之后,开始执行bgsave命令生成RDB快照文件并使用缓存区记录此后执行的所有写命令。
master服务器bgsave执行完之后,就会向所有Slava服务器发送快照文件,并在发送期间继续在缓冲区内记录被执行的写命令。
slave服务器收到RDB快照文件后,会将接收到的数据写入磁盘,然后清空所有旧数据,在从本地磁盘载入收到的快照到内存中,同时基于旧的数据版本对外提供服务。
master服务器发送完RDB快照文件之后,便开始向slave服务器发送缓冲区中的写命令。
slave服务器完成对快照的载入,开始接受命令请求,并执行来自主服务器缓冲区的写命令;
如果slave node开启了AOF,那么会立即执行BGREWRITEAOF,重写AOF。

1、主从关系建立后,从节点向主节点发送一个 SYNC 命令请求进行主从同步。
2、主节点收到 SYNC 命令后,执行 fork 创建一个子进程,子进程将所有的数据编码存储到 RDB(Redis Database) 文件中,这就产生了数据库的快照。
3、主节点将此快照发送给从节点,从节点接收快照并载入。
4、主节点接着将生成快照、发送快照期间积压的命令发送给从节点。
5、此后,主节点源源不断地新执行的写命令同步到从节点,从节点执行传播来的命令,命令执行后,从库中的数据也就得到了更新。如此,主从数据保持一致。需要说明的是,命令传播存在时延的,所以任意时刻,不能保证主从节点间数据完全一致。
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

缓存热 key 怎么解决

缓存热key怎么办

热key问题是指:突然有几十万甚至更大的请求去访问redis上的某个特定key。
如何找到热key?
1.凭借业务经验,进行预估哪些是热key

2.客户端统计收集,本地统计或者上报

3.如果服务端有代理层,可以在代理层进行收集上报
如何解决热key问题?
1.增加分片副本,分担读流量

2.热key备份,比如key,备份为key1,key2……keyN,同样的数据N个备份,N个备份分布到不同分片,访问时可随机访问N个备份中的一个,进一步分担读流量

3.使用本地缓存,发现热key后,将热key对应数据加载到应用服务器本地缓存中,访问热key数据时,直接从本地缓存中获取,而不会请求到redis服务器。

4.熔断限流保护

熔断限流也是极端情况下需要考虑的事情。面对高并发可以加一个对热点数据访问的限流熔断保护措施,限定缓存集群每秒最多的请求次数。防止缓存集群被干爆。

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

内存淘汰策略

定期删除
Redis会将每个设置了过期时间的key放入到一个独立的字典中,以后会定期遍历这个字典来删除到期的key。Redis默认每秒进行10次过期扫描(100ms一次,可以通过修改配置文件redis.conf 的 hz 选项来调整这个次数),但这个扫描并不会扫描过期字典中所有的key,而是通过一种贪心策略来随机筛选删除key,步骤如下:
从过期字典中随机选出20个key;
删除这20个key中已经过期的key;
如果过期的key的比例超过了1/4,那就重复从步骤1开始执行。

惰性删除
所谓惰性删除就是在客户端访问这个key的时候,Redis对key的过期时间进行检查,如果过期了就立即删除,然后返回null。
不管是定期删除还是惰性删除,都是一种不完全精确的删除策略,始终还是会存在已经过期的key无法被删除的场景。而且这两种过期策略都是只针对设置了过期时间的key,不适用于没有设置过期时间的key的淘汰,所以,Redis还提供了内存淘汰策略,用来筛选淘汰指定的key。

noeviction 策略:永不淘汰数据
volatile-ttl 在筛选时,会针对设置了过期时间的键值对,根据过期时间的先后进行删除,越早过期的越先被删除。
volatile-random 就像它的名称一样,在设置了过期时间的键值对中,进行随机删除。
volatile-lru 会使用 LRU 算法筛选设置了过期时间的键值对。
volatile-lfu 会使用 LFU 算法选择设置了过期时间的键值对。
allkeys-random 策略,从所有键值对中随机选择并删除数据;
allkeys-lru 策略,使用 LRU 算法在所有数据中进行筛选。
allkeys-lfu 策略,使用 LFU 算法在所有数据中进行筛选。

lru:按照最近最少使用的原则来筛选数据,按时间戳大小
lfu:LFU 缓存策略是在 LRU 策略基础上,为每个数据增加了一个计数器,来统计这个数据的访问次数。当使用 LFU 策略筛选淘汰数据时,首先会根据数据的访问次数进行筛选,把访问次数最低的数据淘汰出缓存。如果两个数据的访问次数相同,LFU 策略再比较这两个数据的访问时效性,把距离上一次访问时间更久的数据淘汰出缓存。

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

Redis单线程吗?为什么这么设计

redis是单线程还是多线程;slot听说过吗?跳表知道吗?

我们所说的Redis的单线程,不是指Redis程序真的只会有一个线程。这里所说的单线程,指的是Redis处理客户端发来的数据操作请求(增删改查),只会使用一个线程去执行。但是实际上,Redis在执行其他操作的时候,可能会开启多个进程或线程,比如说持久化。Redis执行BGSAVE指令,进行快照持久化时,就会fork出一个子进程,然后子进程去创建快照,完成持久化操作。
Redis将数据存放在内存当中,这也就意味着,Redis在操作数据时,不需要进行磁盘I/O。磁盘I/O是一个比较耗时的操作,所以对于需要进行磁盘I/O的程序,我们可以使用多线程,在某个线程进行I/O时,CPU切换到当前程序的其他线程执行,以此减少CPU的等待时间。而Redis直接操作内存中的数据,所以使用多线程并不能有效提升效率,相反,使用多线程反倒会因为需要进行线程的切换而降低效率。
使用多线程的话,多个线程间进行同步,保证线程的安全,也是需要开销的。尤其是Redis的数据结构都是一些实现较为简单的集合结构,若使用多线程,将会频繁地发生线程冲突,线程的竞争频率较高,反倒会拖慢Redis的响应速度。
添加链接描述
添加链接描述
添加链接描述

Redis的事物怎么处理的,怎么保证事物之间互不影响

原子性
首先Redis的事务一定能保证执行不会被中断。但Redis只能保证事务内命令要么全部执行,要么全部不执行,不能保证全部执行成功或全部执行失败,Redis事务是否具有原子性存在争议。
Redis 对事务原子性属性的保证情况小结:
命令入队时就报错,会放弃事务执行,保证原子性;
命令入队时没报错,实际执行时报错,不保证原子性;

一致性
Redis能够保证,Redis事务在开始前和结束后数据库的完整性不会被破坏,因此Redis事务具有一致性。

隔离性
Redis能够保证,当数据库中有多客户端同时执行事务时(并发),各事务间不会互相影响,在并发状态下执行的事务和串行时执行事务的结果完全相同,Redis事务具有隔离性。

持久性
Redis事务本身没有持久化的操作,但如果服务器开启了AOF或者RDB的持久化,可以认为Redis事务具有持久性。
添加链接描述
添加链接描述
添加链接描述
添加链接描述

Keys命令存在的问题

1、keys 命令时间复杂度是 O(n),n 即总的 key 数量,n 如果很大,性能非常低

2、redis 执行命令是单线程执行,一个命令执行太慢会阻塞其它命令,阻塞时间长甚至会让 redis 发生故障切换

3、可以使用 scan 命令替换 keys 命令

    1.虽然 scan 命令的时间复杂度仍是 O(n),但它是通过游标分步执行,不会导致长时间阻塞

    2.可以用 count 参数提示返回 key 的个数

    3.返回值代表下次的起点(桶下标)
  • 1
  • 2
  • 3
  • 4
  • 5

添加链接描述
添加链接描述
添加链接描述
添加链接描述

redis的hashtable是怎么扩容的

Hash的扩容

为了使 rehash 操作更高效,Redis 默认使用了两个全局哈希表:哈希表 1 和哈希表 2。一开始,当你刚插入数据时,默认使用哈希表 1,此时的哈希表 2 并没有被分配空间。随着数据逐步增多,Redis 开始执行 rehash,这个过程分为三步:
1.给哈希表 2 分配更大的空间,例如是当前哈希表 1 大小的两倍;
2.把哈希表 1 中的数据重新映射并拷贝到哈希表 2 中;
3.释放哈希表 1 的空间。
Redis 采用了渐进式 rehash。简单来说就是在第二步拷贝数据时,Redis 仍然正常处理客户端请求,每处理一个请求时,从哈希表 1 中的第一个索引位置开始,顺带着将这个索引位置上的所有 entries 拷贝到哈希表 2 中;等处理下一个请求时,再顺带拷贝哈希表 1 中的下一个索引位置的 entries。如下图所示:在这里插入图片描述

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

redis数据结构原理

Redis各数据结构实现原理

Redis的数据结构和底层实现,各自应用场景

Redis常见的数据结构,Zset的实现,为什么跳表?

redis的set底层什么时候是hash,什么时候是跳表

跳表具体是怎么实现的

跳表每一层跳的个数
Redis底层数据结构主要包括简单动态字符串(SDS)、链表、字典、跳跃表、整数集合和压缩列表六种类型,并且基于这些基础数据结构实现了字符串对象、列表对象、哈希对象、集合对象以及有序集合对象五种常见的对象类型。每一种对象类型都至少采用了2种数据编码,不同的编码使用的底层数据结构也不同。

在这里插入图片描述
zset的两种实现方式
ziplist(压缩列表):满足以下两个条件的时候

元素数量少于128的时候
每个元素的长度小于64字节
skiplist(跳跃链表):不满足上述两个条件任一个就会使用跳表

压缩列表
压缩列表实际上类似于一个数组,数组中的每一个元素都对应保存一个数据。和数组不同的是,压缩列表在表头有三个字段 zlbytes、zltail 和 zllen,分别表示列表长度、列表尾的偏移量和列表中的 entry 个数;压缩列表在表尾还有一个 zlend,表示列表结束。
1.zlbytes:32位无符号整形,记录ziplist整个结构体的占用空间大小。当然了也包括 zlbytes 本身。这个结构有个很大的用处,就是当需要修改 ziplist 时候不需要遍历即可知道其本身的大小。
2.zltail: 32 位无符号整型, 记录整个 ziplist 中最后一个 entry 的偏移量。所以在尾部进行 POP 操作时候不需要先遍历一次。
3.zllen: 16 位无符号整型, 记录 entry 的数量, 所以只能表示 2^16。但是 Redis 作了特殊的处理:当实体数超过 2^16 ,该值被固定为 2^16 - 1。 所以这种时候要知道所有实体的数量就必须要遍历整个结构了。
4.entry: 真正存数据的结构。
5.zlend: 8 位无符号整型, 固定为 255 (0xFF)。为 ziplist 的结束标识。
在这里插入图片描述
在压缩列表中,如果我们要查找定位第一个元素和最后一个元素,可以通过表头三个字段的长度直接定位,复杂度是 O(1)。而查找其他元素时,就没有这么高效了,只能逐个查找,此时的复杂度就是 O(N) 了。
跳表在这里插入图片描述
跳表是在双向链表之上加多层索引构成,相对于双向链表支持快速查找,更新,删除。在查找某一个数据时,先在索引里面查找出一个大范围,然后再下降到原始链表中精确查找,因为加上一层索引后查找一个节点需要遍历的次数减少了,所以查找效率大大提升(用空间换时间)。
针对链表长度比较大的时候,构建索引查找效率的提升就会非常明显。
特点:
1.有很多层结构,由原始“链表”和一些通过“跳跃”生成的链表组成
2.每一层都是一个有序的链表
3.最底层的链表包含所有元素,越上层“跳跃”的越高,元素(索引)越少
4.查找时从顶层向下,不断缩小搜索范围
5.上层链表是下层链表的子序列
6.每个节点包含两个指针,一个指向同一个链表中的下一个元素,一个指向下面一层的元素
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

Redis听过大Key吗?会有什么问题?

redis出现大key怎么解决

以下是几种常见的解决方法:

分割大 key:将大 key 拆分成多个小 key 来存储数据。例如,如果一个大型哈希表存储了大量的数据,可以将它拆分成多个小的哈希表,每个哈希表存储一部分数据。这样可以降低每个 key 的大小,并使 Redis 更加稳定和高效。

使用适当的数据结构:选择适当的 Redis 数据结构,以减少单个 key 的大小。例如,如果要存储大量元素,应该使用 Redis 集合或有序集合,而不是使用列表。

定期清理数据:定期清理 Redis 中的过期数据和不必要的数据,以避免大 key 的大小增长。可以使用 Redis 内置的过期机制或手动清理不必要的数据。

压缩数据:使用 Redis 的数据压缩功能,将大 key 中的数据进行压缩,可以减少每个 key 的大小,从而提高 Redis 的性能和可用性。

按需加载数据:不要在一次性将整个大 key 加载到内存中,而是按需加载数据,可以降低 Redis 的内存使用率,从而提高性能。

怎么解决大key
拆分成多个小key。这是最容易想到的办法,降低单key的大小,读取可以用mget批量读取。

数据压缩。使用String类型的时候,使用压缩算法减少value大小。或者是使用Hash类型存储,因为Hash类型底层使用了压缩列表数据结构。

设置合理的过期时间。为每个key设置过期时间,并设置合理的过期时间,以便在数据失效后自动清理,避免长时间累积的大Key问题。

启用内存淘汰策略。启用Redis的内存淘汰策略,例如LRU(Least Recently Used,最近最少使用),以便在内存不足时自动淘汰最近最少使用的数据,防止大Key长时间占用内存。

数据分片。例如使用Redis Cluster将数据分散到多个Redis实例,以减轻单个实例的负担,降低大Key问题的风险。

删除大key。使用UNLINK命令删除大key,UNLINK命令是DEL命令的异步版本,它可以在后台删除Key,避免阻塞Redis实例。

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

string和hash的存储有什么区别

适合用 String 存储的情况:
每次需要访问大量的字段
存储的结构具有多层嵌套的时候

适合用 Hash 存储的情况:
在大多数情况中只需要访问少量字段
自己始终知道哪些字段可用,防止使用 mget 时获取不到想要的数据
添加链接描述
添加链接描述

redis实现分布式锁,存在什么问题,怎么解决

基于Redis的分布式锁

Redis怎么实现的分布式锁

Redis实现分布式锁的方案?存在的问题?使用超时解决的问题?

基于单个 Redis 节点实现分布式锁
Redis 给 SET 命令提供了类似的选项 NX,用来实现“不存在即设置”。如果使用了 NX 选项,SET 命令只有在键值对不存在时,才会进行设置,否则不做赋值操作。此外,SET 命令在执行时还可以带上 EX 或 PX 选项,用来设置键值对的过期时间。
举个例子,执行下面的命令时,只有 key 不存在时,SET 才会创建 key,并对 key 进行赋值。另外,key 的存活时间由 seconds 或者 milliseconds 选项值来决定。
在这里插入图片描述
有了 SET 命令的 NX 和 EX/PX 选项后,我们就可以用下面的命令来实现加锁操作了。
在这里插入图片描述
其中,unique_value 是客户端的唯一标识,可以用一个随机生成的字符串来表示,PX 10000 则表示 lock_key 会在 10s 后过期,以免客户端在这期间发生异常而无法释放锁。
因为在加锁操作中,每个客户端都使用了一个唯一标识,所以在释放锁操作时,我们需要判断锁变量的值,是否等于执行释放锁操作的客户端的唯一标识,如下所示:
在这里插入图片描述
这是使用 Lua 脚本(unlock.script)实现的释放锁操作的伪代码,其中,KEYS[1]表示 lock_key,ARGV[1]是当前客户端的唯一标识,这两个值都是我们在执行 Lua 脚本时作为参数传入的。

基于多个 Redis 节点实现高可靠的分布式锁
为了避免 Redis 实例故障而导致的锁无法工作的问题,Redis 的开发者 Antirez 提出了分布式锁算法 Redlock。
Redlock 算法的基本思路,是让客户端和多个独立的 Redis 实例依次请求加锁,如果客户端能够和半数以上的实例成功地完成加锁操作,那么我们就认为,客户端成功地获得分布式锁了,否则加锁失败。这样一来,即使有单个 Redis 实例发生故障,因为锁变量在其它实例上也有保存,所以,客户端仍然可以正常地进行锁操作,锁变量并不会丢失。
Redlock 算法的实现需要有 N 个独立的 Redis 实例。接下来,我们可以分成 3 步来完成加锁操作。
第一步是,客户端获取当前时间。
第二步是,客户端按顺序依次向 N 个 Redis 实例执行加锁操作。
这里的加锁操作和在单实例上执行的加锁操作一样,使用 SET 命令,带上 NX,EX/PX 选项,以及带上客户端的唯一标识。当然,如果某个 Redis 实例发生故障了,为了保证在这种情况下,Redlock 算法能够继续运行,我们需要给加锁操作设置一个超时时间。
如果客户端在和一个 Redis 实例请求加锁时,一直到超时都没有成功,那么此时,客户端会和下一个 Redis 实例继续请求加锁。加锁操作的超时时间需要远远地小于锁的有效时间,一般也就是设置为几十毫秒。
第三步是,一旦客户端完成了和所有 Redis 实例的加锁操作,客户端就要计算整个加锁过程的总耗时。
客户端只有在满足下面的这两个条件时,才能认为是加锁成功。
条件一:客户端从超过半数(大于等于 N/2+1)的 Redis 实例上成功获取到了锁;
条件二:客户端获取锁的总耗时没有超过锁的有效时间。
在满足了这两个条件后,我们需要重新计算这把锁的有效时间,计算的结果是锁的最初有效时间减去客户端为获取锁的总耗时。如果锁的有效时间已经来不及完成共享数据的操作了,我们可以释放锁,以免出现还没完成数据操作,锁就过期了的情况。
当然,如果客户端在和所有实例执行完加锁操作后,没能同时满足这两个条件,那么,客户端向所有 Redis 节点发起释放锁的操作。
在 Redlock 算法中,释放锁的操作和在单实例上释放锁的操作一样,只要执行释放锁的 Lua 脚本就可以了。这样一来,只要 N 个 Redis 实例中的半数以上实例能正常工作,就能保证分布式锁的正常工作了。
所以,在实际的业务应用中,如果你想要提升分布式锁的可靠性,就可以通过 Redlock 算法来实现。
在这里插入图片描述
在第2步已经成功获取到锁后,由于GC时间超过锁过期时间,导致GC完成后其他客户端也能够获取到锁,此时2个客户端都会持有锁。就会有问题。
这个问题无论是redlock还是zookeeper都会有这种问题。不做业务上的兜底操作就没得解。
时钟漂移问题也只能是尽量避免吧。无法做到根本解决。

添加链接描述
添加链接描述

哈希分区算法有哪些

节点取余分区
一致性hash算法
虚拟槽hash
添加链接描述

Redis的list用作消息队列,和Kafka相比有什么区别

Redis使用MQ做同步是否有问题?

1)redis是内存数据库,只是它的list数据类型刚好可以用作消息队列而已
kafka是消息队列,消息的存储模型只是其中的一个环节,还提供了消息ACK和队列容量、消费速率等消息相关的功能,更加完善
2)redis 发布订阅除了表示不同的 topic 外,并不支持分组
kafka每个consumer属于一个特定的consumer group(default group), 同一topic的一条消息只能被同一个
consumer group内的一个consumer消费,但多个consumer group可同时消费这一消息。
3) 处理数据大小的级别不同
4)kafka消费了之后,可以重新消费。redis消费(lpop)了数据之后,数据就从队列里消失了。
添加链接描述
添加链接描述
添加链接描述
添加链接描述

Redis集群方式了解吗?用的什么方式呢?

Redis如果存储已经满了继续存会发生什么?

如果 Redis 的内存用完了,可能会发生以下几种情况:
1、Redis 会停止接收新的写入请求:当 Redis 的内存用尽时,它将停止接收新的写入请求,而只能处理读取请求。这是因为 Redis 无法将新的数据写入内存中。
2、Redis 会开始执行淘汰策略:Redis 会尝试执行配置的淘汰策略,从而释放一些内存,以容纳新的数据。例如,当使用 LRU 策略时,Redis 会删除最近最少使用的键,以腾出内存空间。
3、Redis 可能会出现性能下降:当 Redis 的内存使用率接近满负荷时,读取操作可能会变得更加缓慢,因为 Redis 需要将一些数据从内存中换出到磁盘上。 Redis 可能会崩溃:
4、当 Redis 的内存完全耗尽时,Redis 会停止服务并崩溃,导致数据丢失和服务中断。为了避免这种情况,建议对 Redis 的内存使用情况进行监控,并在内存接近满负荷时采取相应的措施,如增加内存容量或使用更高效的数据结构等。

redis 的expire底层实现原理

设置数据过期时间的命令一共有 4 个,我们可以把它们分成两类:
EXPIRE 和 PEXPIRE:它们给数据设置的是从命令执行时开始计算的存活时间;
EXPIREAT 和 PEXPIREAT:它们会直接把数据的过期时间设置为具体的一个时间点。

在这里插入图片描述
当主从库全量同步时,如果主库接收到了一条 EXPIRE 命令,那么,主库会直接执行这条命令。这条命令会在全量同步完成后,发给从库执行。而从库在执行时,就会在当前时间的基础上加上数据的存活时间,这样一来,从库上数据的过期时间就会比主库上延后了。
为了避免这种情况,我给你的建议是,在业务应用中使用 EXPIREAT/PEXPIREAT 命令,把数据的过期时间设置为具体的时间点,避免读到过期数据。
对于读到过期数据,这是可以提前规避的,一个方法是,使用 Redis 3.2 及以上版本;另外,你也可以使用 EXPIREAT/PEXPIREAT 命令设置过期时间,避免从库上的数据过期时间滞后。不过,这里有个地方需要注意下,因为 EXPIREAT/PEXPIREAT 设置的是时间点,所以,主从节点上的时钟要保持一致,具体的做法是,让主从节点和相同的 NTP 服务器(时间服务器)进行时钟同步。

数据库和redis数据一致性如何保持

添加链接描述
“一致性”包含了两种情况:
缓存中有数据,那么,缓存的数据值需要和数据库中的值相同;
缓存中本身没有数据,那么,数据库中的值必须是最新值。
不符合这两种情况的,就属于缓存和数据库的数据不一致问题了。
对于读写缓存来说,要想保证缓存和数据库中的数据一致,就要采用同步直写策略。
对于只读缓存来说,如果有数据新增,会直接写入数据库;而有数据删改时,就需要把只读缓存中的数据标记为无效。这样一来,应用后续再访问这些增删改的数据时,因为缓存中没有相应的数据,就会发生缓存缺失。此时,应用再从数据库中把数据读入缓存,这样后续再访问数据时,就能够直接从缓存中读取了。

给你介绍一种方法:重试机制。
具体来说,可以把要删除的缓存值或者是要更新的数据库值暂存到消息队列中(例如使用 Kafka 消息队列)。当应用没有能够成功地删除缓存值或者是更新数据库值时,可以从消息队列中重新读取这些值,然后再次进行删除或更新。如果能够成功地删除或更新,我们就要把这些值从消息队列中去除,以免重复操作,此时,我们也可以保证数据库和缓存的数据一致了。否则的话,我们还需要再次进行重试。如果重试超过的一定次数,还是没有成功,我们就需要向业务层发送报错信息了。
刚刚说的是在更新数据库和删除缓存值的过程中,其中一个操作失败的情况,实际上,即使这两个操作第一次执行时都没有失败,当有大量并发请求时,应用还是有可能读到不一致的数据。
同样,我们按照不同的删除和更新顺序,分成两种情况来看。在这两种情况下,我们的解决方法也有所不同。
情况一:先删除缓存,再更新数据库。
假设线程 A 删除缓存值后,还没有来得及更新数据库(比如说有网络延迟),线程 B 就开始读取数据了,那么这个时候,线程 B 会发现缓存缺失,就只能去数据库读取。这会带来两个问题:
线程 B 读取到了旧值;
2.线程 B 是在缓存缺失的情况下读取的数据库,所以,它还会把旧值写入缓存,这可能会导致其他线程从缓存中读到旧值。
等到线程 B 从数据库读取完数据、更新了缓存后,线程 A 才开始更新数据库,此时,缓存中的数据是旧值,而数据库中的是最新值,两者就不一致了。
这该怎么办呢?我来给你提供一种解决方案。在线程 A 更新完数据库值以后,我们可以让它先 sleep 一小段时间,再进行一次缓存删除操作。
之所以要加上 sleep 的这段时间,就是为了让线程 B 能够先从数据库读取数据,再把缺失的数据写入缓存,然后,线程 A 再进行删除。所以,线程 A sleep 的时间,就需要大于线程 B 读取数据再写入缓存的时间。这个时间怎么确定呢?建议你在业务程序运行的时候,统计下线程读数据和写缓存的操作时间,以此为基础来进行估算。
这样一来,其它线程读取数据时,会发现缓存缺失,所以会从数据库中读取最新值。因为这个方案会在第一次删除缓存值后,延迟一段时间再次进行删除,所以我们也把它叫做“延迟双删”。
情况二:先更新数据库值,再删除缓存值。
如果线程 A 删除了数据库中的值,但还没来得及删除缓存值,线程 B 就开始读取数据了,那么此时,线程 B 查询缓存时,发现缓存命中,就会直接从缓存中读取旧值。不过,在这种情况下,如果其他线程并发读缓存的请求不多,那么,就不会有很多请求读取到旧值。而且,线程 A 一般也会很快删除缓存值,这样一来,其他线程再次读取时,就会发生缓存缺失,进而从数据库中读取最新值。所以,这种情况对业务的影响较小。

渐进式Rehash的时候会影响主流程吗

不影响
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

redis集群在扩容过程中(rehash)读写会有什么影响?

扩缩容过程中,客户端访问某个redis节点的key不存在,节点会返回move信息给到客户端,客户端根据move信息请求到新节点获取key
原文添加链接描述

过期键的删除策略

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

内存淘汰策略有哪些

添加链接描述
添加链接描述
添加链接描述
添加链接描述

redis是怎么标记失效的

redis存储一个key具体做了什么

添加链接描述
添加链接描述

redis用了什么数据结构,项目里的

Redis 键值对中的每一个值都是用 RedisObject 保存的。RedisObject 包括元数据和指针。其中,元数据的一个功能就是用来区分不同的数据类型,指针用来指向具体的数据类型的值。
Redis 的基本对象结构
RedisObject 的内部组成包括了 type、encoding、lru 和 refcount 4 个元数据,以及 1 个*ptr指针。
type:表示值的类型,涵盖了我们前面学习的五大基本类型;
encoding:是值的编码方式,用来表示 Redis 中实现各个基本类型的底层数据结构,例如 SDS、压缩列表、哈希表、跳表等;
lru:记录了这个对象最后一次被访问的时间,用于淘汰过期的键值对;
refcount:记录了对象的引用计数;
ptr:是指向数据的指针。
RedisObject 结构借助
ptr指针,就可以指向不同的数据类型,例如,ptr指向一个 SDS 或一个跳表,就表示键值对中的值是 String 类型或 Sorted Set 类型。所以,我们在定义了新的数据类型后,也只要在 RedisObject 中设置好新类型的 type 和 encoding,再用ptr指向新类型的实现,就行了。
在这里插入图片描述

什么是缓存击穿?怎么避免?什么是布隆过滤器?怎么实现?过滤有还是过滤的无?

缓存穿透,访问大量不存在redis也不存在于数据库的数据

解决措施,缓存空对象、布隆过滤器
布隆过滤器的压力大怎么办

Redis:缓存雪崩

缓存雪崩
当某⼀时刻发⽣⼤规模的缓存失效的情况,例如缓存服务宕机、大量key在同一时间过期,这样的后果就是⼤量的请求进来直接打到DB上,可能导致整个系统的崩溃,称为雪崩。
可能的原因:
redis宕机、重启
大量数据使用了同一过期时间
解决方法:
引入随机性,在原有缓存失效时间上加上一个随机值,避免大量数据在同一时间失效。
通过请求限流、熔断机制、服务降级等手段,降低服务器负载。
实现缓存组件的高可用,防止单点故障、机器故障、机房宕机等一系列问题。
提高数据后台数据库的容灾能力。

缓存击穿
当Redis中存在某些极热点数据时,即有大量请求并发访问的key-value数据。当极热点key-value数据突然失效时,缓存未命中引起对后台数据库的频繁访问,这种现象叫缓存击穿。
引起的原因:
缓存上极热点数据突然失效
解决办法:
对极热点key设置永不过期
使用互斥锁。如果缓存失效的情况,只有拿到锁才可以查询数据库,降低了在同一时刻访问数据库的请求量,防止数据库崩溃。缺点是会导致系统的性能变差。

缓存穿透
当有大量查询请求未命中缓存时,引起对后台数据库的频繁访问,导致数据库负载压力增大,这种现象就叫做缓存穿透。
引起的原因:
黑客大量访问不存在的key,导致数据库处理大量请求
1、将无效的key存进Redis中,若果数据库查询某个key不存在时,同样将这个key缓存到Redis缓存中,并设置value为NULL,表示不存在。如果攻击请求的key每次都相同,该方法有效;如果攻击请求的key每次随机生成,则同样会产生缓存穿透问题。
2、使用布隆过滤器,过滤掉一些不存在的key。布隆过滤器判定为true时,key可能存在于数据库中,也可能不存在;判定为false时,key一定不存在于数据库。
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

用过redis吗?redis有哪些应用场景?

Redis使用场景 订单的查询

Redis应用场景有哪些,你在项目中应用了哪些场景

1、缓存
2、消息队列
3、分布式锁
4、位统计(bitmap)
5、排行榜
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

哈希表为什么查找复杂度是常数?

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

redis数据结构,怎么保证数据不丢失?

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

Redis高可用的三种实现方式

添加链接描述

公司的Redis的集群模式有了解吗?

是否使用过Redis集群,集群的原理是什么

集群模式
集群模式,实现分布式存储,每个节点存储不同的内容。集群部署的方式能自动将数据进行分片,每个master上放一部分数据,提供了内置的高可用服务,即使某个master宕机了,服务还可以正常地提供
集群模式中数据通过数据分片的方式被自动分割到不同的master节点上,每个Redis集群有16384个哈希槽,进行set操作时,每个key会通过CRC16校验后再对16384取模来决定放置在哪个槽。数据在集群模式中是分开存储的,那么节点之间想要知道其他节点的状态信息,包括当前集群状态、集群中各节点负责的哈希槽、集群中各节点的master-slave状态、集群中各节点的存活状态等是通过建立TCP连接,使用gossip协议来进行集群信息传播。

​ 故障判断方法:判断故障的逻辑其实与哨兵模式有点类似,在集群中,每个节点都会定期的向其他节点发送ping命令,通过有没有收到回复来判断其他节点是否已经下线。具体方法是采用半数选举机制,当A节点发现目标节点疑似下线,就会向集群中的其他节点散播消息,其他节点就会向目标节点发送命令,判断目标节点是否下线。如果集群中半数以上的节点都认为目标节点下线,就会对目标节点标记为下线,从而告诉其他节点,让目标节点在整个集群中都下线。

优点:

无中心结构,部署简单。所有的Redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽。
可扩展性,可扩展master节点,释放单个master的写数据压力,节点可动态添加或删除。
能够实现自动故障转移,节点之间通过gossip协议交换状态信息,用投票机制完成slave到master的角色转换。

添加链接描述
添加链接描述
添加链接描述
添加链接描述

Redis集群如何保证一致性

Redis集群内如何实现的数据同步?

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

Redis的同步机制了解么

Redis怎么实现主从同步的?

主从复制是Redis最基本、最常用的数据同步方式。它的原理是将主节点的数据复制到从节点,使得从节点的数据与主节点保持一致。主从复制的流程如下:

1)从节点连接主节点,并发送SYNC命令请求同步数据。
2)主节点在接收到SYNC命令后,开始执行BGSAVE命令,将数据持久化到磁盘中,并将生成的RDB文件发送给从节点。
3)从节点在接收到RDB文件后,通过LOAD命令将其加载到内存中,从而与主节点的数据保持一致。
4)从节点开始接收主节点的增量数据,并将其应用到自己的数据集中,保持与主节点的同步。
需要注意的是,主从复制是异步的,从节点与主节点的数据不是实时同步的。如果主节点发生故障,从节点可能会因为数据延迟而出现数据丢失的情况。
添加链接描述

Redis常见的部署方式有哪些

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

Redis怎么用的,如何实现数据一致性?

添加链接描述
添加链接描述

Redis sharding有哪些做法

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

哨兵Sentinel原理

Redis哨兵机制有几个定时任务,分别是干什么的?

通过 pub/sub 机制,哨兵之间可以组成集群,同时,哨兵又通过 INFO 命令,获得了从库连接信息,也能和从库建立连接,并进行监控。

每个哨兵实例也提供 pub/sub 机制,客户端可以从哨兵订阅消息。哨兵提供的消息订阅频道有很多,不同频道包含了主从库切换过程中的不同关键事件。
知道了这些频道之后,你就可以让客户端从哨兵这里订阅消息了。具体的操作步骤是,客户端读取哨兵的配置文件后,可以获得哨兵的地址和端口,和哨兵建立网络连接。然后,我们可以在客户端执行订阅命令,来获取不同的事件消息。
有了这些事件通知,客户端不仅可以在主从切换后得到新主库的连接信息,还可以监控到主从库切换过程中发生的各个重要事件。这样,客户端就可以知道主从切换进行到哪一步了,有助于了解切换进度。

添加链接描述
添加链接描述

Redis常见性能问题和解决方案

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

Pipeline有什么好处,为什么要用pipeline

pipeline的作用是将一批命令进行打包,然后发送给服务器,服务器执行完按顺序打包返回。
通过pipeline,一次pipeline(n条命令)=一次网络时间 + n次命令时间
添加链接描述

redis中有一批key瞬间过期,为什么其它key的读写效率会降低?

Redis的过期策略采用主动过期+懒惰过期两种策略:
主动过期:Redis内部维护一个定时任务,默认每隔100毫秒会从过期字典中随机取出20个key,删除过期的key,如果过期key的比例超过了25%,则继续获取20个key,删除过期的key,循环往复,直到过期key的比例下降到25%或者这次任务的执行耗时超过了25毫秒,才会退出循环
懒惰过期:只有当访问某个key时,才判断这个key是否已过期,如果已经过期,则从实例中删除
注意,Redis的主动过期的定时任务,也是在Redis主线程中执行的,也就是说如果在执行主动过期的过程中,出现了需要大量删除过期key的情况,那么在业务访问时,必须等这个过期任务执行结束,才可以处理业务请求。此时就会出现,业务访问延时增大的问题,最大延迟为25毫秒。
而且这个访问延迟的情况,不会记录在慢日志里。慢日志中只记录真正执行某个命令的耗时,Redis主动过期策略执行在操作命令之前,如果操作命令耗时达不到慢日志阈值,它是不会计算在慢日志统计中的,但我们的业务却感到了延迟增大。
添加链接描述
添加链接描述
添加链接描述

10亿个key中判断某个key是否存在?要求:1 内存空间不能太大,2 查询流量500w qps

布隆过滤器
布隆过滤器由一个初值都为 0 的 bit 数组和 N 个哈希函数组成,可以用来快速判断某个数据是否存在。当我们想标记某个数据存在时(例如,数据已被写入数据库),布隆过滤器会通过三个操作完成标记:
首先,使用 N 个哈希函数,分别计算这个数据的哈希值,得到 N 个哈希值
然后,我们把这 N 个哈希值对 bit 数组的长度取模,得到每个哈希值在数组中的对应位置。
最后,我们把对应位置的 bit 位设置为 1,这就完成了在布隆过滤器中标记数据的操作。
如果数据不存在(例如,数据库里没有写入数据),我们也就没有用布隆过滤器标记过数据,那么,bit 数组对应 bit 位的值仍然为 0。
当需要查询某个数据时,我们就执行刚刚说的计算过程,先得到这个数据在 bit 数组中对应的 N 个位置。紧接着,我们查看 bit 数组中这 N 个位置上的 bit 值。只要这 N 个 bit 值有一个不为 1,这就表明布隆过滤器没有对该数据做过标记,所以,查询的数据一定没有在数据库中保存。

答:用redis的bitmap实现,通过key 进行hash下标位置
问:那你怎么完全解决hash冲突?
答:多次hash
问:那只能降低概率,但不能完全避免
跟面试官说,要精确的知道某个key是否存在,只用hash肯定搞不定,所以可以多种方案并用,前置一个布隆过滤器,加速不存在的响应速度,后续分片到不同服务器,不同分片加索引,这个方案机器够的话吞吐量没问题,但是内存不能太多可能就要具体在问了,因为要精确的一定得存储,只是存储方案问题而已。
布隆过滤器,经过多次hash判断是否该值存在,能够精确的判断该值不存在,如果过滤器说存在,可能是hash冲撞造成的。所以要进一步验证是不是真实存在,因为hash冲撞概率不高,所以验证这一步并不会很频繁。
这个,直接使用HBASE的解决方案。
1.按照字典序分为多个文件
2.每个文件中保证自身有序(可以增加布隆过滤器)
3.查询时根据字典序查找到多个匹配文件。
4.在查找匹配的多个文件中是否存在数据(先匹配布隆过滤器,在通过二分查找)
原文添加链接描述

select poll epoll,epoll具体是怎么实现的

x86:32位
x64:64位
添加链接描述

你知道有哪些进程调度策略?多级反馈队列的实现原理

添加链接描述
添加链接描述
添加链接描述
添加链接描述

深度优先遍历和广度优先遍历的区别

添加链接描述
添加链接描述
添加链接描述
添加链接描述

linux下的栈大小

添加链接描述
添加链接描述

什么情况下用堆什么情况下用栈
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

linux命令想要找到文件并执行或者删除

添加链接描述
添加链接描述
添加链接描述
添加链接描述

linux文件系

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

Linux阻塞和非阻塞(异步IO)

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

多线程和多进程的区别

添加链接描述
添加链接描述
添加链接描述

存数据比较慢,用户想让你优化怎么办,而且用户要立刻读,所以就是不能用异步

添加链接描述

什么情况用redis什么情况用mysql

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

线程和协程的隔离程度

添加链接描述

对自动驾驶了解么 如果让你分析你怎么设计自动驾驶模块

添加链接描述
添加链接描述
添加链接描述
添加链接描述

给一个文件,输入一个单词,打印所有该文件中这个单词的兄弟单词(只是顺序不同)

添加链接描述
添加链接描述

怎么解决高并发问题

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

怎么创建子进程

父进程和子进程共享什么
添加链接描述

添加链接描述
添加链接描述
添加链接描述

内核态和用户态是什么,怎么转换

添加链接描述
添加链接描述
添加链接描述

操作系统调度算法需要考虑哪些因素?

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

cpu占用率超过100%是为什么

添加链接描述
添加链接描述
添加链接描述

linux怎么查端口号以及内存占用情况等等

添加链接描述
添加链接描述
添加链接描述

linux的control c是做什么的,按下之后系统咋实现功能的

添加链接描述
添加链接描述
添加链接描述

死锁产生的必要条件?

添加链接描述
添加链接描述

为什么选择json序列化

和protobuf比较json的优劣势
添加链接描述
添加链接描述
添加链接描述
添加链接描述

rpc跟普通的http有什么区别

RPC(即Remote Procedure Call,远程过程调用)和HTTP(HyperText Transfer Protocol,超文本传输协议),两者前者是一种方法,后者则是一种协议。两者都常用于实现服务,在这个层面最本质的区别是RPC服务主要工作在TCP协议之上(也可以在HTTP协议),而HTTP服务工作在HTTP协议之上。由于HTTP协议基于TCP协议,所以RPC服务天然比HTTP更轻量,效率更胜一筹。

在内部子系统较多、接口较多的情况下,RPC框架的好处就凸显出现了,首先是长连接,不必每次通信都要像HTTP那样三次握手,减少了网络开销;其次是RPC框架一般都有注册中心,有丰富的监控发布方法;RPC接口的发布、下线、动态扩展等对调用方是无感知的、统一化的操作。

在这里插入图片描述

原文链接:https://blog.csdn.net/Solo95/article/details/122640662
添加链接描述
添加链接描述

如果UDP发送方一直发,接受不过来会怎么样

会导致丢包
解决:
控制发送端发送的频率。比如现在每次发送256字节,做个缓冲,等到16k的时候再发送。 接收端确保每次接收数据时将数据全部接收完。
做了缓冲了也不行就要提升接收端的硬件配置了,UDP丢包属于正常,如果你的应用一帧数据都不能丢的话还是使用TCP比较好

tcp阻塞和非阻塞

发送操作:
(1)对于TCP的send系统调用发送数据,如果socket是阻塞的,我们需要这样理解:send操作将会等待所有数据均被拷贝到发送缓冲区后才会返回。
—如果发送缓冲区可用大小为0或者比要发送的数据长度要小,则会阻塞,直到发送缓冲区里的数据被系统发送出去后,可用缓冲区大小比要发送的数据长度大时,send返回成功,否则一直阻塞等待。因此,send返回的发送大小,一定是参数中发送长度的大小。
—例如:如果当前发送缓冲区总大小为8192,个字节,通过send已经拷贝到缓冲区的数据为8000字节,那缓冲区剩余大小为192字节,而现在上层应用需要发送2000字节的数据,那么send就会等待缓冲区足够把所有2000字节数据拷贝进去,如第一次拷贝进去192字节,当缓冲区成功发送出1808字节后,再把上层应用buf中剩余的1808字节拷贝到发送缓冲区,最后send返回成功拷贝到发送缓冲区的字节数。
(2)对于TCP的send系统调用,如果socket是非阻塞的,send会立即返回。
—例如,当发送缓冲区中有192字节,但是需要发送2000字节,此时send调用立即返回,并且返回值为192。因此,非阻塞send仅仅是尽自己的能力向发送缓冲区拷贝尽可能多的数据。如果发送缓冲区剩余空间为0,这时send立即返回,send返回值为EAGAIN,这是应用层最好休息一下再尝试发送。
接收操作:
1)在阻塞socket模式下,recv/recvfrom会一直阻塞到接收缓冲区里有一个字节或者一个完整的UDP数据报为止,然后再返回。
—如果socket发送缓冲区中有数据,或者接收缓冲区中无数据,或者协议正在接收数据,socket都阻塞等待,直到有数据拷贝到用户程序中,然后返回拷贝的字节数。(协议接收到的数据长度可能大于buf的长度(recvbuf长度),需要调用几次recv函数才能把socket接收缓冲区中的数据拷贝完)。
(2)在非阻塞socket模式下,recv/recvfrom会立即返回。
—如果接收缓冲区有任何一个字节数据(TCP)或者一个完整的UDP数据报,它们将会返回接收到的数据大小;如果缓冲区没有数据,则直接返回错误EWOULDBLOCK或者EGAIN,表示没有数据,休息一会儿再次接收操作。
添加链接描述

http和https的区别?

Http协议运行在TCP之上,明文传输,客户端与服务器端都无法验证对方的身份;Https是身披SSL(Secure Socket Layer)外壳的Http,运行于SSL上,SSL运行于TCP之上,是添加了加密和认证机制的HTTP。二者之间存在如下不同:
端口不同:Http与Http使用不同的连接方式,用的端口也不一样,前者是80,后者是443;
资源消耗:和HTTP通信相比,Https通信会由于加减密处理消耗更多的CPU和内存资源;
开销:Https通信需要证书,而证书一般需要向认证机构购买;

GET 和 POST 的区别?

GET是默认的HTTP请求方法。
(1). 从功能上讲,GET一般用来从服务器上获取资源,POST一般用来更新服务器上的资源;
(2). 从REST服务角度上说,GET是幂等的,即读取同一个资源,总是得到相同的数据,而POST不是幂等的,因为每次请求对资源的改变并不是相同的;进一步地,GET不会改变服务器上的资源,而POST会对服务器资源进行改变;
(3). 从请求参数形式上看,GET请求的数据会附在URL之后,即将请求数据放置在HTTP报文的 请求头 中,以?分割URL和传输数据,参数之间以&相连。特别地,如果数据是英文字母/数字,原样发送;否则,会将其编码为 application/x-www-form-urlencoded MIME 字符串(如果是空格,转换为+,如果是中文/其他字符,则直接把字符串用BASE64加密,得出如:%E4%BD%A0%E5%A5%BD,其中%XX中的XX为该符号以16进制表示的ASCII);而POST请求会把提交的数据则放置在是HTTP请求报文的 请求体 中。
(4). 就安全性而言,POST的安全性要比GET的安全性高,因为GET请求提交的数据将明文出现在URL上,而且POST请求参数则被包装到请求体中,相对更安全。
(5). 从请求的大小看,GET请求的长度受限于浏览器或服务器对URL长度的限制,允许发送的数据量比较小,而POST请求则是没有大小限制的。

TCP是逻辑链接还是物理连接?

TCP连接是一条虚连接,也就是逻辑连接,而不是一条真正的物理连接。

OSI七层模型是哪七层,每层的作用

添加链接描述

301和302错误码的含义?

在这里插入图片描述

浏览器输入url整个过程

(1). 浏览器查询 DNS,获取域名对应的IP地址:
(2). 浏览器获得域名对应的IP地址以后,浏览器向服务器请求建立链接,发起三次握手;
(3). TCP/IP链接建立起来后,浏览器向服务器发送HTTP请求;
(4). 服务器接收到这个请求,并根据路径参数映射到特定的请求处理器进行处理,并将处理结果及相应的视图返回给浏览器;
(5). 浏览器解析并渲染视图,若遇到对js文件、css文件及图片等静态资源的引用,则重复上述步骤并向服务器请求这些资源;
(6). 浏览器根据其请求到的资源、数据渲染页面,最终向用户呈现一个完整的页面。

tcp和udp的区别

TCP (Transmission Control Protocol)和UDP(User Datagram Protocol)协议属于传输层协议,它们之间的区别包括:

TCP是面向连接的,UDP是无连接的;

TCP是可靠的,UDP是不可靠的;

TCP只支持点对点通信,UDP支持一对一、一对多、多对一、多对多的通信模式;

TCP是面向字节流的,UDP是面向报文的;

TCP有拥塞控制机制;UDP没有拥塞控制,适合媒体通信;

TCP首部开销(20个字节)比UDP的首部开销(8个字节)要大;

服务端的连接数_上限由什么决定,如何解决上限问题

TCP服务端,需要的只是一个监听端口,无论多少客户端连接上来,始终都是这个端口对外。服务端accept返回的socket只是通过客户端的ip跟端口来区分TCP连接的。
所有客户端的数据都是通过那个监听端口获取的。这个是操作系统底层的实现,抽象出来就是服务端只需要一个端口。所以理论上的最大连接数会非常大,ip * 端口数。
但是由于系统会受到内存等因数的限制,到不了这个数字。
客户端才与端口数有关,一般系统的端口数是0-65535.实际上可以绑定的端口只有1024-65535,因为0-1024被系统预定了。所以客户端可以绑定的端口数会更少。

总结:
TCP可以支持的最大连接数可以认为无上限,只是受到服务器配置影响。客户端才会受端口数影响,因为每个客户端发起连接时都需要绑定端口。
原文:添加链接描述

DNS是怎么做解析的

1)首先搜索浏览器的 DNS 缓存,缓存中维护一张域名与 IP 地址的对应表;
2)若没有命中,则继续搜索操作系统的 DNS 缓存;
3)若仍然没有命中,则操作系统将域名发送至本地域名服务器,本地域名服务器查询自己的 DNS 缓存,查找成功则返回结果(注意:主机和本地域名服务器之间的查询方式是递归查询);
4)若本地域名服务器的 DNS 缓存没有命中,则本地域名服务器向上级域名服务器通过以下方式进行迭代查询(注意:本地域名服务器和其他域名服务器之间的查询方式是迭代查询,防止根域名服务器压力过大):

首先本地域名服务器向根域名服务器发起请求,根域名服务器是最高层次的,它并不会直接指明这个域名对应的 IP 地址,而是返回顶级域名服务器的地址,也就是说给本地域名服务器指明一条道路,让他去这里寻找答案
本地域名服务器拿到这个顶级域名服务器的地址后,就向其发起请求,获取权限域名服务器的地址
本地域名服务器根据权限域名服务器的地址向其发起请求,最终得到该域名对应的 IP 地址
4)本地域名服务器将得到的 IP 地址返回给操作系统,同时自己将 IP 地址缓存起来
5)操作系统将 IP 地址返回给浏览器,同时自己也将 IP 地址缓存起来
6)至此,浏览器就得到了域名对应的 IP 地址,并将 IP 地址缓存起来

telnet命令是哪层的命令?

应用层
Telnet提供远程登录功能,使得用户在本地主机上运行Telnet客户端,就可登录到远端的Telnet服务器. 在本地输入的命令可以在服务器上运行,服务器把结果返回到本地,如同直接在服务器控制台上操作. 这样就可以在本地远程操作和控制服务器。
添加链接描述

https怎么加密的

HTTPS的原理?非对称加密和对称加密?(RSA、AES和证书的原理)

1)客户端发起一个http请求,告诉服务器自己支持哪些hash算法。
2)服务端把自己的信息以数字证书的形式返回给客户端(证书内容有密钥公钥,网站地址,证书颁发机构,失效日期等)。证书中有一个公钥来加密信息,私钥由服务器持有。
3)验证证书的合法性
客户端收到服务器的响应后会先验证证书的合法性(证书中包含的地址与正在访问的地址是否一致,证书是否过期)。
4)生成随机密码(RSA签名)
如果验证通过,或用户接受了不受信任的证书,浏览器就会生成一个随机的对称密钥(session key)并用公钥加密,让服务端用私钥解密,解密后就用这个对称密钥进行传输了,并且能够说明服务端确实是私钥的持有者。
5)生成对称加密算法
验证完服务端身份后,客户端生成一个对称加密的算法和对应密钥,以公钥加密之后发送给服务端。此时被黑客截获也没用,因为只有服务端的私钥才可以对其进行解密。之后客户端与服务端可以用这个对称加密算法来加密和解密通信内容了。
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

拥塞控制和流量控制怎么实现的?具体讲一下

滑动窗口在计网中的应用

流量控制:点对点。TCP 利用滑动窗口实现流量控制的机制,目的是接收方通过TCP头窗口字段告知发送方本方可接收的最大数据量。

拥塞控制:全局。控制拥塞使用拥塞窗口。
拥塞控制主要是四个算法:1)慢启动,2)拥塞避免,3)拥塞发生,4)快速恢复。在这里插入图片描述
1、慢启动:
初始化拥塞窗口cwnd大小为1,每经过一个往返时间,乘2,呈指数上升。
有一个慢开始门限ssthresh(slow start threshold),是一个上限,当cwnd >= ssthresh时,就会进入“拥塞避免算法”。
2、拥塞避免:
每经过一个往返延迟时间RTT,cwnd大小加一。
3、拥塞发生
对于丢包有两种判定方式,一种是超时重传RTO[Retransmission Timeout]超时,另一个是收到三个重复确认ACK。
3.1超时重传算法:
原理是在发送一个数据以后就开启一个计时器,在一定时间内如果没有得到发送数据报的ACK报文,那么就重新发送数据,直到发送成功为止。
1)由于发生丢包,将慢启动门限ssthresh设置为当前cwnd的一半,即ssthresh = cwnd / 2
2)cwnd重置为1
3)进入慢启动过程
3.2快速重传算法(收到三个重复确认ACK)
但是如果发送端接收到3个以上的重复ACK,TCP就意识到数据发生丢失,需要重传。这个机制不需要等到重传定时器超时,所以叫 做快速重传,而快速重传后没有使用慢启动算法,而是拥塞避免算法,所以这又叫做快速恢复算法。
1)cwnd大小缩小为当前的一半
2)ssthresh设置为缩小后的cwnd大小
3)然后进入快速恢复算法Fast Recovery快速恢复。(拥塞避免算法)

添加链接描述

DDOS攻击实现原理?怎么防护?

在这里插入图片描述

XSS攻击知道吗?怎么防止?

XSS又叫CSS (Cross Site Script) ,跨站脚本攻击。它指的是恶意攻击者往Web页面里插入恶意html代码,当用户浏览该页面时,嵌入其里面的html代码会被执行,从而达到恶意的特殊目的。
解决办法:
1、在输入方面对所有用户提交内容进行可靠的输入验证,包括URL、查询关键字、http头、post数据等
2、在输出方面,在用户输出内容中使用标签。标签内的内容不会解释,直接显示。
3、严格执行字符输入字数控制。
4、在脚本执行区中,应绝无用户输入。
5、不要在cookie里存放重要信息,以防cookie被盗
添加链接描述
添加链接描述

csrf

CSRF攻击原理过程如下:
1、用户C打开浏览器,访问安全网站A,输入用户名和密码请求登录网站A.
2、在用户信息通过验证后,网站A产生Cookie信息并返回给浏览器,此时用户登录A成功,可以正常发送请求到网站A。
3、用户没有退出A之前,在同一个浏览器中,打开一个Tab页面来访问网站B.
4、网站B接收到用户的请求后,返回一些攻击代码,并且发出一个请求要求访问第三方站点A.
5、浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带Cookie信息,向网站A发出请求。网站A并不知道该请求其实是由B发出的,所以会根据用户C的cookie信息以C的权限处理该请求,导致来自网站B的恶意代码被执行。
想要达成CSRF攻击,必须达成两个基本条件:
1、登录受信任网站A,并且在本地生成Cookie。
2、在不退出登录网站A的前提下,访问危险网站B.
预防CSRF攻击:
1、验证HTTP Referer字段
优点:使用方便,开发简单,一定程度上能预防CSRF攻击
缺点:这种机制完全依托于浏览器,Referer字段容易被故意篡改,或者被禁用。
2、添加token验证
3、只使用JSON API
通过只接收JSON可以很大可能避免CSRF攻击。
添加链接描述
添加链接描述

tcp三次握手丢包后会发生什么

第一次握手丢失:客户端超时重传
客户端发送SYN请求连接报文,如果迟迟等不到服务器的请求确认报文段,那么就会进行超时重传,具体重传几次,要看tcp_syn_retries内核参数,一般默认是5次。要注意的是,重传的请求连接报文的seq序列号字段还是之前的seq,不会重新生成哦。

第二次握手丢失:客户端、服务器超时重传
第二次握手丢失就有意思了,因为服务器发送的第二次握手是连接确认报文段,既包括对第一次握手的ACK确认,同时还有SYN字段表示要建立连接,所以第二次握手也可以成为SYN-ACK报文。所以当第二次握手丢失,客户端迟迟等不到第一次握手的确认,就会触发超时重传机制,进行超时重传;服务器等不到自己SYN连接的确认,也会进行超时重传。客户端和服务器具体的超时重传次数还是由内核参数决定。

第三次握手丢失
第三次握手丢失,此时客户端已经处于Established状态了,因为它通过两次握手已经验证了自己的发送和接收能力嘛。但是此时第三次握手丢失,服务器迟迟得不到ACK报文,但是ACK报文丢失,ACK 报文是不会有重传的,当 ACK 丢失了,就由对方重传对应的报文。所以当到达服务器的超时重传时间后,服务器会超时重传第二次报文,当达到最大超时重传次数还没得到ACK报文,服务器就会断开连接。

第三次握手情况比前两种复杂一些,我们还是先从理论上分析一下。假如第三次握手客户端发送的ack包丢了,客户端是不知道的,因为只要第三次握手发出之后,客户端就认为连接已经建立了,状态变成ESTABLISHED;而服务端由于收不到第三次握手的ack包,状态依然为SYN_REVD,理论上服务端会进行重传,重传一定次数之后会释放连接。而客户端如果发送数据,服务端收到请求之后,由于不处于ESTABLISHED状态,可能认为这不是一个正常的连接,然后回个rst;如果客户端不发送数据,那可能就会hang住,只能等待keepalive超时。

为什么需要三次握手,而不是两次

1.为了避免已失效的连接报文段又到达服务器。考虑这样一个正常的情况:

假设TCP连接是两次握手。当客户端发送了一个请求连接的报文时,由于网络原因这个报文丢失了,那么客户端一段时间内没有收到服务器的确认就会再次发送请求连接报文,这次服务器收到了,双方都建立了连接,然后数据传输,最后关闭连接。

但是考虑一下,上文中的丢失数据包若没有丢失,只是在一个网络节点长时间滞留了,这时双方都已经关闭了连接,此时服务器又收到了丢掉了的数据包请求,认为客户端又要建立连接,因为是两次握手所以服务器向客户端发送了确认报文,并变为建立连接状态。

可想而知客户端并没有发起连接所以会忽略服务器的确认,则服务端一直等待客户端发送数据,这样就浪费了服务器的资源。
2.Server端易受到SYN攻击?
服务器端的资源分配是在二次握手时分配的,而客户端的资源是在完成三次握手时分配的,所以服务器容易受到SYN洪泛攻击,SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server则回复SYN+ACK确认包,并等待Client确认回复ACK,而这些大量的IP是不存在的,并不会向服务端发送ack确认包,所以会大量的占领半连接队列资源,导致正常的SYN请求因为队列满而被丢弃,从而引起网络拥塞甚至系统瘫痪。
3.预防SYN攻击?
开启SYN cookies技术、增加最大半连接和缩短超时时间。
SYN cookies应用于linux、FreeBSD等操作系统,当半连接队列满时,SYNcookies并不丢弃SYN请求,而是通过加密技术来标识半连接状态。

在TCP实现中,当收到客户端的SYN请求时,服务器需要回复SYN+ACK包给客户端,客户端也要发送确认包给服务器。通常,服务器的初始序列号由服务器按照一定的规律计算得到或采用随机数,但在SYN cookies中,服务器的初始序列号是通过对客户端IP地址、客户端端囗、服务器IP地址和服务器端囗以及其他一些安全数值等要素进行hash运算,加密得到的,称之为cookie。当服务器遭受SYN攻击使得半连接状态队列满时,服务器并不拒绝新的SYN请求,而是回复cookie(回复包的SYN序列号)给客户端, 如果收到客户端的ACK包,服务器将客户端的ACK序列号减去1得到cookie比较值,并将上述要素进行一次hash运算,看看是否等于此cookie。如果相等,直接完成三次握手(注意:此时并不用查看此连接是否属于半连接状态队列)。

为什么不能是三次挥手?握手和挥手过程中的状态

TCP是全双工的,A发起断开连接操作只能说明A不发送任何数据了,B的ACK确认收到断开请求,而B可以选择不断开,继续向A发送数据。(此时服务器是 CLOSE-WAIT 状态,TCP连接出于半关闭状态,即A已经没有数据要发送了,但B若发送数据,A仍要接受,这个状态可能会持续一段时间)
如果服务器段将ACK(第二次挥手)和FIN(第三次挥手)合并成一块发过去的话,这就意味着一方关闭,另一方也要被迫关闭,同时代表若此时有服务器继续单向的发送片段给客户端的需求则无法实现。
添加链接描述

time_wait的为什么是2msl,close_wait的作用,time_wait过多怎么办

等待2MSL的原因:
第一,为了保证A发送的最后一个ACK报文段能够到达B。这个ACK报文段有可能丢失,因而使处在LAST-ACK状态的B收不到对已发送的FIN + ACK报文段的确认。B会超时重传这个FIN + ACK报文段,而A就能在2MSL时间内收到这个重传的FIN +ACK报文段。接着A重传一次确认,重新启动2MSL计时器。最后,A和B都正常进入到CLOSED状态。如果A在TIME-WAIT状态不等待一段时间,而是在发送完ACK报文段后立即释放连接,那么就无法收到B重传的FIN + ACK报文段,因而也不会再发送一次确认报文段。这样,B就无法按照正常步骤进入CLOSED状态。

第二,防止上一节提到的“已失效的连接请求报文段”出现在本连接中。A在发送完最后一个ACK报文段后,再经过时间2MSL,就可以使本连接持续的时间内所产生的所有报文段都从网络中消失。这样就可以使下一个新的连接中不会出现这种旧的连接请求报文段。

TIME_WAIT状态可以通过优化服务器参数得到解决,因为发生TIME_WAIT的情况是服务器自己可控的,要么就是对方连接的异常,要么就是自己没有迅速回收资源,总之不是由于自己程序错误导致的。
大量CLOSE_WAIT的解决办法总结为一句话那就是:查代码。因为问题出在服务器程序里头。
添加链接描述

tcp四次挥手,为什么需要中间那个FIN-WAIT-2这个过程

FIN_WAIT_2:进入这个状态后,就处于一个半关闭状态。在面试过程中,很多面试官会问,为什么TCP握手需要三次,而挥手需要四次。就是因为TCP允许半关闭,而半关闭处于的状态就是FIN_WAIT_2。
添加链接描述

TCP四次握手中CLOSE_WAIT状态后什么时候server端能发送FIN呢

服务器出现大量CLOSE_WAIT状态的原因?
服务器出现大量CLOSE_WAIT状态只有一种情况,在客户端发送FIN报文时,服务器端没有进一步发送(ACK,或者FIN报文已确认)
换句话说:对方关闭socket连接,我方忙于读或写,没有及时关闭连接。解决办法如下:
• 检查代码,特别是释放资源的代码
• 检查配置,特别是处理请求的线程配置

tcp如何保证安全可靠的传输

1、基于数据块传输
2、对失序数据包重新排序以及去重
3、校验和
4、超时重传
5、流量控制
6、拥塞控制
添加链接描述

HTTP1.0, HTTP1.1,HTTP2.0 区别

HTTP1.0特点:无状态、短连接
HTTP1.1特点:长连接、请求管道化、引入了更多的缓存控制策略、Host字段、断点传输
HTTP2.0特点:二进制传输、多路复用、头部压缩、服务器推送
http1.x中,网页的加载过程是这样的:请求主网页 => 解析网页 => 请求页面内的依赖资源(如 js、css 、图片等静态文件) => 加载依赖资源。由于每一个依赖资源都必须明确地向服务器端发送请求,这样会导致加载过程非常缓慢。但是在http2.0中,服务器在响应浏览器第一个请求的时候,就可以开始推送这些依赖的资源,而无需客户端明确的向其发起请求。
添加链接描述

TCP 粘包怎么解决

要发送的数据小于TCP发送缓冲区的大小,TCP将多次写入缓冲区的数据一次发送出去,将会发生粘包。
接收数据端的应用层没有及时读取接收缓冲区中的数据,将发生粘包。
处理方式:
1、当时短连接的情况下,不用考虑粘包的情况
2、如果发送数据无结构,如文件传输,这样发送方只管发送,接收方只管接收存储就ok,也不用考虑粘包
3、如果双方建立长连接,需要在连接后一段时间内发送不同结构数据
发送端给每个数据包添加包首部,首部中应该至少包含数据包的长度,这样接收端在接收到数据后,通过读取包首部的长度字段,便知道每一个数据包的实际长度了。
发送端将每个数据包封装为固定长度(不够的可以通过补0填充),这样接收端每次从接收缓冲区中读取固定长度的数据就自然而然的把每个数据包拆分开来。
可以在数据包之间设置边界,如添加特殊符号,这样,接收端通过这个边界就可以将不同的数据包拆分开。
添加链接描述

HTTP的header,request,response,你知道的有哪些部分

content-type,content-length各自是什么含义?
Content-Length:请求的内容长度。
Content-Type:请求的与实体对应的MIME信息。

request headers
在这里插入图片描述
response headers
在这里插入图片描述
在这里插入图片描述
添加链接描述
添加链接描述
添加链接描述

http请求头、分隔符、长连接怎么实现

在HTTP/1.0中默认使用短连接。也就是说,客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。当客户端浏览器访问的某个HTML或其他类型的Web页中包含有其他的Web资源(如JavaScript文件、图像文件、CSS文件等),每遇到这样一个Web资源,浏览器就会重新建立一个HTTP会话。
而从HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头加入这行代码:
Connection:keep-alive
在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。实现长连接需要客户端和服务端都支持长连接。

为什么又要用cookie又要用token

session id怎么存的,以及怎么能防止被劫持

cookie:优点是节省服务器空间,缺点不安全。不要保存敏感信息。
session:优点是安全,缺点需要服务器空间(服务器重启,则数据丢失), 是一种最常见的解决方案。而这个时候,我们用token就更好
token的意思是“令牌”,是服务端生成的一串字符串,作为客户端进行请求的一个标识
token是为了防止CSRF的;
CSRF攻击的原因是浏览器会自动带上cookie,而不会带上token;
以CSRF攻击为例:
cookie:用户点击了链接,cookie未失效,导致发起请求后后端以为是用户正常操作,于是进行扣款操作;
token:用户点击链接,由于浏览器不会自动带上token,所以即使发了请求,后端的token验证不会通过,所以不会进行扣款操作;
在这里插入图片描述

不同线程共享的是什么

线程共享的资源包括:
(1) 进程代码段
(2) 进程的公有数据(利用这些数据,线程很容易实现相互之间的通讯)
(3) 进程的所拥有资源。
原文:添加链接描述

数组和链表的比较

(1)数组的元素个数是固定的,而组成链表的结点个数可按需要增减;

(2)数组元素的存诸单元在数组定义时分配,链表结点的存储单元在程序执行时动态向系统申请:

(3)数组中的元素顺序关系由元素在数组中的位置(即下标)确定,链表中的结点顺序关系由结点所包含的指针来体现。

(4)对于不是固定长度的列表,用可能最大长度的数组来描述,会浪费许多内存空间。

(5)对于元素的插人、删除操作非常频繁的列表处理场合,用数组表示列表也是不适宜的。若用链表实现,会使程序结构清晰,处理的方法也较为简便。

例如在一个列表中间要插人一个新元素,如用数组表示列表,为完成插人工作,插人处之后的全部元素必须向后移动一个位置空出的位置用于存储新元素。

对于在一个列表中删除一个元素情况,为保持数组中元素相对位置连续递增,删除处之后的元素都得向前移一个位置。如用链表实现列表.链表结点的插人或删除操作不再需要移动结点,只需改变相关的结点中的后继结点指针的值即可,与结点的实际存储位置无关。
原文:添加链接描述
添加链接描述
数组地址连续的优点:
数组的优点:数组的“连续”特征决定了它的访问速度很快,因为它是连续存储的,所以这就决定了它的存储位置就是固定的,因此它的访问速度就很快。
数组的缺点:缺点它对内存的要求比较高,必须要找到一块连续的内存才行。

内存惰性分配是如何实现的,原理

当进程向系统申请分配内存时,操作系统采取的是惰性分配的策略,即系统会快速回应需要内存的进程表示你的申请是有效的,但此时并不会为该进程真正分配出内存空间,而是在该进程真正使用到这段内存时才真正分配,这就是惰性分配思想。操作系统采取惰性分配的好处个人认为如下:
避免某些进程空占着内存资源。有些进程在初始化时就先分配了大量内存,但这些内存空间也许要等到某些条件触发时才会利用上,也有可能到进程退出时也用不到这些内存,因此为了保证内存的使用率,惰性分配很有必要。以一个“延时满足”的思想解决了内存消耗过快的问题。
添加链接描述
添加链接描述
添加链接描述

操作系统内存模型

添加链接描述
添加链接描述
添加链接描述

虚拟地址的作用是什么

1、 程序可以使用一系列相邻的虚拟地址来访问物理内存中不相邻的大内存缓冲区。
2 、程序可以使用一系列虚拟地址来访问大于可用物理内存的内存缓冲区。
3 、不同进程使用的虚拟地址彼此隔离。一个进程中的代码无法更改正在由另一进程或操作系统使用的物理内存。
添加链接描述
添加链接描述
添加链接描述

介绍一下文件系统,谈谈理解

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

工作中那些地方使用过多线程,哪些场景,以及开启线程和线程配置,线程池的使用

多线程怎么实现的

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

系统设计

一、性能
指标:

响应时间
吞吐量
并发用户数
性能优化方案:

集群
缓存
异步
二、伸缩性
指不断向集群中添加服务器来缓解不断上升的用户并发访问压力和不断增长的数据存储需求。

三、扩展性
指的是添加新功能时对现有系统的其它应用无影响,这就要求不同应用具备低耦合的特点。

四、可用性
保证可用性方案:

冗余
监控
熔断限流降级
五、安全性

java、python、go的区别和各自的优势

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

页面置换?淘汰算法?LRU用基础数据结构的实现思路?

页面置换算法
1.最佳置换算法
每次选择淘汰的页面将是以后永不使用,或者在最长时间内不再被访问的页面,这样可以保证最低的缺页率。
最佳置换算法可以保证最低的缺页率,但是实际上,只有进程执行的过程中才能知道接下来会访问到的是哪个页面。操作系统无法提前预判页面的访问序列。因此,最佳置换算法是无法实现的。
2.先进先出置换算法(FIFO)
算法思想:每次选择淘汰的页面是最早进入内存的页面。
FIFO算法虽然实现简单,但是该算法与进程实际运行时的规律不适应。因为先进入的页面也有可能最经常被访问。算法性能差。
当为进程分配的物理块数增大时,缺页次数不减反增的异常现象称为贝莱迪(Belay)异常。只有FIFO算法会产生Belay异常。
3.最近最久未使用置换算法(LRU,Least Recently Used)
算法思想:每次淘汰的页面是最近最久未使用的页面。
实现方法:赋予每个页面对应的页表项中,用访问字段记录该页面自上次被访问以来所经历的时间t。当需要淘汰一个页面时,选择现有页面中t最大的页面,即最近最久未使用。
4.时钟置换算法
最佳置换算法那性能最好,但无法实现。先进先出置换算法实现简单,但是算法性能差。最近最久未使用置换算法性能好,是最接近OPT算法性能的,但是实现起来需要专门的硬件支持,算法开销大。时钟置换算法是一种性能和开销均平衡的算法。又称CLOCK算法,或最近未用算法(NRU,Not Recently Used)
简单CLOCK算法算法思想:为每个页面设置一个访问位,再将内存中的页面都通过链接指针链接成一个循环队列。当某个页被访问时,其访问位置1.当需要淘汰一个页面时,只需检查页的访问位。如果是0,就选择该页换出;如果是1,暂不换出,将访问位改为0,继续检查下一个页面,若第一轮扫描中所有的页面都是1,则将这些页面的访问位一次置为0后,再进行第二轮扫描(第二轮扫描中一定会有访问位为0的页面,因此简单的CLOCK算法选择一个淘汰页面最多会经过两轮扫描)。
5.改进型的时钟置换算法
简单的时钟置换算法仅考虑到了一个页面最近是否被访问过。事实上,如果淘汰的页面没有被修改过,就不需要执行I/O操作写回外存。只有淘汰的页面被修改过时,才需要写回外存。
因此,除了考虑一个页面最近有没有被访问过之外,操作系统还需要考虑页面有没有被修改过。
改进型时钟置换算法的算法思想:在其他在条件相同时,应该优先淘汰没有被修改过的页面,从而来避免I/O操作。
为了方便讨论,用(访问位,修改位)的形式表示各页面的状态。如(1,1)表示一个页面近期被访问过,且被修改过。
算法规则:将所有可能被置换的页面排成一个循环队列
在这里插入图片描述由于第二轮已将所有的页的访问位都设为0,因此第三轮、第四轮扫描一定会选中一个页,因此改进型CLOCK置换算法最多会进行四轮扫描。
在这里插入图片描述
添加链接描述
添加链接描述
添加链接描述

淘汰算法
redis 使用的方式就是“惰性淘汰+定期淘汰”
添加链接描述
添加链接描述

LRU用基础数据结构的实现思路
添加链接描述
添加链接描述
添加链接描述

信号是什么?用过吗?

信号(signal)是进程间通讯的一种方式,用来提醒进程某个事件已经发生。它属于一种异步通知进制。一个进程不必通过任何操作来等待信号的到达,事实上进程也不知道信号到底什么时候到达。进程之间可以互相通过系统调用kill发送软中断信号。内核也可以因为内部事件而给进程发送信号,通知进程发生了某个事件。

信号是事件发生时对进程的通知机制。有时也称之为软件中断。信号与硬件中断的相似之处在于打断了程序执行的正常流程,大多数情况下,无法预测信号到达的精确时间。

因为一个具有合适权限的进程可以向另一个进程发送信号,这可以称为进程间的一种同步技术。当然,进程也可以向自身发送信号。然而,发往进程的诸多信号,通常都是源于内核。引发内核为进程产生信号的各类事件如下。
硬件发生异常,即硬件检测到一个错误条件并通知内核,随即再由内核发送相应信号给相关进程。比如执行一条异常的机器语言指令(除 0,引用无法访问的内存区域)。
用户键入了能够产生信号的终端特殊字符。如中断字符(通常是 Control-C)、暂停字符(通常是 Control-Z)。
发生了软件事件。如调整了终端窗口大小,定时器到期等。

针对每个信号,都定义了一个唯一的(小)整数,从 1 开始顺序展开。系统会用相应常量表示。Linux 中,1-31 为标准信号;32-64 为实时信号(通过 kill -l 可以查看)。

信号达到后,进程视具体信号执行如下默认操作之一。
忽略信号,也就是内核将信号丢弃,信号对进程不产生任何影响。
终止(杀死)进程。
产生 coredump 文件,同时进程终止。
暂停(Stop)进程的执行。
恢复进程执行。

当然,对于有些信号,程序是可以改变默认行为的,这也就是 os/signal 包的用途。
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

常见的OOM现象,以及如何解决

oom就是Out of Memory内存溢出,它是指需要的内存空间大于系统分配的内存空间
常见造成oom的原因:
1.内存泄漏造成
2.加载的文件或者图片过大造成
3. 线程数量过多,队列容量设置过大,导致OOM
解决方案:
内存泄露是造成内存溢出的一个原因,所以避免内存泄露的那些方法都适用于内存溢出
比如及时回收无用的引用对想,资源回收等…
使用统一的线程池管理类进行线程管理。
添加链接描述
添加链接描述
添加链接描述
当使用golang过程中,遇到性能和内存gc问题,都可以使用golang tool pprof来排查分析问题

一堆文件中怎么找到最大的10000个数(top K问题)

添加链接描述
添加链接描述
添加链接描述

接口设计

1、接口参数校验
2、接口的兼容性
3、充分考虑接口的可扩展性
4、如果你调用第三方接口,或者分布式远程服务的的话,需要考虑:
异常处理 接口超时 重试次数
5、接口实现考虑熔断和降级
6、接口的功能单一、明确。比如订单服务、积分、商品信息相关的接口都是划分开的
7、接口有些场景,使用异步更合理
8、接口实现过程中,恰当使用缓存
使用缓存增加了需要考虑这些点:缓存和数据库一致性如何保证、集群、缓存击穿、缓存雪崩、缓存穿透等问题。
保证数据库和缓存一致性:缓存延时双删、删除缓存重试机制、读取biglog异步删除缓存
缓存击穿:设置数据永不过期
缓存雪崩:Redis集群高可用、均匀设置过期时间
缓存穿透:接口层校验、查询为空设置个默认空值标记、布隆过滤器。
9、接口考虑热点数据隔离性
10、接口状态和错误需要统一明确
11、保证接口安全性
如果你的API接口是对外提供的,需要保证接口的安全性。保证接口的安全性有token机制和接口签名。
添加链接描述
添加链接描述

websocket的协议体

websocket是一种浏览器与服务器进行全双工通信的网络技术,属于 应用层协议,补HTTP协议在持久通信能力上的不足。
websocket的特点:
1.节省资源开销,HTTP请求每次都要携带完整的头部,此项开销显著减少了;
2.更强的实时性,由于协议是全双工通信,所以服务器可以主动给客户端推送数据,相对于HTTP请求需要等待客户端发起请求服务端才能响应,延迟明显更少;
3.保持连接状态,能够记录用户状态,通信时可以省略部分状态信息,不像HTTP每次都需要携带用户认证信息;
4.更好的二进制支持,Websocket定义了二进制帧,相对HTTP,可以更轻松地处理二进制内容。
websocket与http的区别
相同点:
都是基于TCP协议进行数据传输
都属于应用层协议
不同点:
websocket是双向通信协议,而HTTP是单向通信
websocket是有状态的,而HTTP是无状态的
联系点:
websocket在建立握手时,数据是通过HTTP协议传输的(HTTP只进行了握手动作),
但是握手之后,单独建立了一条TCP通信通道,之后数据都是基于TCP协议直接传输,不需要HTTP协议了。

websocket与socket的区别
Socket其实并不是一个协议,而是为了方便使用TCP或UDP而抽象出来的一层,是位于应用层和传输控制层之间的一组接口。Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。当两台主机通信时,必须通过Socket连接,Socket则利用TCP/IP协议建立TCP连接。TCP连接则更依靠于底层的IP协议,IP协议的连接则依赖于链路层等更低层次。WebSocket则是一个典型的应用层协议。Socket是传输控制层协议,WebSocket是应用层协议。

可以理解为张三和张三丰的关系
1.Socket 是传输控制层的接口,用户可以通过 Socket 来操作底层 TCP/IP 协议簇通信。
2.WebSocket 是一个完整的应用层协议。
3.Socket 更灵活,WebSocket 更易用。
4.两者都能做即时通讯
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

断点续传的原理,我回答的太简单了, 后面反问才知道想让深入讲HTTP的断点续传 如何实现

添加链接描述
添加链接描述
添加链接描述
添加链接描述

设计一个支付系统,如支付宝,方案对比

添加链接描述
添加链接描述
添加链接描述

设计一个kv数据库,各个组成部分如何实现

添加链接描述
添加链接描述

RBAC控制方案你觉得好在哪里,注意事项,核心要点讲讲;

添加链接描述
添加链接描述

聊了ChatGPT,有没有用来写代码,对这个工具怎么看待

添加链接描述
添加链接描述
添加链接描述
添加链接描述

实现简单令牌桶算法,没有考虑时间滑动的情况

加强版:令牌桶,加上时间滑动的要求,即:限制用户在任一连续的一小时内,不能超过5w的请求
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

设计微博

添加链接描述
添加链接描述
添加链接描述
添加链接描述

如果让你设计一个数据库,你会怎么设计

添加链接描述
添加链接描述
添加链接描述

k8s原理

添加链接描述
添加链接描述
添加链接描述

设计一个秒杀系统,一层层展开

原文https://blog.csdn.net/zhanghe_zht/article/details/130270623?spm=1001.2014.3001.5501
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

了解哪些后端框架

工作中使用的框架

Gin:一个知名且简约的Golang Web应用框架。Gin 是 Go语言写的一个 web 框架,它具有运行速度快,分组的路由器,良好的崩溃捕获和错误处理,非常好的支持中间件和 json。该框架拥有各种开发所需的库和功能。许多知名的开发公司都会采用该Web框架,来处理各种监控、跟踪、以及调试等问题。此外,相对其他平台,该框架还具有如下特点:
该框架非常适合构建出高性能的REST API。
它使用HTTP路由器,来管理Golang流量。
它使用简单的设计规则,并提供精确的文档。
Gin 是一个用 Go (Golang) 编写的 Web 框架。 它具有类似 martini 的 API,性能要好得多,多亏了 httprouter,速度提高了 40 倍。 如果您需要性能和良好的生产力,您一定会喜欢 Gin。
特性
快速:基于 Radix 树的路由,小内存占用。没有反射。可预测的 API 性能。
支持中间件:传入的 HTTP 请求可以由一系列中间件和最终操作来处理。 例如:Logger,Authorization,GZIP,最终操作 DB。
Crash处理:Gin 可以 catch 一个发生在 HTTP 请求中的 panic 并 recover 它。这样,你的服务器将始终可用。例如,你可以向 Sentry 报告这个 panic!
Json验证:Gin 可以解析并验证请求的 JSON,例如检查所需值的存在。 路由组 更好的组织路由。是否需要授权,不同的 API 版本…… 此外,这些组可以无限制地嵌套而不会降低性能。 错误管理 Gin 提供了一种方便的方法来收集 HTTP 请求期间发生的所有错误。最终,中间件可以将它们写入日志文件,数据库并通过网络发送。 内置渲染 Gin 为 JSON,XML 和 HTML 渲染提供了易于使用的 API 可扩展性

Gorm框架:
Gorm框架是一个基于Golang的ORM框架,它支持多种数据库,包括MySQL、PostgreSQL、SQLite、SQL Server等。Gorm框架提供了类似于Active Record的API,使得程序员可以通过简单的代码完成对数据库的操作。

Gorm框架还支持事务处理、预加载、关联查询等高级功能。同时,Gorm框架还支持数据库迁移和表结构自动生成等功能,方便程序员进行数据库的管理和维护。

由于Gorm框架的高效性和易于使用的特点,使得它在Golang开发中得到了广泛的应用。

Grpc框架:
gRPC是rpc框架中的一种,是rpc中的大哥,是一个高性能,开源和通用的RPC框架,基于Protobuf序列化协议开发,且支持众多开发语言。面向服务端和协议端,基于http2.0设计。
添加链接描述

在以前的公司最大的收获是什么

添加链接描述

在命令行输入kill pid的时候,发生了什么?

添加链接描述
添加链接描述

你来设计一个对文档中敏感词的检测服务,说说你的思路。(建字典树,将敏感词存在字典树里。)

你怎么做字典树的持久化呢?(把敏感词存储在mysql里,每次重启服务,从mysql中读取敏感词,重新建树。)
那你怎么解决一致性问题呢?有可能不只一个服务器在提供这个服务。

消息队列场景

1、系统解耦
2、异步处理
3、流量削峰
4、日志处理
添加链接描述
添加链接描述
添加链接描述
添加链接描述

如何解决高流量高并发的问题

1.动静分离。
将网站中的静态资源单独拆分出来, 比如 css, js, 图片, 视频资源单独存储在一台服务器上, 或者直接使用云存储平台, 七牛云或者阿里云之类的, 这样能有效的降低主服务器的运行压力
2.CDN加速。
云平台提供 CDN 加速, 可以对资源进行全国服务器节点的分发, 提高全国各地的访问速度。
3.反向代理,负载均衡。
反向代理就是将用户的请求, 分发到不同的 web 服务器上, 进行处理, 降低单台服务器的压力, 负载均衡则是根据 web 服务器的性能进行请求的分配, 负载较小的多分配一些请求, 负载较大的小分配一下请求.   nginx 就可以实现反向代理和负载均衡。
4.使用数据缓存。
数据缓存可以使用 memcache 和 redis 这样的内存缓存系统来实现, 将一些常用数据写入到内存中, 从而提升响应的速度。
5.数据库优化。
数据缓存,结构优化,定位慢查询语句,语句优化,索引优化,分库分表,主从复制读写分离,中文分词。
6.压缩合并js css。
过多的 js 和 css 请求会消耗服务器的资源. 可以借助前端工具 webpack 来进行打包。
7.分布式集群搭建。
将业务拆分到不同的服务器下, 降低单台服务器压力.例如用户和商品功能拆分开。
8.页面静态化。
页面静态化其实是缓存的一种实现, 将要返回的 HTML 内容预先写入到一个文件中, 访问的时候可以直接返回该文件中的内容。
9.防止外部盗链。
盗链是其他网站引用当前服务器的资源, 比如css, js 和图片,主要是图片. 可以使用 refer 进行限制。
10.使用消息队列。
将请求的内容压入到队列中, 用另外的脚本异步处理请求, Redis 的列表结构就可以实现这个效果。

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

对于分布式数据库,可以将数据库做什么操作(我用的是分片,比如燃气库根据地区进行分片,数据多的再分片,数据少的进行合并)

给一个ID,如何从分片的数据库中去找到自己想要的数据(如何确定数据在分片的哪个表)我想的是可以配置规则(类似路由表)
分布式数据库:
一个分布式数据库在逻辑上是一个统一的整体,在物理上则是分别存储在不同的物理节点上。一个应用程序通过网络的连接可以访问分布在不同地理位置的数据库。它的分布性表现在数据库中的数据不是存储在同一场地。更确切地讲,不存储在同一计算机的存储设备上。这就是与集中式数据库的区别。从用户的角度看,一个分布式数据库系统在逻辑上和集中式数据库系统一样,用户可以在任何一个场地执行全局应用。就好像那些数据是存储在同一台计算机上,有单个数据库管理系统(DBMS)管理一样,用户并没有什么感觉不一样。
添加链接描述
添加链接描述
添加链接描述

一个RPC框架最少应该包含什么(说了Dubbo的组成部分,然后说了spring cloud的额外功能),如何设计一个框架

一个基本的RPC架构里面应该至少包含以下4个组件:

1、客户端(Client):服务调用方(服务消费者)

2、客户端存根(Client Stub):存放服务端地址信息,将客户端的请求参数数据信息打包成网络消息,再通过网络传输发送给服务端

3、服务端存根(Server Stub):接收客户端发送过来的请求消息并进行解包,然后再调用本地服务进行处理

4、服务端(Server):服务的真正提供者
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

项目中用到了什么设计模式?

设计模式,组合模式和装饰器模式,应用场景

代理模式和装饰者模式有啥区别

代理模式
添加链接描述
装饰器模式
添加链接描述

solid原则都是什么

SOLID原则,分别是单一原则、开闭原则、里氏替换原则、接口隔离原则、依赖倒置原则。

设计模式

面向对象设计原则
在这里插入图片描述
在这里插入图片描述
高内聚低耦合
耦合越弱越好,内聚越高越好
耦合指模块之间的关系,最弱的耦合就是通过一个主控模块来协调几个模块进行运作
内聚指的是模块内部的功能,最强的就是功能不能拆分,也就是原子化

简单工厂模式、工厂方法模式、抽象工厂方法模式、单例模式

添加链接描述
添加链接描述
添加链接描述
添加链接描述
单例模式
“饿汉式”。含义是,在初始化单例唯一指针的时候,就已经提前开辟好了一个对象,申请了内存。饿汉式的好处是,不会出现线程并发创建,导致多个单例的出现,但是缺点是如果这个单例对象在业务逻辑没有被使用,也会客观的创建一块内存对象。
懒汉式:可以借助Once来实现单例模式的实现

微服务的理解,优劣势

添加链接描述

服务拆分的原则及实践

原文添加链接描述
添加链接描述

给你一个这样的需求,一个用户可以看到自己发布的所有帖子,怎么建立索引?

如何应对大流量保证服务的稳定性

1、降级指系统将某些业务或者接口的功能降低,可以是只提供部分功能,也可以是完全停掉所有功能,优先保证核心功能。
2、熔断是指按照一定的规则,比如1分钟内60%的请求响应错误就停掉对外部接口的访问,防止某些外部接口故障导致自己的系统处理能力急剧下降或者出故障。
3、每个系统都有服务的上线,所以当流量超过服务极限能力时,系统可能会出现卡死、崩溃的情况,所以就有了降级和限流。限流其实就是:当高并发或者瞬时高并发时,为了保证系统的稳定性、可用性,系统以牺牲部分请求为代价或者延迟处理请求为代价,保证系统整体服务可用。
4、排队这种方式,想必大家在熟悉不过了。大家在12306买火车票的时候,是不是会告诉你在排队中,等待一段时间后才会锁定车票,付款。年底时,全中国那么多人买票,12306就是通过排队机制来搞定的。但是也有缺点,那就是用户体验没那么好。
由于排队需要临时缓存大量的业务请求,单个系统内部无法缓存这么多数据,一般情况下,排队需要用独立的系统去实现,例如使用Kafka这类消息队列来缓存用户请求。
在这里插入图片描述
添加链接描述
添加链接描述
添加链接描述

kafka的全局策略

Kafka的partition和block

Kafka有哪些技术特点,系统讲一讲

添加链接描述

Kafka如何保证消息的有序消费?

kafka中1个partition只能被同组的一个consumer消费
添加链接描述
添加链接描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Kafka消息堆积处理方案

添加链接描述
添加链接描述

幂等性

所谓的幂等性,是分布式环境下的一个常见问题,一般是指我们在进行多次操作时,所得到的结果是一样的,即多次运算结果是一致的。
也就是说,用户对于同一操作,无论是发起一次请求还是多次请求,最终的执行结果是一致的,不会因为多次点击而产生副作用。

kafka 如何不消费重复数据?比如扣款,我们不能重复的扣。

这个问题换种问法,就是kafka如何保证消息的幂等性。对于消息队列来说,出现重复消息的概率还是挺大的,不能完全依赖消息队列,而是应该在业务层进行数据的一致性幂等校验。

比如你处理的数据要写库(mysql,redis等),你先根据主键查一下,如果这数据都有了,你就别插入了,进行一些消息登记或者update等其他操作。另外,数据库层面也可以设置唯一健,确保数据不要重复插入等 。一般这里要求生产者在发送消息的时候,携带全局的唯一id。

项目中:在这里插入图片描述

写程序, 统计字符串字母出现的次数,试着改为并发的方式呢?

type LetterFreq map[rune]int
func LetterCount(strs []string) LetterFreq {}

查询接口调优,不能用缓存,要求实时性,怎么调优?

1、本地缓存
2、并行化
3、异步化
4、池化技术
5、分库分表
6、SQL 优化
7、事务相关
8、批量读写
9、锁的粒度
10、上下文传递
11、查询优化
避免一次从 DB 中查询大量的数据到内存中,可能会导致内存不足,建议采用分批、分页查询。
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

现在用户要查询一张表,当流控降级时,兜底方案应该是怎么样的?

用户下订单,订单按什么字段分表?分表之后,如果想按照某个时间段查询指定时间段内的所有用户的订单怎么办?
添加链接描述
添加链接描述
添加链接描述
添加链接描述

讲一下限流有什么具体的实现方案?

限流就是限制到达系统的并发请求数量,保证系统能够正常响应部分用户请求,对于超过限制的流量,可以用拒绝服务的方式或者返回一个比较友好的页面提示的方式来保证系统的可用性。

那限流的实现方式有:计数器,滑动窗口,漏桶,令牌桶等等。
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

设计题:设计一个短链接服务,尽可能多的说出能想到东西

在这里插入图片描述
读取全局计数器的时候要加锁

https://www.bilibili.com/video/BV1dy4y1E7A3/?spm_id_from=333.880.my_history.page.click&vd_source=0eaaad564f92d5c0b11b6c9639d86d38
https://blog.csdn.net/weixin_43247186/article/details/86678589
添加链接描述

项目数据库表怎么设计的.

表结构设计主要有两个目的,一是让表结构更加的更具有表现力,做到数据库表的自描述,减少注释甚至不使用注释;二是满足系统效率和扩展性的需要,让系统性能更好,后期维护更简单。
添加链接描述
添加链接描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

你怎么返回数据给前端

在项目开发中统一封装Api数据格式返回给前端这是最基本和常见的。

群聊是怎么实现的 # 设计一个聊天室系统,一步步展开

成员太多I0占用很多业务,这时候怎么优化
你怎么查聊天记录给前端
添加链接描述
添加链接描述
添加链接描述
添加链接描述

设计一个排行榜的后端

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

linux查询日志的命令、awk了解过吗?

添加链接描述

添加链接描述
添加链接描述

点赞模块设计如何优化可以支持高并发的场景

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

协程、线程、进程之间通讯方式有哪些?

添加链接描述
添加链接描述

Linux怎么看磁盘占用?

https://www.cnblogs.com/sylvia-liu/p/4866388.html

Linux怎么看内存占用?

free

Linux中top命令会展示CPU相关的那些时间维度的信息?

https://blog.csdn.net/Nicolege678/article/details/125558818

怎样批量修改一批文件替换文件中的某个占位符?

https://blog.csdn.net/weixin_42326851/article/details/127571161

程序运行中的堆和栈是什么?什么区别?

操作系统的数据存储,以及程序中的什么都存在哪里

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

平衡二叉树和红黑树

平衡二叉树
规则1:每个节点最多只有两个子节点(二叉)
规则2:每个节点的值比它的左子树所有的节点大,比它的右子树所有节点小(有序)
规则3:每个节点左子树的高度与右子树高度之差的绝对值不超过1

红黑树
规则1: 每个节点不是黑色就是红色
规则2:根节点为黑色
规则3:没有两个相邻的红色节点(红色节点不能有红色父节点或红色子节点)。
规则4:所有的叶子节点都是黑色
规则5:从任一节点到其子树中每个叶子节点的路径都包含相同数量的黑色节点。
添加链接描述
添加链接描述

什么是平衡二叉树、最小堆

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

队列,树,栈的应用场景和区别

添加链接描述

倒排索引原理;倒排索引和B+树索引比较一下

添加链接描述

es分词器怎么存储的

添加链接描述

Lucence

关于Lucene :就像很多业务系统是基于 Spring 实现一样,Elasticsearch 和 Lucene 的关系很简单:Elasticsearch 是基于 Lucene 实现的。ES 基于底层这些包,然后进行了扩展,提供了更多的更丰富的查询语句,并且通过 RESTful API 可以更方便地与底层交互。类似 ES 还有 Solr 也是基于 Lucene 实现的。在应用开发中,用 Elasticsearch 会很简单。但是如果你直接用 Lucene,会有大量的集成工作。

添加链接描述

动态映射,滚动索引

动态映射
添加链接描述
滚动索引
添加链接描述

es索引的过程

添加链接描述
添加链接描述

说下es的查询原理

ES写入数据的过程:
数据写入步骤如下:write -> refresh -> flush -> merge

一个新文档过来,会存储在 in-memory buffer 内存缓存区中,同时会记录 Translog。

这时候数据还没到 segment ,是搜不到这个新文档的。数据只有被 refresh 后,才可以被搜索到。

refresh 默认是1 秒钟执行一次refresh流程。ES 是支持修改这个值的,通过 index.refresh_interval 设置 refresh (冲刷)间隔时间。refresh 流程大致如下:

in-memory buffer 中的文档写入到新的 segment 中,但 segment 是存储在文件系统的缓存中。此时文档可以被搜索到,然后释放in-memory buffer。(注意: 此时Translog 没有被清空)

文档经过 refresh 后, segment 暂时写到文件系统缓存,这样避免了性能 IO 操作,又可以减少文档搜索到新数据的延时。refresh 默认 1 秒执行一次,性能损耗太大。一般建议稍微延长这个 refresh 时间间隔,比如 5 s。因此,ES 其实就是准实时,达不到真正的实时,对一些业务数据较大的企业级应用甚至延时很高,这里又衍生出很多高效同步的框架,比如DTS,这个我也不熟,就不献丑了,大家感兴趣的可以了解下。

segment 在文件系统缓存中,会有意外故障导致文档丢失。那么,为了保证文档不会丢失,需要将文档写入磁盘。那么文档从文件缓存写入磁盘的过程就是 flush。写入磁盘后,清空 translog。
Translog的用途就是:

保证文件缓存中的文档不丢失,系统重启时,从 translog 中恢复未持久化的数据,新的 segment 收录到 commit point 中。

总结:

write -> refresh -> flush

write:文档数据到内存缓存,并存到 translog

refresh:内存缓存中的文档数据,到文件缓存中的 segment 。此时已经可以被搜到

flush 是缓存中的 segment 文档数据写入到磁盘

添加链接描述

ES分页算法有哪些,举例

在这里插入图片描述

添加链接描述
添加链接描述

ES底层数据结构,深挖

添加链接描述
添加链接描述
添加链接描述
添加链接描述

es索引的过程,切词怎么切,切词算法

ik分词器
ik_max_word: 会将文本做最细粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,中华人民,中华,华人,人民共和国,人民,人,民,共和国,共和,和,国国,国歌”,会穷尽各种可能的组合,适合 Term Query;
ik_smart: 会做最粗粒度的拆分,比如会将“中华人民共和国国歌”拆分为“中华人民共和国,国歌”,适合 Phrase 查询。
添加链接描述
添加链接描述
添加链接描述
添加链接描述

es分布式架构

添加链接描述
添加链接描述

Mysql和ES数据同步方案汇总

https://blog.csdn.net/w1014074794/article/details/127124574

ES查询方法总结

添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述
添加链接描述

怎么学习新技术的(聊了一下我常看的一些技术网站)

添加链接描述
添加链接描述
在这里插入图片描述

牛客网项目总结

添加链接描述

深入项目,项目架构,模块组成,技术栈

项目中的技术亮点

深挖项目,实现细节,方案对比

项目所产生的价值,具体点,用一些案例或数字来佐证

项目难点,亮点

项目中最难的是什么?

讲一个比较有意思的事情,讲一讲其中的技术要素

QPS

QPS即每秒查询率,是对一个特定的查询服务器在规定时间内所处理流量多少的衡量标准。QPS = req/sec = 请求数/秒,即每秒的响应请求数,也即是最大吞吐能力。
QPS 原理:每天80%的访问集中在20%的时间里,这20%时间叫做峰值时间。 公式:( 总PV数 * 80% ) / ( 每天秒数 * 20% ) = 峰值时间每秒请求数(QPS) 。

职业发展

领导如何评价你

添加链接描述
可以这么说:“我的上司是一个对工作特别认真的人,他对工作的要求特别高,尤其是在细节上面,一丝不苟,在他的影响下,我们的工作返工率很低,我很感谢他对我的严格要求,让我格外地注重细节,做事更加细致谨慎。”

性格有什么优缺点

优点:
我做事很有计划性
列购物清单
在工作方面,在每一天的早晨,我都会思考今天该做些什么,然后列一张日程表,之后,就按这些表来做事,生活就会变得井然有序了。
适应能力强,有责任心和做事有始终
我比较善于带领别人一起工作。
我担任过班长,学生会干部,从无到有创建了系青年志愿者组织,还创建了一个很大的IT社团萤火虫俱乐部。同学们都说和我一起工作干劲很高,我想最主要的原因是因为我善于调动每个人的积极性。我觉得一个人无论才能大小,都希望能肩负一定的责任,所以在团队工作中,我十分重视让每个人都能展示自己的才能。
缺点:
喜欢追求细节 导致作业未能按期完成 先完成框架再去改善细节

不知如何拒绝 同学们找我帮忙 然后基本上都会去帮 很影响我自己的工作节奏和进度
后面就是会告诉他们 比如 我现在在忙 然后什么时间才有空 然后让他们考虑 看还需不需要 我去帮忙处理

控制情绪,心平气和的求解决 各退一步

把各自的观点说出来 然后静下心去分析,那个意见更好一些 或者两者意见否中和,取长补短? 不能一味的去否定别人 虚心才会使人进步 找出他们意见的长处加以赞美 然后再把不足 加上自己的观点

作为程序员,可以说自己拥有比较强的执行力,所以在面对项目的时候会有比较高的客户配合度,所以相比较来说自己的领导力就没有那么强。

再比如,自己对于程序开发会有自己的见解,所以常常会和产品经理产生一定的沟通意见,但是自己绝对会尊重客户和产品,因为觉得”头脑风暴”是会产生更好产品的动力。
在这里插入图片描述

遗憾的事情

当时没有珍惜机会?

感到很遗憾,所以我现在会比其他人更珍惜机会,更加努力的去争取,不会再在这方面留下遗憾。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/273904
推荐阅读
相关标签
  

闽ICP备14008679号