一面
1.自我介绍
2.mysql
- mysql索引
正常八股
- mysql主从同步机制
从节点上执行
start slave命令之后,从节点会创建一个I/O线程用来连接主节点,请求主库中更新的binlog,I/O线程接收到主节点binlog之后,保存在本地relaylog中,从库线程读取relaylog中的内容,解析成具体的操作并执行。
- mysql如何保证主从同步的数据一致性
1.异步复制
mysql默认的复制机制,事务提交并写入主库后就会返回成功给客户端,binlog更新后如果从库还没有更新会引起数据不一致的问题
2.全同步
事务提交后,必须等待全部从库全部执行相同事务后才会返回成功。缺点是会影响性能。
3.半同步
事务提交后,只需要等待其中一个从库记录relaylog的响应即可,不需要等待从库执行事务。
总结
异步复制会有数据不一致的风险,半同步和全同步可以保证数据一致性,但是全同步会影响数据库性能,所以一般生产环境会使用半同步的方式。
- 慢sql如何处理
使用explain关键字分析sql,如果没有索引建索引,没走索引则分析没走索引的原因。一般有以下几种情况:
1.索引命中的数据太大
2.对字段进行计算
3.不符合最左前缀匹配原则
还有尽量减少多表join,因为会产生笛卡尔积;查询字段尽量写出来,不要select *,有些情况下可以直接走索引返回,避免回表。
3.kafka
- kafka和rabbitmq对比
略
- kafka重复消费问题
发生的场景:
1.还没有提交offset时线程挂掉。
2.线程消费了,消费时间过长,超过session timeout时间,导致partition断开连接。此时还没提交offset,但是kafka会reblance,就会导致重复消费。
3.消费者重新分配partition的时候,可能出现从头开始消费的情况。
4.消费速度很慢,导致在一个session周期内心跳检测机制出问题,也会导致offset没提交从而导致重复消费。
- kafka结构
生产者,消费者,borker,topic,partition
一个topic为一类消息,每条消息必须指定一个topic。物理上,一个topic分成一个或多个partition,每个partition有多个副本分布在不同的broker中。每个partition都是一个append log文件,新增消息时会顺序写入append log,每条消息在log文件中的位置称为offset。消费时只需要修改offset的位置即可。
- kafka内存管理策略
1.基于时间:每隔一段时间删除部分数据
2.基础存储:partition大小超过指定大小时删除部分数据
4.go
- GMP模型
- 优势
- grpc框架,rpc协议和http协议的区别
5.系统架构
- 如何保证系统高并发和高可用
可以参考这位大佬的文章: 字节三面:如何设计一个高并发系统
6.k8s
- k8s如何实现事务的注册与发现
7.笔试题
- 两个协程交替输出字母和数字
要求格式:12AB34CD56EF78GH910IJ1112KL1314MN1516OP1718QR1920ST2122UV2324WX2526YZ2728
package main
import (
"fmt"
"sync"
)
var number = make(chan int)
var letter = make(chan int)
var wg = sync.WaitGroup{}
func printNumber() {
n := 0
for {
select {
case signal := <-number:
for i := 0; i < 2; i++ {
n += 1
fmt.Print(n)
}
if signal == 2 {
wg.Done()
return
}
letter <- 1
}
}
}
func printLetter() {
l := 'A'
for {
select {
case <-letter:
for i := 0; i < 2; i++ {
fmt.Print(string(l))
l += 1
}
if l >= 'Z' {
number <- 2
return
}
number <- 1
}
}
}
func main() {
wg.Add(1)
go printNumber()
go printLetter()
number <- 1
wg.Wait()
}
- 给定一个数组,找到和为target的最短子序列的长度,如果找不到返回0
例:nums = [2,1,2,6,3,4], target=7,应返回2,因为最短子序列为[3,4]
package main
import "fmt"
func getMinSplice(target int, nums []int) int {
// 滑动窗口,当sum值大于等于target时移动左指针,记录最小长度
if nums == nil || len(nums) == 0 {
return 0
}
left, right := 0, 0
sum := 0
minLen := len(nums) + 1
for right < len(nums) {
sum += nums[right]
for sum >= target {
if sum == target && right-left+1 < minLen {
minLen = right - left + 1
}
sum -= nums[left]
left += 1
}
right += 1
}
if minLen > len(nums) {
return 0
}
return minLen
}
func main() {
result := getMinSplice(7, []int{2, 1, 2, 6, 3, 4})
fmt.Print(result) // 2
}