HIDEYOSHI's BLOG - 面试
type: channel
link: https://blog.hideyoshi.top/tag/%E9%9D%A2%E8%AF%95/
items: GOALNG面试题-01
items: 进程、线程、协程
items: 设计模式
items: Redis面试题

GOALNG面试题-01
type: item
date: 2024-05-11T09:55:00+00:00
description: 自我介绍讲一个项目的点，因为用到了中间件平台的数据同步，于是开始鞭打数据同步。。如果同步的时候，插入了新数据怎么处理？binlog有什么用？binlog的数据格式有哪些？如何监听binlog？mysqldump 之后需要进行什么处理？（这个问的太细了，细到我都不知道面试官是什么意思？）唯一索引和联合索引有什么区别？联合索引可以是唯一索引吗？那mysql索引结构是什么样的？一个索引的建立过程是什么样的？如果我对age字段建立索引，建立的过程是什么样的？为什么走索引加快了？为什么age可以建立索引？sex字段就不行？为什么sex建立索引还是会扫全表？如果我订单表达到一定规模之后mysql单表是撑不住了，怎么办？具体你会怎么分库分表？分库分表如果进行条件查询？同步ES？不使用其他组件，单单是mysql怎么操作，所有表遍历找过去吗？索引会不会失效？ok，redis源码有了解吗？他的线程模型是什么样的？redis有哪些存储日志的形式？同步还是异步？那AOF具体是怎么存储日志的？AOF不断的写日志不是会有很多的io操作吗？怎么避免？RDB是怎么进行操作？那如果数据库和redis需要缓存一致性怎么解决？那我不考虑最终一致性，我要强一致性，怎么解决？ok，网络这块我也问问。http和https的区别是什么？https是怎么建立连接的？先建立什么？再建立什么？具体是怎么建立的ssl tls加密？http的请求头和响应头一般有什么信息，有什么用？ok，页的概念你清楚吗？为什么需要内存对齐？页碎是什么？go里面怎么样会发生死锁？死锁的场景具体有哪些？内存泄漏有哪些场景？怎么排查？goruntine泄漏的场景有哪些？怎么排查？进程、线程、协程有什么区别？协程能被 kill 掉吗？那协程应该怎么处理？那context一般有什么信息？有什么用途？那如果我要 clone 一个context，子context 和 父context 是一摸一样吗？为什么？singleflight 是什么？什么时候用的？如果这个goruntine超时怎么办？doChan方法具体是怎么实现的？为什么会有饥饿模式？什么时候会让出时间片？IO密集型和计算密集型的区别？这段代码会发生什么？为什么？具体是怎么溢出的？var a uint = 1 var b uint = 2 fmt.Println(a-b) 说出以下输出结果？为什么？func TestSlicePrint(t *testing.T) { a := []byte("AAAA/BBBBB") index := bytes.IndexByte(a, '/') b := a[:index] c := a[index+1:] b = append(b, "CCC"...) fmt.Println(string(a)) fmt.Println(string(b)) fmt.Println(string(c)) }这个锁是什么用的？这段代码有什么问题？func TestNumPrint(t *testing.T) { wg := sync.WaitGroup{} lock := sync.Mutex{} a := 0 b := 10 for i := 0; i < 5; i++ { go func() { if a > b { fmt.Println("done") return } lock.Lock() defer lock.Unlock() a++ fmt.Printf("i: %d \n", i) }() } wg.Wait() }最后手撕一题：整数反转。

进程、线程、协程
type: item
date: 2023-10-23T03:45:00+00:00
description: 进程进程是资源分配的最小单位，每个进程都有自己的独立内存空间，进程由进程控制块、程序段和数据段组成。进程控制块（PCB）保存进程运行期间相关的数据，是进程存在的唯一标志。程序段是能被进程调度程序调度到CPU 运行的程序的代码段。数据段用来存储程序运行期间的相关数据。进程是应用程序运行的载体，可看做是正在执行的程序。程序本身是没有生命周期的，只是存在于磁盘上的一些指令集合，但程序一旦被运行起来就是进程。启动后的进程，会依赖操作系统的调度完成生命周期的转换。由于每个进程都有独立的代码和数据空间，所以进程间的切换会有较大的开销。线程线程是CPU任务调度和执行的最小单位，一个进程中可以包含多个线程，这些线程可以并发运行，且共享进程提供的相同的代码和数据空间，每个线程都有自己独立的运行栈和程序计数器，线程间切换的开销小。协程协程，又称微线程，是一种用户态的轻量级线程，一个线程可以有多个协程。协程的调度完全由用户控制（也就是在用户态执行）。协程拥有自己的寄存器上下文和栈。协程调度切换时，将寄存器上下文和栈保存到线程的堆区，在切回来的时候，恢复先前保存的寄存器上下文和栈，直接操作栈则基本没有内核切换的开销，可以不加锁的访问全局变量，所以协程的上下文切换非常快。线程在进程的内部，它不能独立执行，必须依存于进程中，由进程提供多个线程的执行控制，进程和线程都可以并发的执行。协程抽象于线程之上，线程是被分割的CPU资源, 协程是组织好的代码流程, 协程需要线程来承载运行。与线程相比，协程占用资源小，由用户调度，切换开销小，同一个线程中的协程不需要使用锁，执行效率更高。

设计模式
type: item
date: 2023-10-09T10:11:00+00:00
description: 一、什么是设计模式设计模式，是一套被反复使用，多数人知晓的，经过分类编目的，代码设计经验的总结。使用设计模式是为了可重复代码、让代码更容易被他人理解、保证代码可靠性、程序重用性。二、为什么要学习设计模式看代码源码：如果你不懂色剂模式去看源码，你就会很迷茫，你会寸步难行看看前辈的代码：你去个公司难道都是新项目让你接手？很有可能是解盘的，前辈的开发难道不用设计模式？编写自己的理想中的好代码：我个人反正是这样的，对于我自己开发的项目我会很认真，我对它比我对女朋友还好，把项目当初自己儿子一样三、设计模式分类创建型模式：单例模式、工厂方法模式、抽象工厂模式、建造者模式、原型模式结构型模式：适配器模式、桥接模式、组合模式、装饰模式、外观模式、亨元模式、代理模式行为型模式：访问者模式、模板模式、策略模式、状态模式、观察着模式、备忘录模式、中介者模式、迭代器模式、解释器模式、命令模式、责任链模式四、设计模式的六大原则开放封闭原则（Open Close Principle）原则思想：尽量通过扩展软件实体来解决需求变化，而不是通过修改已有代码来完成变化描述：一个软件产品在生命周期内，都会发生变化，既然变化是一个既定的事实，我们就应该在设计的时候尽量适应这些变换，以提高稳定性和灵活性。优点：单一原则告诉我们，每个类都有自己负责的职责，里氏替换原则不能破坏继承关系体系里氏代换原则（Liskov Substiution Principle）原则是想：是用的基类可以在任何地方使用继承的子类，完美替换基类。大致意思是：子类可以扩展父类的功能，但不能改变父类原有的功能。子类可以实现父类的抽象方法，但不能覆盖父类的抽象方法优点：增加程序健壮型，即使增加了子类，原有的子类还可以继续运行，互不影响。依赖倒转原则（Dependence Inversion Principle）一览倒置原则的核心思想是面向接口编程。依赖倒转原则要求我们在程序代码中传递参数时或在关联关系中，尽量引用层次高的抽象类这个时开放封闭原则的基础，具体内容是：对接口编程，依赖于抽象而不依赖于具体接口隔离原则（Interface Segregation Principle）这个原则的意思是：使用多个隔离的接口，比使用单个接口要好。还是一个降低类之间的耦合度的意思，从这儿我们看出，其实设计模式就是一个软件的设计思想，从大型软件架构出发，为了升级和维护方便，所以上文中多次出现：降低依赖，降低耦合。例如：支付类的接口和订单类的接口，需要把着俩类别的接口变成两个隔离的接口迪米特法则（最少知道法则）（Demeter Principle）原则思想：一个对象应当对其他对象有尽可能少的了解，简称类的解耦大概意思就是一个类尽量减少对其他类的依赖，原则是低耦合，高内聚，只有使各个模块间的耦合尽量的低，才能提高代码的复用率优点：低耦合、高内聚单一职责原则（Principle of single responsibility）原则思想：一个方法只负责一件事情。描述：单一职责原则很简单，一个方法一个类只负责一个职责，各个职责的程序改动，不影响其他程序，这是常识，几乎所有程序员都会遵循这个原则。优点：降低类和类的耦合，提高可读性，增加可维护性，降低可变性的风险。五、单例模式1. 什么是单例模式保证一个类只有一个实例，并且提供一个访问全局访问点2. 那些地方用到了单例模式网站的计数器，一半也是采用单例模式实现，否则难以同步应用程序的日志应用，一般都是单例模式实现，只有一个实例操作才好，否则内容不好追加显示。多线程的线程池的设计一般也是采用单例模式，因为线程池要方便对池中的线程进行控制Windows的（任务管理器）就是很典型的单例模式，他不能打开两个Windows的（回收站）也是典型的单例模式。在整个系统运行过程中，回收站纸维护一个实例。3. 单例优缺点优点：单例模式中，活动的单例只有一个实例，对单例类的所有实体话得到的都是相同一个实例。这样就防止其他对象对自己实例话，确保所有对象都访问一个实例单例模式具有一定伸缩性，类自己来控制实例话进程，类就在改变实例话进程上又相应的伸缩性提供了一个对唯一实例的受控访问。由于在系统内存中只存在一个对象，因此可以节约系统资源，当需要频繁创建和销毁的对象是单例模式无疑可以提高系统的性能允许可变数目的实例避免共享资源的多重占用缺点：不适用于变化的对象，如果同一类型的对象总是要在不同的用例场景发生变化，单利就会引起数据的错误，不能保存彼此的状态。由于单例模式中没有抽象层，因此单例类的扩展有很大的困难。单例类的职责过重，在一定程度上违背单一职责原则滥用单例带来的一些负面问题，如果为了节省资源将数据库连接池对象设计位单例类，可能会导致共享连接池对象的程序过多而出现连接池溢出；如果实体化的对象长时间不被利用…

Redis面试题
type: item
date: 2023-09-27T12:44:00+00:00
description: 一、Redis是单线程还是多线程Redis6.0之前的单线程指的是其网络IO和键值对读写是由一个线程完成的Redis6.0引入多线程指的是网络请求采用多线程，而键值对读写命令依然是单线程处理的，所以redis依然是并发安全的也就是只有网络请求和模块数据操作模块是单线程的,而其他的持久话、集群数据同步等，其实是由额外的线程执行的二、Redis单线程为什么会这么快命令执行基于内存操作的，一条命令在内存里操作的时间是几时纳秒命令执行是单线程操作，没有线程切换开销基于IO多路复用机制提升Redis的IO效率高效的数据储存结构，全局hash表以及多种高效数据结构，比如：跳表，压缩列表，链表等等三、Redis底层数据是如何跳表来储存的和数据库索引差不多详情可见数据库索引四、Redis Key过期了为什么内存没释放你在使用Redis时，肯定经常使用SET命令SET除了可以设置key- value以外，还可以设置key的过期时间，就像下面这样：127.0.0.1:6379> SET hideyoshi hidesyohi EX 120 OK 127.0.0.1:6379> TTL hideyoshi (integer) 117此时如果想要修改key的值，但只是使用SET命令，而没有加上过期时间的参数，那么这个key的过期时间将会被擦除127.0.0.1:6379> SET hideyoshi hidesyohi OK 127.0.0.1:6379> TTL hideyoshi (integer) -1导致这个问题的原因在于：SET命令如果不设置过期时间，那么Redis会自动擦除这个key的过期时间如果你发现Redis的内存持续增长，而且很多key原来设置了过期时间，后来发现过期时间丢失了，很有可能是因为这个原因导致的。这是你的Redis中就会存在大量不过期的key，消耗过多的内存资源所以，你在使用SET命令是，如果刚开始设置了过期时间，那么修改这个key，也务必要加上过期时间参数，避免过期时间丢失问题Redis对过期key的处理一半有惰性删除和定时删除两种策略惰性删除：当读/写一个已经过期的key时，会触发惰性删除策略，判断key是否过期，如果过期了直接删除这个key定时删除：由于惰性删除无法保证冷数据被及时删除，所以Redis会定期（默认100ms）主动淘汰一批已经过期的key，这里的一批只是部分过期key吗所以可能会出现部分key已经过期但还没有被清理掉的情况，导致内存没有被释放五、Redis Key没有设置过期时间为什么被Redis删除了当redis已用内存超过maxmemory限定时，触发主动清理策略主动清理策略在Redis4.0之前一共实现了6种内存淘汰策略，在4.0后，又增加了两种，总共8种：针对设置了过期时间的key做处理：volatile-ttl：在筛选时，会针对设置了过期时间的键值对，根据过期时间的先后进行删除，越早过期越先被删除。volatile-random：在设置了过期时间的键值对中，进行随机删除。volatile-lru：会使用LRU算法筛选设置了过期时间的键值对删除。（最久未使用）volatile-lfu：会使用LFU算法筛选设置了过期时间的键值对删除。（最不常使用）对所有key做处理：allkeys-random：从所有键值对中随机选择并删除数据allkeys-lru：所有key使用LRU算法删除（最久未使用）allkeys-lfu：所有key使用LFU算法删除（最不常使用）不处理：noeviction：不会剔除任何数据，拒绝所有写入操作并返回客户端信息"（error）OOM command not allowed when used memory"，此时Redis只响应读操作。六、删除Redis Key的命令会阻塞Redis吗删除命令的时间复杂读：O(N), N为被删除的key的数量删除单个字符串的key，时间复杂度为0(1).删除单个列表、集合、有序集合或哈希表类型的的key，时间复杂度为0(M),M为以上数据结构内的元素数量。结论：会阻塞Redis七、Redis主从、哨兵、集群架构优缺点比较哨兵模式在Redis3.0以前的版本要实现集群一般是借助哨兵模式sentinel工具来监控master节点状态，如果master节点异常，则会做主从切换，将一台slave作为master，哨兵的配置略微复杂，并且性能和高可用等各方面表现一般，特别是在主从切换的瞬间存在访问瞬断的情况，而且哨兵模式只有一个主节点对外提供服务，没法支持很高的并发，且单个主节点内存也不宜设置过大，否则会导致持久化文件过大，影响数据恢复或主从同步效率高可用集群模式reids集群是有一个多个主从节点群组成的服务器群，他具有复制、高可用和分片特性。R…