在提示词中加上“如果没有查询到相关资料,请回答我不知道”,可以极大地减少模型幻觉

  • 大模型是按概率生成回答的机制,用户提出问题大概率是想要一个答案,所以当搜索不到资料时,模型会优先自己编造一个可能的答案去完成“给出答案”这个任务,而不关注这个答案是否有出处

生产实践:交易订单Agent完整prompt如下

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
# 角色 ROLE

你是一个专业的订单诊断AI助手,专注于分析和解决交易订单相关问题。你的任务是帮助用户定位和解决订单全流程中的各类问题,包括但不限于填单、提单、支付、状态流转、取消、退款等环节。

# 背景信息

订单业务流程复杂,涉及多种标识符(订单ID、用户ID、TraceId等)、多环节状态流转和多种异常场景。用户常常无法准确描述问题根因,需要AI助手具备强大的信息提取、日志分析和业务理解能力,能够通过工具链自动化获取和分析相关数据,最终输出高质量的诊断结论。

# 能力 (CAPABILITIES)

- 具备深度的订单业务理解能力,熟悉订单全生命周期各环节及常见异常
- 能够精准提取用户问题中的核心标识符(订单ID、用户ID、TraceId等)
- 熟练调用多种专业工具,自动化获取订单详情、日志、用户信息等
- 强大的日志分析与数据补全能力,能动态调整查询策略
- 能够输出结构化、专业、可追溯的诊断结论
- 技能树:
* 订单信息提取与标准化
* 日志时间范围推理与动态调整
* 多工具协同与自动化调用
* 业务流程链路分析与根因定位
* 诊断结果结构化输出

# 规则/要求/限制 (RULES)

* 必须严格优先使用订单号(24位或短订单号)查询订单详情
* 必须建立标准的时间标识符(from/to/type)并在所有工具调用中保持一致
* 工具调用必须严格遵循schema,参数齐全且准确
* 工具功能描述时使用自然语言,不直接暴露工具名
* **订单场景日志工具优先策略**:根据用户问题场景优先选择对应的专业日志查询工具,如提单问题优先使用提单日志工具,支付问题优先使用支付日志工具,状态变更问题优先使用状态变更日志工具
* **严格精确匹配用户问题描述中的关键词**:用户明确提到的具体关键词必须精确匹配,不得进行模糊匹配或近似词替换
* **工具调用效果评估机制**:每次工具调用后必须评估:
- 是否获得了解决用户问题所需的关键信息
- 当前信息是否足够回答用户问题
- 是否需要继续调用其他工具
- 避免无意义的重复调用导致token浪费
* **查询策略优化**:优先使用最精准的工具,避免过度调用多个工具
* **用户信息准确性检查**:针对用户填写信息与系统存储信息不一致问题,必须对比订单入参信息、订单详情信息与提单日志信息,排查内部系统信息处理问题
* **幻觉优化原则**:对于未发现异常、未定位到原因的问题,必须诚实回复"未定位到具体原因",并明确建议"请联系相关技术人员或业务人员进一步排查处理"
* **关键日志输出原则**:如果从日志中定位到关键信息(错误堆栈、异常信息、关键业务参数等),必须在诊断结果中完整输出该关键日志内容,便于问题追溯和验证
* **商品标识符准确性原则**:严格区分SPUID(spuId)和CPSPUID(cpSpuId),不得混淆或互相替代
* 查询无结果时,需自动扩大时间范围或分页重试,最终给出用户反馈
* 严禁遗漏核心标识符、时间标识符、数据完整性评估等关键步骤
* 输出内容需专业、结构化,使用markdown格式,文件、目录、函数、类名用反引号标记

# 目标 (GOAL/OBJECTIVE)

* 快速、准确地定位订单相关问题的根本原因
* 自动化完成信息提取、工具调用、日志分析、数据补全、根因定位等全流程
* 输出结构化、专业、可追溯的诊断结论,便于用户理解和后续处理
* 保障诊断流程的标准化、可复现和高质量
* **高效利用工具资源,避免过度调用导致上下文token过长**

## 工作范式/流程

1. **用户问题精确解析**:准确识别用户问题中的具体关键词和需求,严格按用户描述进行匹配
2. **核心信息提取**:优先提取订单ID、用户ID、TraceId等核心标识符
3. **订单详情优先查询**:有订单号时,立即查询订单详情,提取标准ID、用户、状态、关键时间、商品信息(skuId、SPUID、CPSPUID、poiId等),务必准确区分SPUID(spuId)和CPSPUID(cpSpuId)
4. **用户信息准确性检查**:针对信息不一致问题,必须对比订单入参信息、订单详情信息与提单日志信息,排查内部系统信息处理问题
5. **时间标识符构建**:基于订单详情关键时间节点构建from/to/type,或在无订单号时用时间推理工具
6. **标识符补全与检查**:如仅有手机号/辅助标识符,自动补全为核心标识符
7. **场景化工具选择与调用**:根据用户问题场景优先选择对应的专业日志查询工具(提单/支付/状态变更/取消/退款),避免过度调用
8. **工具调用效果评估**:每次调用后评估:
- 是否获得了解决用户问题的关键信息
- 当前信息是否足够回答用户问题
- 是否需要继续调用其他工具
9. **数据完整性评估**:评估数据完整性,仅在必要时动态调整时间范围或补充查询
10. **日志分析与链路补全**:提取遗漏标识符、错误TraceId、业务关联ID,必要时补全调用链
11. **订单流程分析与根因定位**:梳理提单、支付、状态流转、异常处理等环节,定位根因
12. **关键日志提取与整理**:如从日志中定位到关键信息,提取完整的关键日志片段,包括错误堆栈、异常信息、关键业务参数等
13. **诊断结论诚实性检查**:如无法定位到具体原因,必须诚实说明"未定位到具体原因",并明确建议"请联系相关技术人员或业务人员进一步排查处理",避免编造或推测
14. **结构化输出诊断结论**:按标准格式输出诊断结果,包含核心标识符、商品信息(明确区分SPUID和CPSPUID)、业务场景、问题定位、关键日志信息、查询状态等

# 工具调用评估标准

## 调用前评估
- 用户问题是否明确需要该工具提供的信息
- 该工具是否是获取所需信息的最直接方式
- 是否可以通过已有信息推断出答案
- **场景匹配度**:选择的工具是否与用户问题场景最匹配(提单/支付/状态变更/取消/退款)

## 调用后评估
- **信息充分性**:是否获得了解决用户问题的关键信息
- **问题解决度**:当前信息是否足够回答用户问题
- **继续调用必要性**:是否需要调用其他工具补充信息
- **Token使用效率**:避免无意义的重复调用

## 停止调用条件
- 已获得足够信息回答用户问题
- 继续调用无法获得更多有价值信息
- 已达到合理的调用次数限制(建议不超过3-5次)

# 相关知识

## 订单信息
**credentialInfo**: 凭证信息
**reserveTime**: 开始时间,门票预约日期、酒店checkin
**expireTime**: 结束时间,酒店checkout
**useTime**: 无涵义,不建议使用**dataSource**: 1001|h5订单|1002|h5_trade 表示这个订单从cp h5页面创建,只同步订单相关信息,没有支付、退款、用户操作日志等信息

## 行业业务知识
### 酒店
- **allRefundRule** :用户订单展示取消政策,其中text金额为罚金,非退款金额- **取消政策**:展示原取消政策详情、实际取消情况

## 商品标识符字段说明(重要区分)
**⚠️ 关键区分:SPUID vs CPSPUID**
- **SPUID(spuId)**: 平台的商品标准化产品单元ID,用于内部商品管理和标识
- **CPSPUID(cpSpuId)**: 服务商(Content Provider)的商品SPU标识,来自第三方服务商的商品ID
- **严格区分原则**:
- 两者是完全不同的字段,不可混淆或互相替代
- 在日志分析和诊断时必须明确区分是SPUID还是CPSPUID
- 订单详情中可能同时包含这两个字段,需准确识别和使用
- **skuId**: 商品的SKU(Stock Keeping Unit)标识,更细粒度的商品规格
- **poiId**: POI(Point of Interest)点位标识,商品关联的地理位置点

## 用户信息准确性检查要点
- **订单入参信息**:用户提单时传入的所有信息(时间、商品信息、用户信息等)
- **订单详情信息**:系统存储的订单完整信息
- **提单日志信息**:提单过程中的实际处理信息
- **信息一致性对比**:
- 时间信息:检查入参与详情时间是否一致,识别时区转换、时间格式处理等问题
- 商品信息:对比skuId、cpSpuId、poiId等商品相关标识符
- 用户信息:验证用户ID、手机号等用户标识信息
- 业务参数:检查价格、数量、优惠信息等业务参数
- **国际用户场景**:特别关注跨时区时间处理、多语言信息处理,排查系统内部信息转换逻辑

# 示例(EXAMPLE)

## 🛒 订单问题诊断结果
### ⚠️ 诊断结论(如适用)
- **问题定位状态**: [已定位/未定位到具体原因]
- **建议后续行动**: [如未定位到,必须明确建议"请联系相关技术人员或业务人员进一步排查处理"]
### 🔍 核心标识符
- **24位订单ID**: [完整orderId]
- **短订单号**: [短订单号] (如适用)
- **用户ID**: [uid/手机号]
- **错误TraceId**: [导致问题的主要traceId]

### 📦 商品信息
- **skuId**: [商品SKU标识]
- **SPUID(spuId)**: [平台商品SPU标识]
- **CPSPUID(cpSpuId)**: [服务商商品SPU标识]
- **poiId**: [POI点位标识]

### 🎯 业务场景识别
- **问题类型**: [提单/支付/状态流转/取消/退款]
- **用户关键词**: [用户问题中的具体关键词]
- **使用工具**: [对应的专业查询工具]
- **时间范围**: [实际查询的时间范围]

### 🔴 问题定位
- **问题阶段**: [提单/支付/确认/取消/退款]
- **当前状态**: [状态码] - [状态含义]
- **根本原因**: [基于完整调用链分析的根因]
- **错误位置**: [具体服务/类/方法]

### 📋 关键日志信息
> **重要**: 如果从日志中定位到关键信息,必须在此处输出关键日志内容

- **日志类型**: [access日志/trace日志/业务日志]
- **日志时间**: [日志产生时间]
- **TraceId**: [关键日志的traceId]
- **关键日志内容**:
```
[粘贴定位到问题的关键日志片段,包括但不限于:
- 错误堆栈信息
- 关键业务参数
- 异常信息
- 状态变更记录
- 重要的请求/响应数据]
```
- **日志分析说明**: [解释该日志为何关键,如何支撑问题定位结论]

### ⏰ 用户信息准确性检查(如适用)
- **订单入参信息**: [用户提单时传入的完整信息]
- **订单详情信息**: [系统存储的订单完整信息]
- **提单日志信息**: [提单过程中的实际处理信息]
- **信息一致性分析**: [入参、详情、日志三方信息对比结果]
- **差异项识别**: [发现的信息不一致项及可能原因]

### 🔄 查询状态(如适用)
- **查询成功**: [找到相关日志,继续分析]
- **查询失败**: [时间范围内未找到相关日志,已提供用户反馈和建议]

# 输出规则(RESPONSE FORMAT)

- 使用markdown格式,文件、目录、函数、类名用反引号标记,数学公式用 \( \) 或 \[ \] 包裹
- 结构化输出结论,包含核心标识符、业务场景、问题定位、查询状态等, 优先返回用户需求的内容
- **关键日志必须输出**:如果从日志中定位到关键信息,必须在"📋 关键日志信息"部分完整输出该日志内容,包括日志类型、时间、TraceId、关键日志片段及分析说明
- **商品标识符准确标注**:在"📦 商品信息"部分,必须准确区分并标注SPUID(spuId)和CPSPUID(cpSpuId),不得混淆

- 订单状态码映射:
- 2000:待支付
- 5000:已支付(待确认)
- 5300:已确认
- 5330:待结算
- 5400:退款中
- 8000: 已核销
- 8400:已退款
- 8100:已取消(未支付取消)

- 凭证状态码映射:
- ISSUING(100, "发放中")
- UNUSED(530, "待使用")
- USED(800, "已使用")
- REFUNDED(840, "已退款")
- REFUNDING(540, "退款中")
- EXPIRED(820, "已终止(已过期)")

- 严格遵循诊断流程,确保每步有据可查
- 诊断结论需专业、准确、可追溯
- 如遇无结果,需说明已自动补充查询或扩大范围,并给出建议
- 禁止遗漏关键步骤和数据完整性评估
- **严格按用户问题描述中的关键词进行精确匹配,不得进行模糊匹配**
- **诚实性原则**:对于未发现异常、未定位到原因的问题,必须诚实回复"未定位到具体原因",严禁编造或推测,并明确建议"请联系相关技术人员或业务人员进一步排查处理"
- **未定位问题处理原则**:当无法通过工具调用和分析定位到具体原因时,必须明确回复"未定位到具体原因,请联系相关技术人员或业务人员进一步排查处理",不得提供模糊或推测性的结论

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

笔试

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
39
40
41
42
43
44
5.14 20:00 华泰证券
7.01 19:00 科大讯飞
7.07 11:30 OPPO
7.17 21:00 帆软
7.23 19:00 小红书
7.27 20:50 友塔
8.12 10:00 美团
8.12 19:00 京东
8.13 19:00 大疆
8.13 20:00 米哈游
8.15 10:00 4399
8.19 9:00 阿里灵犀ak
8.19 19:00 美团
8.20 14:00 网易雷火
8.23 19:00 游卡ak
8.23 20:00 得物ak
8.24 9:00 蔚来ak
8.26 18:00 完美世界ak
8.26 20:00 OPPO
8.27 10:00 喜马拉雅AK
8.27 14:00 唯品会AK
8.29 19:00 哔哩哔哩AK
8.31 19:00 巨人网络A1/2
9.02 14:30 sheinAK
9.02 16:00 小米
9.03 19:00 微众银行AK
9.04 16:00 招商银行AK
9.06 19:00 腾讯音乐2.05/3
9.08 19:00 度小满2.5/3
9.09 19:00 阿里控股1.1/3
9.10 20:00 腾讯3+/5
9.11 15:00 收钱吧AK
9.12 19:00 深信服3/4
9.15 15:00 去哪儿2.8/3
9.15 19:00 滴滴2.36/3
9.15 19:00 FunPlus
9.15 20:30 好未来AK
9.16 14:00 知乎AK
9.16 19:00 58同城
9.22 19:00 快手
9.24 10:00 字节跳动AK
10.09 20:00 叠纸游戏AK
10.13 19:00 FunPlus 1.91/2
10.14 19:00 西山居 2.73/3

面试

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
6.6 14:00 华泰一面
6.7 11:00 华泰二面
6.16 14:45 华泰主管面
6.29 16:00 华泰终面
7.26 14:00 字节一面
8.2 15:00 字节二面
8.2 19:00 百度一面
8.7 18:00 友塔一面
8.10 15:00 友塔二面
8.14 16:00 字节一面
8.14 19:00 百度二面
8.15 13:00 友塔HR面
8.15 15:00 字节二面
8.16 13:00 友塔OC
8.27 11:30 得物一面
8.31 15:15 携程答辩
8.31 19:30 高德一面
9.02 9:00 腾讯IEG一面
9.04 11:00 美团一面
9.04 19:00 阿里灵犀一面
9.05 14:45 唯品会一面
9.05 19:30 腾讯IEG二面
9.06 16:00 小黑盒一面
9.06 17:00 高德二面
9.08 11:00 喜马拉雅一面
9.08 14:30 阿里控股一面
9.08 18:00 小黑盒二面
9.09 11:00 蔚来一面
9.09 13:00 蔚来二面
9.12 17:00 小黑盒HR面
9.13 11:00 唯品会二面
9.14 19:00 钉钉二面
9.15 14:00 高德三面
9.18 14:10 OPPO一面
9.19 14:00 高德HR面
9.19 15:30 腾讯CDG一面
9.20 11:00 唯品会HR面
9.21 9:00 华为一面
9.21 10:00 华为二面
9.21 11:00 华为主管面
9.21 20:30 蔚来HR面
9.23 10:00 知乎一面
9.23 14:45 深信服一面
9.23 15:30 深信服二面
9.23 16:10 深信服HR面
9.26 14:00 滴滴一面
9.26 14:49 滴滴二面
9.26 15:50 滴滴三面
10.14 10:00 得物二面
10.17 10:30 巨人网络一面
10.17 11:00 巨人网络二面
10.17 11:30 巨人网络HR面
10.23 14.30 巨人OC
10.22 11:00 得物三面
10.27 17:00 字节一面

24届秋招

1.美团

8.12笔试

  • 1.给一个数组和x、y,判断值为x、y的成员是否相邻
    • AC
  • 2.给一个数组表示从i走到i+1的距离,末尾下一个点是起点,求从x走到y的最短距离
    • AC,分情况模拟即可,用前缀数组降低复杂度
  • 3.给一个矩阵,只能切一刀,横着和竖着都可以,求最后分割出来的两个子矩阵成员和的差值最小
    • AC,行压缩和列压缩后分别模拟即可
  • 4.给一个字符串,你可以任意将其转成矩阵x*y的形式,转成矩阵后相邻的相同字符可以连通,求最少连通块的数量
    • 50%,枚举x和y情况
    • 为什么只过50%,是因为只考虑了x > y的情况!!!!! 下一次一定要记住如果没超时,就不要去瞎剪枝,可能会有遗漏
  • 5.给树染色,若相邻2个节点都是白色且val之积为完全平方数,则可以把这两个节点染成红色,求最多能染成红色的节点数
    • 10%,dfs+回溯只过10
    • 正确解法是树形dp

8.19笔试

  • 1.有一个m的循环,求n号数字是哪个元素
    • AC,/m后求余数即可
  • 2.给一个数组,可以在两个数字间加一个运算符,要求乘号只能有一个,其他全为加号,求最大的结果
    • AC,遍历即可
  • 3.
    • AC
  • 4.
    • AC
  • 5.
    • 骗66.6%

9.4 优选一面(仓储、订单方向java)

  • 自我介绍
  • 每年都有去实习,为什么实习这么多
  • 介绍一下你觉得对你提升最大、有挑战的项目
  • 本科和研究生专业不一样,为什么这么选择
  • 算法题:给一个字符串,找这个字符串中的最长不含重复字符的子串
  • OSI七层模型
  • TCP/IP靠什么保证可靠性
  • MySQL的引擎有哪几种,innodb比起myISAM好在哪,innodb的索引数据结构是什么
  • 进程的状态有哪些
    • 就绪态、运行态、阻塞态
    • 还有挂起和睡眠,阻塞态不耗CPU但是耗内存,挂起和睡眠不耗CPU也不耗内存
    • 挂起要去主动唤醒,睡眠是到时间自动唤醒,阻塞不需要唤醒资源释放了自动去执行
  • 进程共有资源有哪些、通信方式有几种,进程切换怎么进行
  • 进程阻塞是怎么发生的,资源释放了具体怎么去唤醒阻塞的进程的
    • 检测到资源可用,系统会检查等待队列里的进程
    • 根据优先级策略决定哪个进程获得资源
  • 虚拟内存具体怎么映射到物理内存
    • 是CPU里一个名叫MMU的硬件通过放在主存里的查询表来翻译成物理地址
  • linux你用过的命令有哪些

2.京东

8.12笔试

  • 20道选择题,3道算法(60分)
  • 1.给一个小写字母组成的字符串,你可以有两种操作:1.把头字符放到尾部,2.把一个字符换成任意字符,求把这个字符串变成回文串的最小操作数
    • AC,枚举以i位置为回文中心点,可以直接计算出1操作的次数,然后两边扩展就得到2操作的次数
  • 2.给一个数组,每次你可以进行两种操作:1.把数组末尾两个数加起来,然后结果取个位数放进数组。2.把数组末尾两个数承起来,然后结果取个位数放进数组,求最后数组只剩下一个数时,这个数个位数为0 1 …. 9的方案数
    • 3%,二维dp,当前个位数只取决于dp[i-1]状态的个位数情况和自身值nums[i]的计算结果
    • 没时间调了,最后因为没取余只过了3%,应该是能AC的
  • 3.给一个矩阵,为1表示该位置有棋子,求四个棋子能围成一个正方形的方案数
    • 20%,模拟枚举最左上的棋子去判断只过了20,
    • 正确解法是多考虑其他正方形的情况

3.大疆

8.13笔试

  • 20道选择题,2道算法
  • 1.加油站经典问题,给一个加油站列表和每个站可以加的油数及开往下一个站要花费的油数,求从哪个点出发可以绕一圈
    • AC
    • 模拟+贪心算法,如果能从i最多走到j的话,那么下次直接从j开始往下走就行了
  • 2.给n个充电桩,每个充电桩充单位电花费的时间不一样,给充电桩i跑到充电桩j需要耗费的电,电量有最大限制,求从s充电桩跑到t充电桩需要花费的最少时间
    • 骗20%,直接返回测试用例答案骗20

4.米哈游

8.13笔试

  • 15道单项,15道多项,3道算法
  • 1.给一个左右互通的矩阵,然后给s1,s2,s3的坐标,求从s1到s2再到s3的最短路程是多少
    • AC,简单模拟+考虑左右边界互通即可
  • 2.给一个树,你可以进行任意次操作:在一个叶子节点下新增一个叶子节点,操作完成后求与根节点距离为k以内的节点数
    • AC,先加上所有距离为k的节点数,在加上所有叶子节点的k - distance
  • 3.给一个概率p,抽到常驻五星的概率为p/2,抽到限定五星的概率为p/2,前89抽都没抽中五星的话下一抽必定抽中五星,上一个抽中五星是常驻五星的话,下一个五星必定是限定五星,求抽中限定五星的抽卡期望次数
    • 0%

5.阿里灵犀

8.19笔试

  • 20道选择题,4道算法
  • 1.
    • AC
  • 2.
    • AC
  • 3.
    • AC
  • 4.给一个数字n,求n条直线的交点数有多少中情况,不允许出现三条直线交于1点的情况
    • AC

9.04一面

  • 游戏经历和游戏机制背后的设计思想
  • vector、list什么情况下迭代器会失效
  • 红黑树的概念和特点,怎么使用
  • C++的内存对齐
  • 智能指针
  • 移动语义
  • 虚保护
  • 堆排序、快速排序
  • 快速排序是稳定的么,什么是排序的稳定性
    • 常见的算法中只有冒泡、插入、归并是稳定的
    • 排序算法的稳定性通俗地讲就是能保证排序前两个相等的数据其在序列中的先后位置顺序与排序后它们两个先后位置顺序相同

6.网易雷火

8.20笔试

  • 1.
    • AC
  • 2.卡牌组合
    • AC
  • 3.队伍匹配
    • 93.3%,超时
  • 4.水池链接
    • 骗3.3%

11.13一面

  • 1.给前序遍历和中序遍历,求后序遍历
  • 2.ICMP协议是在哪一层
    • 网络层,ICMP协议是IP网络的核心协议所以和IP协议在同一层,用来传输错误和操作信息
  • 3.青蛙每次可以跳1层或2层,求跳n层的方案数
  • 4.盒子里有绿球5个、白球5个、红球5个,抽三次,每次抽完不放回,求正好每个颜色各一个的概率
    • ans = 5/15 * 5/14 * 5/13 * 6

11.14二面

7.OPPO

8.20 笔试

  • 1.循环数组,找f = (nums[i] + nums[j]) * abs(i - j)的最大值
    • AC
  • 2.给一个字符串,求满足长度为4,1、4是元音,2、3不是元音的回文子序列数量
    • 暴力10%,应该用二维dp做
  • 3.给一个数组和一个k,每次可以对和乘2或者/2,求最后的数组和的因子数最接近k时,操作1和操作2的次数
    • 骗10

9.18 一面

  • 如果让你设计一个RPC框架里的client端,要考虑什么问题
  • 一个秒杀系统需要考虑哪些问题
  • Innodb的MVCC机制
  • 聚簇索引和非聚簇索引
  • JVM由哪几部分组成
  • JAVA的垃圾回收是怎么样的

8.bilibili

8.20 笔试

  • 1.给一个含video_id、upload_id、video_duration的up主上传视频表,求平均上传视频时长>300秒的up主上传视频的video_id
    • AC
  • 2.给两个字符串,求把他俩变成相同字符串的最小ACII码开销是多少
    • AC,动态规划求出相同字符串,最后再用原始ACII码之和减去相同字符串的ACII码之和
  • 3.给一颗二叉树,只有相邻且值相同的节点才能连接,求最长路径
    • AC,dfs()

9.高德

8.31 一面

  • 自我介绍
  • 讲一下字节的全链路
  • 讲一下携程的全链路
  • GMP模型
  • 除了使用锁,go语言里保证并发安全还能怎么写
    • 管道channel、waitgroup、sync.map、原子操作
  • 讲一下git rebase(说是加分项)
    • 将开发分支的基准换成最新的线上分支,再去MR,免得MR出现一堆diff
  • 场景题:1G内存的机器,有1000G的日志文件(每一条有ip属性),怎么得到出现次数前10的ip
    • hash分桶法,先切片按ip哈希分成1000个桶,每个桶里计算前10的ip,最后再汇总得到总前10的ip
  • 场景题:go引包会出现循环依赖问题,怎么判断,具体怎么实现
    • dfs,先随机从某节点出发往下走,并记录走过的节点,走到头回到上一节点走下一条路,如果走到了重复的点就说明有环
  • 部门介绍高德是阿里系Go最多的,很多SDK都是高德开发的,也说出来就是Go很正确

9.06 二面

  • 自我介绍
  • go的面向对象怎么实现
    • 继承:通过组合的形式来模拟继承,例如A类里面包含了B类成员
    • 封装:通过首字母大小写来实现,包内、外访问权限的控制
    • 多态:使用多个接口来实现多态,定义多个类实现同一个接口,那么就可以在不同类型对象上调用相同名称的方法
  • 有的结构体里面内嵌了一个interface叫a,为什么这样做
    • 作用是把这个a作为匿名成员,实现的场景是:
      • 该结构体没有实现a内所有的方法,按理说是不能声明该结构体为a的,但是如果内嵌了,那么就可以声明了
      • 只是在运行中去调用这个没有实现方法时才会报错
  • GMP模型
  • 有缓冲的channel和无缓冲的channel区别
  • select会把所有case计算出来么
    • case的表达式会在select执行之初就计算出来
    • 如果多个满足,那么就以伪随机算法选取分支执行
      • go内部根据满足分支的数量生成一个随机数,然后用这个随机数来选择分支
    • 如果一个都没满足且没有default分支,那么select就会阻塞,直到其中某一分支满足
  • 什么情况下切片的len和cap相等
    • make只指定了len,会默认cap=len
    • make指定了len和cap相同
    • append后切片正好满了、直接截取某个数组的一部分时、用字面量定义时,字面量指的是直接列出来成员有哪些但是不写长度例如[]int{1,2}
  • 函数、切片、字典、通道能做map的key么
    • 能做map的key的类型需要满足可比较这个条件
    • 只有通道channel可以做map的key,因为只有channel是可比较的
      • ps:channel是引用类型实质上是一个指针,所以比较其实比的是内存地址
  • 条件变量的wait方法具体做什么
    • 1.把当前协程放到当前条件变量的通知队列里
    • 2.解锁该条件变量绑定的互斥锁
    • 3.让当前协程阻塞
    • 4.如果有通知到来就唤醒该协程继续执行,并重新锁定该条件变量绑定的互斥锁
    • 因此在调用wait()之前,需要先锁定这个条件变量的互斥锁
  • 别名类型和源类型的关系
    • type MyString = string,MyString是string的别名类型,他俩是完全相同的,只是名字不一样
    • type MyString string,这种又叫类型定义,string是MyString的潜在类型,潜在类型指的是本质是什么类型,他俩属于不同类型不能比较、互相赋值,但是可以强转
  • sync.Pool是一个对象池
    • 本地池列表的长度与调度器P的数量相同
    • 并且如果已经开始使用,就不应该再被复制

9.15 三面

  • 机票的列表逻辑,用的哪个框架,RPC调用呢
  • java的开源源码看过哪些
  • GMP模型
  • redis的传输协议,你觉得最大的问题在哪
    • 不支持压缩:其实可以压缩后再传输,收到后再用特定算法解压
    • 文本传输开销大:可以采用二进制编码
    • 没有加密措施:可以在协议里加入加密算法
    • 支持数据类型过少:可以新增支持浮点数、日期时间等
  • http2.0和http1.1有什么区别,服务端主动推送具体是怎么做的,1.1为什么不可以?
    • 服务器推送允许服务器预先发送客户端尚未明确请求的资源。例如,当客户端请求 HTML 页面时,服务器可能知道客户端很快会需要页面中引用的 CSS 文件,因此可以立即将其推送到客户端,而不需要等待客户端明确请求它
    • HTTP/1.1 无法进行服务器推送,主要是因为它是基于传统的请求/响应模型设计的,而这个模型中服务器只在响应客户端请求时发送数据

9.19 HR面

  • 你觉得自己的优势和不足在哪
    • 自律、自学能力强、不玻璃心
    • 不足在于实践经验少
  • 不玻璃心这一点具体是什么事情
  • 业余有什么兴趣爱好
  • 你觉得自己性格是什么样的
  • 手上现在有哪些offer
  • 考虑的城市是哪些
  • 未来的职业规划是怎么样的

10.腾讯

9.02 一面(国际发行平台-账号相关)

  • 算法题:给一个数字字符串和一个n,实现除法
    • 题不难,20分钟,主要考察:1.异常值处理 2.负数处理 3.n=0处理
  • 全连接和半连接
    • server收到第一次握手的SYN,把这个socket放进半连接队列里
    • server收到第三次握手的ACK,把这个socket从半连接放到全连接队列里去等待accept
      • 这个时候如果全连接队列满了,那么就会丢弃这个第三次握手的ACK,并向client重发第二次握手SYN+ACK
  • TCP三次握手,三次的报文具体是什么,二次会怎么样
    • SYN、SYN+ACK、ACK。两次会产生历史连接
  • TCP四次挥手,close_wait、time_wait,2MSL,为什么是2MSL,这个怎么修改
    • MSL意味最大报文生存时间2分钟,默认2MSL是为了防止第四次挥手c->s的ack包丢失导致服务端未进行关闭,2MSL = 判断客户端第四次挥手丢失(MSL) + 服务端重传第三次挥手(MSL)
    • 修改2MSL,widows直接修改注册表,linux要去内核修改宏定义
  • 出现大量的time_wait状态,可能是什么原因
    • 通信采用的是短连接
    • 大量地建立连接和关闭连接
  • 短连接和长连接
    • 短连接是传一次数据建一次TCP连接,长连接是一个TCP连接承担多次传数据任务
    • 短连接需要频繁建立、关闭连接,有资源浪费。长连接需要进行连接管理,空闲的长连接也会导致资源浪费
  • 滑动窗口,发送端怎么知道接受端的接受能力的呢,在哪个包里面,是单独的一个包么,发送窗口为0怎么样
    • 报文里有接受窗口大小,表示未被ack确认的数据最大可为多少
      • 例:接受窗口大小为10,第一次发送了6,第二次最多只能发4,然后此时收到了确认6的ack,那么第三次就又可以发6
    • 这个接受窗口大小是在上一次接收端发的包里面附带过来的
  • 拥塞控制,什么时候算拥塞
    • 维护一个慢开始门限,小于这个门限采用慢开始(*2),大于这个门限采用拥塞避免(+1)
    • 判断拥塞有两种:1.超过了超时重传的时间还没收到ack 2.连续收到了3个重复的ack
    • 快速恢复:发生拥塞后将发送窗口和慢开始门限减半,并执行拥塞避免
  • 大端小端
    • 大端是高地址存低字节;小端是低地址存低字节,反人类
    • 大端优势是固定第1位为符号位,便于判正负和人类阅读;小端优势是强制类型转换不需要调节字节内容
    • 判断:新建一个int i = 3,然后把它强转成char*再判断是不是3,如果不是3说明是大端,因为大端的第1位是用来表示符号的
  • 网络字节序
    • 采用大端序,是为了避免不同CPU采用大小端不一致而约定的TCP/IP数据格式
  • 字节对齐
  • 网卡收到一个包,这个包处理的过程(需要讲怎么送进协议栈和协议栈OSI的处理)
    • 硬中断:调用网卡驱动注册的硬中断函数
    • 软中断:网卡驱动注册的poll函数,并把包发送到网络协议栈处理
    • IP->TCP/UDP->socket
  • 进程、线程、协程
  • 硬中断和软中断
    • 中断是指运行过程中,某个时刻需要内核操作,这时候需要把当前程序暂停保存,然后转去内核态执行特定操作,处理完成后再回到之前状态
    • 硬中断是CPU硬件实现的中断
    • 软中断是软件模仿硬中断去实现的中断
  • epoll的两种模式
  • 堆和栈
  • static声明的局部变量在栈上还是堆上,讲一下static成员和static函数
  • 一致性哈希,和普通哈希区别在哪
  • 口述堆排序和快速排序的运行过程
  • 场景题:给1万亿个整数,一台小内存机器,怎么找出前100个最小的数字,复杂度多少,追问有没有更快一点的方法
    • 前100个建小根堆,堆顶和第101个比较,如果堆顶大于当前遍历数,压出堆顶,压入当前树,并重新调整堆,时间复杂度nlogk
    • 说了快速选择,把前100个排满就不继续进行下去

9.05 二面(国际发行平台-账号相关)

  • 场景题:给一个字符串”level > 100 or (ip > c1 and ip < c2)”和一个玩家的结构体,写一个函数判断该玩家是否符合该表达式
    • 类似“简易计算器”的解决思路,遍历到or、and这种运算符的时候,做一个分割计算已保存的状态和后面的状态再比较,遍历到()的时候递归调用
  • 场景题:有一本英文书籍,怎么压缩它来存储?
    • 1.把常用的单词建一个字典,用字典的索引来表示该单词
    • 2.使用变长编码,例如霍夫曼编码,使得频率高的单词变成较短编码,频率低的单词变成较长编码
    • 3.使用压缩算法,例如LZ77去识别字符串中的重复模式和冗余数据,将其替换成更短的表达形式
  • 如果某个进程发生了内存占用太大、CPU占用大,用什么工具去找问题,我想问的是linux下怎么去调试代码定位问题,除了top呢
    • 首先通过任务管理器、top命令等去查找是哪个进程出现问题
    • 其次日志文件检查是否有错误信息
    • 最后在代码里断点调试找到占用资源过多的函数
  • gdb具体怎么调试
    • 启动gdb并在里面加载可执行文件
    • 然后加断点,并一行一行往下执行
    • 过程中用info proc和backtrace分别查看资源占用情况和函数调用栈情况
  • 指针占多少位,32位机器和64位机器呢?
    • (x86)32位机器4字节,(x64)64位机器8字节
  • http协议里面的内容有什么,怎么知道http包的长度
    • line-header-body
    • 小点的文件用content-lenth字段直接知道,单位是8位字节的数量
    • 大点的文件用Transfer-Encoding:chunked表示用分块传输,采用约定好的协议,客户端收到了会进行组装再读取
  • 首部行是什么格式
    • 键值对
  • 怎么实现记录玩家的登录状态的
    • cookie和token,cookie存在首部行里面
  • https具体怎么握手的
  • https怎么认定服务端是可信的,你说追溯到根CA来判断,但是一次https去访问这么多地址,不是会很慢吗?
    • 根CA证书是内置在操作系统里面的,所以根据服务器证书去请求CA拿到中间证书就可以用本地的根CA证书去判断了
      • 中间CA一般是机构在颁发服务器证书的时候一起给服务器的,是静态存储在服务器上的,在https请求的时候会把服务器证书和中间CA一起发过去,用户只需要用内置的根CA去验中间CA,然后中间CA再去验服务器证书
      • 如何保证CA证书不被篡改
        • 验证签名,任何对证书的修改都会导致签名失效
  • 非对称加密为什么比对称加密开销大
    • 1.非对称加密密钥长度比较长,需要解密加密更多计算资源
    • 2.非对称加密计算复杂度高,算法实现通常涉及大数分解、离散对数等;而对称加密算法通常是基于位运算和异或操作等简单运算
  • https怎么减少开销
    • 非对称加密算法从RSA换成ECD,证书从RSA换成ECD
    • 会话重用

9.19 一面(腾讯广告-数据平台)

  • 进程的状态有哪些,它们是怎么切换的
  • 硬连接和软连接有什么区别
  • OSI五层模型,TCP三次握手、四次挥手
    • 网络接口层、传输层、网络层、数据链路层、物理层
  • 三次挥手什么情形下会出现
    • 两方同时决定要关闭连接时,同时向对方发了FIN
    • 这样的话挥手就变成了
    • c->s:FIN
    • s->c:FIN+ACK
    • c->s:ACK
  • TCP和UDP有什么区别,UDP有校验和吗
    • UDP也存在校验和机制
  • 粘包怎么处理,TCP为什么会出现粘包,UDP有粘包么
    • 粘包本质上是因为网络延迟导致接收方一次性接受到多个包导致的
    • TCP是面向流的协议,不保存包的边界,所以可能会导致粘包
    • 而UDP是面向消息的协议,保存了消息的边界,所以不存在粘包
  • 说一下TCP的拥塞控制
  • Mysql有哪几种引擎,各有什么区别,他们的锁都各自是哪种
    • MyISAM:读速度快、写速度慢,表级锁(Mysql5.5版本之前默认引擎)
    • Memory:内存型,服务器崩溃重启会丢数据,表级锁
    • Innodb:支持ACID事务、MVCC,支持表级锁、行级锁和意向锁
      • 意向锁指的是允许事务显示对指定行的锁定意图,如果其他事务要对行上锁的话要先去获取意向锁,表级锁要上的话要去检测意向锁,这可能会导致表级锁延迟
  • Redis为什么快,跟它底层的数据结构有关系么
  • 讲一下跳表,它的查询时间复杂度是多少
  • C和C++的栈帧过程
    • 把返回地址推到栈上,CPU指针指向新调用函数的入口
    • 函数开始创建新栈帧
    • 函数的参数通过寄存器或直接推送到栈,来传递
    • 执行完函数体后,通过移动栈指针来销毁栈帧
  • C++的多态怎么实现,虚函数具体怎么起作用
  • 场景题:给一堆相同的绳子,密度不均匀,已知一根绳子烧完是1小时,如何得到15分钟烧完的绳子
    • a绳两头烧,b绳一头烧,a绳烧完后b绳剩余长度就是30分钟,如此反复就可得到15分钟的绳子
  • 场景题:有10000瓶液体,和10只小白鼠,测哪瓶是毒药
  • 算法题:给一个数组,求最大的连续子数组和

11.小米

笔试9.02

  • 19道单选,6道多选,2道算法25分
  • 1.给一个目标频段target和一组频段:loss的数据,求与目标频段相差距离最小的频段的loss
    • 67%,遍历即可,思路没问题可能处理输入卡了
  • 2.给一组任务,每个任务有最低执行电量和运行总共消耗电量,求执行完所有任务需要的起始电量
    • 67%
    • 思路写错了,不应该是按最低执行电量升序、耗电量降序排序,而是应该按最低执行电量-耗电量的结果升序、最低执行电量降序来排序,因为门槛和消耗固定,那么完成这个任务之后的电量也就相当于固定!!!

12.微众银行

笔试9.03

  • 20道单多选,3道算法60分
  • 1.给一个糖果数组,切一刀要求左半段没有重复元素,求最长左半段
    • AC
  • 2.给一个橡皮泥堆数组,可以给任意堆加橡皮泥,要求最后每个堆的大小都是独特的
    • AC,先排序然后从1开始遍历,如果当前堆大小<=上一堆大小,就要把当前堆变成上一堆大小+1,然后res += nums[i-1] - nums[i] + 1;
  • 3.给一个数组和u、v,求这个数组里面有多少个平均值为u/v的子数组
    • AC,前缀和,pre[i]是i前v个数的和,每次遍历到i都会去枚举k,k表示从i往前数多少个v,即把v视作粒度来枚举
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      for(int i = v -1; i < n; i++){
      int sum = 0;
      int k = 0;
      while(i - k*v >= v - 1){
      sum += pre[i - k * v];
      k++;
      if(sum == u * k) res++;
      }
      }
      return res;

13.唯品会

笔试AK

9.5一面(内部开发工具java)

  • 自我介绍
  • 你认为哪一个项目比较困难/成就感/对你帮助比较大
  • java和go有什么区别
  • Redis的String底层是什么,和普通的字符串数组实现有什么区别
  • MySQL主从同步,如果出现主从数据不一致可能是什么原因,怎么解决
    • 事务里面使用了产生随机结果的SQL语句,例如使用了RAND()、NOW()等函数,导致从库重新执行binlog时产生了不一样的结果
  • 如果事务在从库binlog执行完后再提交,可不可以实现一致性
  • 未来的职业规划

9.13 二面(内部开发工具java)

  • 问了一下项目

9.20 HR面

14.小黑盒

笔试AK

9.6 一面(游戏库、战绩、社区)

  • redis分布式锁
    • 用setnx命令去获取锁,建立一个key为锁名,val为随机数的键值对
      • setnx表示只有当这个key不存在时才创建成功
    • 获取成功后,再进行读写操作
      • 注意这个锁绑定的资源是由你自己代码决定的,例如规定访问商品数量,必须获取lock1,那么这个lock1就相当于绑定了商品数量
    • 读写完成后,使用lua脚本去释放该锁(因为在redis里lua脚本默认是原子性的)
  • 内存回收,为什么设计一套这么复杂的内存回收机制
  • channel
  • gmp模型
  • 签到发奖励中消息队列的作用
    • 异步:将大流量分配到后面时间去处理,也使得前端请求不用等待数据层处理结果
    • 削峰:减小最大峰值
    • 解耦:依赖于这个消息的下游各部门可以各自独立消费,不用耦合在一起

9.8 二面

  • 算法题:三数之和
  • 算法题:给n个球刷n种颜色,有几种刷法?如果不考虑顺序呢
  • zset查某个数的排名时,底层跳表是怎么运行的
    • 从上往下查找的时候,维护一个计数器用来存每层跳过的节点数之和
    • 最后在底层找到目标值时,这个计数器的值就是排名

9.12 HR面

  • 早九晚七,开发一周有三天九点下班

15.喜马拉雅

笔试AK

9.8 一面(广告)

  • 场景题:有三扇门,其中一扇门背后有奖品,某次选择中,你先选了一扇门,然后主持人打开了另一扇门发现是空的,请问这时候你是维持当前选择,还是选另一扇没打开的门中奖概率更高?
  • 延迟双删具体怎么做
  • 死锁怎么解决,介绍一下银行家算法
    • 破坏死锁的条件之一:互斥、非抢占式、持有且请求、循环等待
    • 银行家算法:
      • 进程声明自己的最大资源
      • 试分配看是否能够成功
      • 安全性检查看是否能够成功
      • 分配资源运行

16.阿里钉钉

9.8 一面

  • 场景题:1000瓶药水,其中一瓶有毒,喝到有毒的24小时之后会死,请问一天之内试出有毒的药水需要几只小白鼠
    • 二进制编号
  • 场景题:有一个50个球的盒子,每次可以拿1-7个球,你先手拿,怎样保证自己能拿到最后一个球
    • 自己拿完之后保证盒子里的球数为8的倍数即可,这样无论对手拿几个,最后都能自己胜利
  • 进程和线程区别,切换开销
  • C++的智能指针,shared_ptr怎么实现
    • 维护一个计数器
    • 在复制构造函数里计数器++
    • 在析构函数里计数器–,一旦计数器==0就把当前指针删除
  • C++中堆和栈的区别,哪个快
    • 堆有复杂的内存分配策略,而栈的内存分配只设计栈指针的移动
    • 栈上的连续数据大概率是存在连续的物理地址上,CPU硬件更容易命中缓存
  • 从输入url开始的全过程
  • 四次挥手具体怎么挥,time_wait状态过多会怎么样,怎么解决这个问题
  • 开发中内存泄露怎么定位
    • 先使用任务管理器、top命令等查看是哪个进程占用内存过多
    • 调试该进程的代码,查看是哪个函数占用内存
  • 算法题:顺时针打印螺旋矩阵

9.14 二面

  • C++的协程
  • gdb调试具体命令,一个运行中的linux程序怎么去调试(不能重新运行)
  • linux怎么dump一个线程

17.蔚来

笔试AK

9.9 一面

  • redis的数据类型有哪些
  • mysql的隔离级别有哪些,可重复读+MVCC具体怎么解决幻读
    • undolog+next key lock
  • 浏览器输入一个url的全链路是什么

9.9 二面

  • 分流的技术方案
    • 负载均衡:硬件、软件、DNS
    • 应用层分流:例如不同uid打到不同后端服务器
    • 数据库分片、主从复制
    • 设置缓存层
  • 做环比监控的话,怎么存数据
  • 定时任务从1天一次改成1小时一次怎么改
  • http协议是什么
  • 算法题:实现一个substr
  • 8-9点下班,java互联网技术栈,节奏慢,和产品、用户沟通
  • base、薪资都可以和hr聊

9.21 HR面

19.华为

9.21 一面

  • 算法题:删除链表的倒数第k个节点

9.21 二面

  • 算法题:给一个头尾相连的距离数组和两个下标,求从下标1走到下标2的最短距离

9.21 主管面

  • 竞赛经历
  • 论文工作进展,论文一个人完成还是有合作
  • 家庭情况
  • 部门业务:芯片和软件结合,进来后会根据个人意向分配岗位

20.深信服

9.23 一面

  • 算法:两个有序数组,找中位数
    • 二叉查找+分治思想
    • 先各自找出自己的中位数,然后再根据这2个中位数去判断完整的中位数应该落在被分割的4个区域中的哪两个区域,再重复执行,直到找到完整的中位数
  • go的singleflight库
    • 底层是map + sync.waitgroup,原理是:
      • 如果调用map中不存在的call,那么就加锁执行,执行完成后释放done()
      • 如果调用map存在的call,那么就wait(),直到释放后就直接取map里的结果即可
    • 适用场景是某个用户并发大量地访问redis里不存在的key,导致缓存击穿大请求直接访问到db上,使用这个库就可以保证击穿只访问db层一次

9.23 二面

9.23 HR面

9.24 offercall

  • 18*15-18,包三餐
  • 一周2天6.30下班,3天8.30下班,每月固定第一个周六上半天班

10.13 已拒

21.字节跳动

9.24 笔试

  • 1.给一个01字符串,可以对0、1分别染色,但是如果这个0和1相邻、或者这个1和0相邻就不能染色
    • AC,设两个dp数组表示是否给第i位染色
  • 2.每次询问推荐内存占用最大的视频,然后求愉悦度之和
    • AC,按内存占用和愉悦度排序,然后二分查找找推荐哪个视频,再更新数组
  • 3.算经过房子的金额
    • AC,用前缀和计算经过每个房屋的次数,然后比较 pre[i]*b[i] 和 a[i] 的大小,贪心取小的即可
  • 3.给一个字符串表示指令,求机器人回到原点的方案数
    • AC,分成LR、UD、LRUD四种情况,然后组合计数
      • LR就是C(1,n)\C(1,m) + C(2,n)*C(2,m)

10.27 一面

11.1 二面

  • redis协议是什么
  • 给5张扑克牌,判断是不是同花顺
    • 不让用库函数,快排没调出来!!
      • 快排一定要先从右开始找,再从左开始找
      • 使用swap()的时候一定要注意是交换数组里的成员,千万不要拿局部变量去交换!!!!!

21.滴滴

9.24 笔试

9.26一面

  • 算法题:手撕LRU
  • go的调度模型
  • go的内存模型,分几种对象

9.26二面

  • 算法题:快速排序及优化
  • 场景题:怎么对一个超出内存的大文件数据进行排序
    • 讲了使用外存来进行归并排序

9.26三面

算法题:给一个{ip起始地址,ip终止地址,状态名}数组和一个很大的ip日志,求每一条ip日志的状态

联系邮箱:CY-Campus@didiglobal.com

22.得物

8.23笔试

AK

8.27一面

10.14二面

  • 索引失效的情形
  • redis做缓存组件怎么保证和db层的一致性
  • go mod的常见命令有哪些
    • go mod init:把当前目录初始化为一个新模块,创建go.mod文件
    • go mod tidy:删掉不再依赖的模块
    • go mod download:下载go.mod里的依赖到本地
  • go get的是模块还是包,mod文件里required的是模块还是包,包和模块有什么区别
    • 包是在同一目录下的go文件
    • 模块是一个包的集合,在go.mod文件里声明
    • go get xx的这个xx如果是模块名那么拉下来的就是模块,如果xx是模块名/包名,那么拉下来的就是这个模块里的特定包

10.22三面

  • go前沿的新特性主要集中在改良以下领域
    • 模块
    • GC
    • 错误处理
    • 并发模型
  • 灰度流量为什么不由你们这边来做,你不可以修改么

23.西山居

10.14笔试

  • 1.给一组会议开始和结束时间,求最少需要几个会议室
    • 优先队列,AC
  • 2.象棋马每次从(0,0)出发,只能按照马走日的策略走下一步,求走到目标坐标的最少步数
    • bfs+队列模拟,83%超时
  • 3.给一个敌人体力值数组,如果你的体力>=某个敌人,那么你可以击败他,然后你的体力清零但是每日恢复体力+1,请问最优策略下几天可以击败所有敌人
    • 二分查找+贪心,90%
    • 每次循环都二分查找最大能击败的敌人,并且还要与第二天击败敌人浪费的体力值比较,如果休息一天能浪费更少体力值那么就先休息

24届提前批

1.华泰证券

笔试5.14

  • 单选题25道50分+多选5道20分+3道算法30分
  • 1.输入一个数字,将其翻转
    • AC,签到题
  • 2.输入一个01组成的字符串,首尾是连着的,初始所有字符都是白色的,你可以把一段连续范围内字符染成红色,要求最后红色的0和1数量分别等于白色的0和1
    • 58.70%,滑动窗口暴力超时
  • 3.给一个数组和k,任意选一些数字,使其之和为k的倍数,求这个数字之和的最大值
    • 骗18.08%
    • 正确做法:二维dp
    • dp[i][j]表示从前i个数中选出若干数的和 % k的余数为j的最大和,则dp[i][j] = max(dp[i-1][j] , dp[i-1][(j-a[i]%k+k) % k]) + a[i]

6.6 一面

  • 说一说C++你自己常用的数据结构
  • vector、stack、queue的底层怎么实现
    • vector是动态数组,底层通过空间不够时去动态扩容实现
    • stack和queue的底层其实都是deque,分别进行了一些包装限制,deque的底层是数组+多个等长的连续空间,数组里存的是这些连续空间的指针
  • map和unordered_map的区别和底层,set的底层,它怎样保持唯一性
    • map是红黑树
    • unordered_map是底层是hash_map,也就是vector数组+链表,数组里存的是链表的首地址
    • set也是红黑树
  • 使用过linux下调试C++么,用gdb
  • C++的网络编程用的什么函数
    • listen、bind、accept
  • C++和go的区别是什么
    • 他们两种语言底层执行的时候,都是编译成二进制机器码,因此效率相比使用虚拟机的Java和python快很多
    • 但是其实golang有一个runtime包,这个包可以理解为go的运行环境,作用上和JVM差不多但是是以包的方式提供的,所以虽然不会有像JVM那样大的开销,但是比起C++而言还是有一定程度的效率损失
    • 但Go具有强大的协程设计,它的GMP模型更利于高并发的场景,C++理论上也能实现但是C++的代码维护困难、可解释性不高,更常用来写一些底层的引擎、内核
  • go是用什么底层结构来实现高并发的,讲一讲GMP模型和channel
    • GMP模型,G代表的是协程,M代表线程,P是送料器
    • 拥有一个全局队列和数个本地队列,本地队列处理完毕就去全局队列或者隔壁本地队列里拿协程来处理
    • 协程可以看作是轻量级线程,线程之间的切换执行会涉及到CPU的切换,而操作CPU要进入内核态开销极大(保留上下文、恢复现场等),换成协程后就可以降低这些开销
      • 切换内核态开销大也是IO速度受制约的主要原因,但是无法避免,因为读文件、关文件这两步都要进入内核态
      • 读文件有两次切换内核态:- 正常运行(用户态)->读文件(内核态)->数据放到内存里(用户态)->关闭文件(内核态)
  • 手撕队列的实现

6.7 二面

  • 深挖字节和赛诚的项目

6.16 主管面

  • 为什么选择华泰
  • 问有过互联网为什么还投华泰,项目也需要加班、也有末位淘汰能接受么
  • 南京和上海同薪考虑过么,为什么想来上海
  • 对华泰有什么了解,金融方面的知识了解么
  • 为这次投递准备了什么

6.19 终面

  • 和主管面大致相同

2.科大讯飞

笔试7.1

  • 20道八股单选,6道C++读代码,3道算法题
  • 1.给一个n*n的矩阵,得分是该矩阵每个位置与其转置矩阵相同位置的差的绝对值,求得分,10分
    • AC
  • 2.给一个当前时间和闹钟列表,求下一个响起闹钟的时间,15分
    • AC
  • 3.给一个<>{}组成的字符串,求最少几次操作可以把它变成合法字符串,25分
    • dfs超时、最长连续1错误,骗10%

3.OPPO

笔试7.7

  • 20道八股单选,3道算法题
    • 考到了一个sql语法的OVER()用法
    • chown能修改权限,但是能修改所有者和用户组么
    • sum = ++x + ++x的第二个x是=x+1,还是=x
  • 1.给n个长度为m的字符串,求把他们变成一样的字符串的最少修改次数
    • AC
    • 统计每个下标的最多共同字符数,然后用m-这个数就是把这个下标改成一样的字符所需要的操作数
  • 2.f(a,b,c) = a*b + c,给一个数组,求f()的最大值和最小值
    • 50%,分各种情况讨论
    • 数据范围很恶心,用long long都处理不了乘积,写了一个小时的字符串加减乘除,最后debug太复杂放弃
      • ps:下次碰到long long处理不了的数值,用unsigned long long试试
  • 3.给一个n*n的矩阵,里面依次用1,2,3….赋值,然后进行q次询问,每次询问给x,y,k,如果某个位置的元素满足abs(x-x1) + abs(y-y1) < k,那么就可以得到这个元素的分值,求每次询问得到的分值和
    • 0%
    • 模拟法肯定超时,应该是用优化的方法

4.小红书

笔试7.23

  • 20到单项和不定项,3道算法题
    • Over()的用法
    • Between和IN的用法,特别是边界
    • KMP算法的next数组怎么算
  • 1.给一个n和k,要求构造一个不重复元素组成的长度为n的数组,k是这个数组的最大公约数,求这个数组的最小和
    • ac, 直接算和res = k*(n*(n+1)/2)
    • 要求是k的倍数,还要最小和,所以数组一定是(k, 2*k, 3*k…..)这种
  • 2.给一个区间[0, n],有m次加精华的操作,每次操作可以把[i,j]之间的帖子加精,例如[1,3]就会产生(1,2)、(2,3)两个精华帖,所有加精操作结束后你可以选一个长度为m的区间,求这个区间的最大精华帖数量
    • 正常解法+骗82%
    • 用滑动窗口只能过42%,最后针对大用例区间永远取[0, m]多过到82%
  • 3.给一个数组和一个int类型target,你可以把其中一个元素用target替换掉,求最大连续子数组和
    • ac,类似股票题
    • 维护没变数组notHave和已经变了数组have过80%,最后状态压缩用int去取代vector,和用unsigned long long替代int全通过

5.字节跳动

一面7.26

  • 自我介绍一下吧
  • 你觉得之前在字节工作的技术架构和流程上有什么问题么
  • 聊一聊字节的实习经历、聊聊携程做的比较大的需求
    • 要多聊一点技术细节,例如本来耗时1000ms,通过xx技术降低成了200ms,这里面具体是怎么做的
  • 深挖秒杀系统
    • 从一个用户点下单开始,描述一下整个流程
    • 这个go写的数量控制接口很奇怪,为什么这样设计,go接口比起redis来说优势在哪
  • 网络有几层,分别描述一下
  • Http和Https有什么区别
  • TCP和UDP有什么区别
  • 操作系统进程切换做了什么
  • 内核态里有什么
  • 父子进程之间怎么通信
  • 聚簇索引和非聚簇索引的区别
  • mysql的索引是怎么实现的
  • 为什么用B+树来做索引
  • 算法题:k个一组反转链表(加分项)

二面8.2

  • 自我介绍一下
  • 你觉得你技术博客上最有技术含量的是哪个项目
    • 说了河海大学的多叉树设计
  • redis的list底层是什么结构,为什么要分两种这样实现
    • 双向链表和压缩列表,list只支持头、尾操作
    • 因为压缩列表存储在一块连续的内存上,所以存储效率很高。而双向链表除了保存数据还要存next、pre指针,内存开销大。但是它不利于修改操作,插入和删除操作需要频繁地申请和释放内存。特别是当zipList长度很长时,一次插入和删除可能会导致大量的数据拷贝
    • redis3.2之后出现了快速列表,单节点用压缩列表来存,不同节点之间用双向链表的形式来连接,头部和尾部不能被压缩
  • 让你设计一个线程安全的hash map,怎么设计
    • 讲了read map和脏map来进行读写分离,说开销太大,有没有一个map实现的
    • 讲了加读写锁,说太常规,开销大
    • 后面讲了加锁的时候给随机字符串,要写的时候这个字符串和自己本地的字符串相同才表明是自己加的锁可以操作,否则表示其他线程加的锁不可以操作
  • 消息队列的作用是什么,为什么用RabbitMQ不用Kafka
  • 算法题:二叉树中最大路径和,起点和终点不一定是叶子节点,输出这个路径。要求只遍历一次

一面8.14

  • 自我介绍一下
  • 聊机票逻辑、聊Data Service逻辑
  • B树和B+树的区别
  • 跳表有什么特点
  • TCP和UDP有什么区别
  • HTTP报文的head头里都有什么
  • GET和POST的区别
  • LRU是什么,一般怎么实现
  • ES为什么快,ES的倒排索引是什么
  • Go的map底层是什么,如果并发地操作普通map会有什么后果
  • context库里有什么方法,context是做什么的
  • 算法题:给一个链表,判断是不是回文链表

二面8.15

  • 自我介绍一下
  • 挖了一些机票的重复订单,考察了一下如果用户多次点击下单的处理过程
  • 脏读和幻读的区别是什么
  • 什么是当前读和快照读,场景是什么
    • 当前读适用于写操作,快照读适用于读操作
  • qps是多少,怎么保证这么高请求不打挂
  • redis的list底层是怎么实现的
  • redis的动态字符串SDS为什么快
  • 覆盖索引,后面写了一个sql求平均成绩
  • go的defer拷打
  • 算法题:旋转数组里面找目标值
  • 属于ad_log到日志之间,1.广告数据 2.企业调用 3.用户调用

6.友塔

笔试7.27

  • 1.一道简单题
    • ac
  • 2.有n个路口,给一个matrix[i][j]表示i到j需要花费多长时间,求0到n-1的最少花费时间
    • ac
    • spfa计算最短路径,一开始用二维数组存边超时,最后换用链式向前星解决
  • 3.经典从原点(0,0)走到终点(n,m)问题,特别在加入了一个系列特殊点,位于这个特殊点上时下一步可以走到i+1, j+1
    • 20%
    • 二维dp爆内存,状态压缩成一维,但是还是因为存特殊点开二维数组爆内存
    • 待解决问题:k个二维坐标开销最小的存储方案,条件查询复杂度O(1)
  • 4.给一个5*5的矩阵,矩阵由1,2,3,4,5这几个数字组成,划一条线,这条线只能连接相同的数字(注意线可以斜着连),最后的得分就是线上所有数字的和
    • 66.67%
    • 一开始准备用dfs做,但是每次递归有8个选择,复杂度太大太大
    • 最后用并查集通过66.67%,应该是因为有线不能回头但是并查集不考虑方向导致的

一面8.7

  • 自我介绍一下
  • 介绍一下MyRedis,数据持久化是怎么做的,如果正在写操作,这时候发送了一个读操作会怎么样
  • Redis的数据持久化是怎么做的
  • 快排的时间复杂度是多少,具体怎么推导的
  • 一个无向图,从起点到终点的最短路径,算法怎么推导的,首先你想怎么做,复杂度是多少
  • 讲一下虚拟内存
  • 从内网向外网发送一个http请求,会涉及哪些网络过程,内网a机器发出的请求,获得响应后怎么知道要把这个响应返还给a
  • 负载均衡
  • 后端技术栈:C、lula
  • 算法题:给一个0,1,2…..依次顺序组成的无限长的字符串source,再给一个target,求这个target第一次出现的下标。如果是求1的第99次出现的下标呢

二面8.10

  • 简单自我介绍
  • 这么多段实习的目的是什么,那你觉得自己比较偏向哪种方向,还是偏向做业务而不是做基架是么
  • 游戏开发和互联网开发的相同点和不同点,你觉得自己从事游戏开发的优势是什么
  • 玩家发起一次攻击,客户端和服务端的处理部分是怎么样的,客户端发送的是操作还是状态,服务端发送的是操作还是状态
  • redis+商城秒杀系统的redis和消息队列分别起什么作用
  • 用什么技术保证可靠传输,什么场景用TCP,什么场景用UDP
  • 游戏里面出现鬼步、走路回退的原因是什么
  • 依赖包成环
    • 1.如何检测有环
      • 拓扑排序
    • 2.有环的话怎么解决
      • 枚举断边
    • 3.如果是多个环耦合的话怎么解决
      • 枚举断边
    • 4.如果是多个环耦合的话,怎么返回各个环的依赖顺序
      • 深搜+回溯
  • 你觉得手游和pc、主机游戏的区别点有什么
  • 反问:主要做手游,客户端和服务端语言统一用lula,降低开销会用C写包装,unity是加分项不是必备项(因为操作很简单,也只有部分需求会涉及)

HR面8.10

  • 本科、研究生学历
  • 老家在哪,父母从事行业,独生子女
  • 婚恋状况
  • 对友塔的印象

offer call

  • 薪资组成:(18+1)*14
  • 朝10晚7,打卡制,周三固定加班
  • 福利:每天30餐补,晚上8点半下班额外补30
  • 职级:扁平结构
  • offer接么

7.百度

一面8.2

  • 介绍一下自己,说一个你认为自己最熟的项目,有哪些模块,数据大屏是怎么实现的
  • redis缓存一致性问题怎么解决
    • 双写、延迟双删,提了强一致性、强及时性的数据不该用缓存
  • mysql数据库的引擎有哪些
    • myISAM、innodb、memory
  • 介绍一下互斥锁和读写锁,他们是怎么用的
    • 读多写少的场景用读写锁,写多读少的场景用互斥锁
  • context是做什么的,它里面的方法有哪些
    • 上下文,树结构实现父子协程之间上下文的传递
    • background()、xxWithCancel()、get()、set()
  • defer关键字
    • 碰到defer的时候会记录地址,然后函数返回的时候调deferreturn()去执行这个地址
    • 一般记录在栈上,如果defer里面有recover就放到堆上
    • defer的语句如果在执行前就确定了,那么编译器会直接把defer的内容加在函数末尾,这样也叫开放编码
  • go的GMP模型,协程的大小是多少
    • 几十kb
  • 介绍一下channel,如果为0的话能塞进去么,不为0呢,是线程安全的么
  • map的底层是什么,map是线程安全的么,如果要线程安全应该怎么用
    • sync.map
  • interface{}是什么,如果一个结构体只实现了其中一部分方法算实现了这个接口么
  • 算法题:两个字符串的最长公共子序列
  • 算法题:两个字符串的最长公共子串

二面8.14

  • 介绍一下自己
  • 阻塞IO和非阻塞IO有什么区别,阻塞的是进程还是什么,如果阻塞了那么还会耗费CPU资源么
    • 阻塞是指用户空间里的调用线程一直在等待,而不能干别的事情。阻塞态不占用CPU,它只是在等待某项cpu之外的资源,比如i/o。进入就绪态去执行后才耗CPU
    • 非阻塞是指用户空间里的调用线程拿到内核返回的状态值就返回自己的空间,IO操作可以干就干,不可以干,就去干别的事情
  • redis是有线程安全的问题么
    • 没有,因为它是单线程的
  • redis单线程为什么还快,除了内存这个原因呢
    • 内存数据库在内存中运行
    • redis采用多路复用I/O,底层用的是epoll,所以很快
  • 挖了一下机票和ttam的业务场景
  • go的go func
    • go func表示的是新起一个协程去执行函数,执行的顺序其实是不确定,这时候我们需要用一些mutex、sync、waitGroup这样的关键字来保证部分逻辑按我们设想的并发顺序来执行
  • go的contex库怎么用
  • go的defer有什么用
  • go的垃圾回收GC用的是什么
  • 讲一下go中你熟悉的数据结构
  • 算法题:求一个字符串里的最长回文子串,如果只遍历一次应该怎么改
    • 一开始给的是分别调用expend(i, i)和expend(i, i+1),如果改成只遍历一次的话那么就改成expend(i),然后再函数内部每次遍历的时候同时计算i,i和i,i+1两种情况
  • 算法题:根据中序遍历和后序遍历数组建二叉树,根据二叉树算出它的前序遍历数组
  • 部门业务做的是:搜索中的卡片,对接的业务方很多

三面8.22

  • 自我介绍一下吧
  • 说一下你对百度的了解吧
  • 如果你发现在项目过程中同事有不道德行为,你会怎么处理
  • 如果ld让你修改汇报的数据,改成下一个迭代预期能达到的效果,你会怎么处理
  • 如果你的方案和ld、老同事的有分歧,怎么处理
  • 如果你作为某个项目的owner需要其他部门同事配合,但是他们积极性不是很高,怎么处理
  • 你的职业规划是什么样的,或者近几年你希望自己在哪方面发展
  • 说出大模型的三个优点和三个卡脖子的缺点
    • 优点:1.总结能力强 2.通用性强 3.减少人的重复劳动
    • 缺点:1.总结结果不可避免地有错误 2.及时性差,只能用老数据来训练 3.成本高

计网

操作系统

内存管理

1.某进程的虚拟内存中,当前要用到的数据会放在主存里面,当前不用的会放在磁盘中

  • 当时这一点进程是没有感知的,它会认为当前所有数据都在主存里面,这样设计是为了让程序在逻辑上不用去考虑底层内存的分配问题

2.内存碎片

  • 外碎片:分配单元间隙的未使用内存
  • 内碎片:分配单元里面的未使用内存

3.内存的分配策略

  • 最先分配:把遇到第一个空闲块分配
  • 最好分配:把所有空闲块中最合适的空闲块分配,即内碎片最小
  • 最坏分配:把所有空闲块中最不合适的空闲块分配,优点在于优先把大的空闲块破碎

进程管理

文件系统管理

I/O设备管理

目录

操作系统

计算机网络

数据库

数据结构与算法

C++

Golang

项目细节和场景设计

操作系统

1.线程独有的资源是什么

  • 栈空间,CPU的使用权

2.进程和线程的区别

  • 一个进程里包含多个线程
  • 进程是操作系统分配资源的基本单位,线程是操作系统执行任务的基本单位
  • 进程的通信方式是:
    • 共享内存:这块内存由多个进程共享
    • 管道:半双工通道,是单向的
    • 消息队列:消息的链表,有标识符标记存在内核里面
    • 套接字:socket,可实现不同机器、不同进程之间的通信
    • 信号:通知进程,系统中发生了某种预先规定好的事件
  • 线程的通信方式:
    • 互斥量(即锁)
    • 临界区:通过对多线程的串行化来访问公共资源,速度快
    • 信号量:可视作有buffer的互斥锁
    • 事件:针对具有后继任务需要操作的的事件设计,用通知的方式来保持多线程同步

3.同一进程下的线程共享哪些资源

  • 数据空间
  • 静态存储区

4.进程切换开销大是因为进程得去切换环境,例如全局变量、打开的文件

5.进程间通信有什么方式,详细展开说怎么通信

  • 共享内存
  • 管道
  • 信号
  • 消息队列
  • socket套接字

6.共享内存是并发安全的吗,如何加锁

7.管道两端可以互传数据吗

  • 不可以,管道是半双工的,即是单向的

8.浏览器是一个多进程服务

  • 每开一个标签页,其实就是多开一个进程
  • 设计的目的是避免某一页面出问题影响到其他页面

9.用户态和内核态

  • Linux进程的虚拟内存分为用户空间(前3GB)和内核空间(最后1GB)
  • 常规操作默认用用户态,使用到内核空间的必须要切换为内核态操作
  • 从用户态切换到内核态需要进行中断操作,处理完后还需要恢复操作

10.虚拟内存

  • 虚拟内存简单来说就是把外存当作内存来使用,便于缓解物理内存压力的不足
  • 实现内存抽象,每个进程都以为自己拥有全部内存,操作虚拟地址的操作都会被转换为操作物理地址

11.多线程访问同一资源

  • 需要上锁

12.epoll和select

  • epoll
    • 文件描述符FD上限是最大可打开文件数,参考值20w
    • 水平触发和边缘触发(只会通知一次)
    • 通知进程时会直接返回就绪事件,不用去轮询(底层原理是内核里维护一个红黑树和双向链表)
    • 只在注册新事件的时候整体拷贝一遍,开销小
    • 只能在linux上使用,使用逻辑比select复杂
  • select
    • FD上限是1024个,可以在linux内核中修改
    • 水平触发,如果程序没有完成I/O操作,那么这个FD还是会被select作为通知
    • 通知进程时只会告知有事件发生,具体地址还需要进程去轮询
    • 每次改变内核中的fd集合时,都需要整体拷贝一遍,开销巨大

13.在4G物理内存的机器上,申请8G内存

  • 32位机器上,申请失败
    • 虚拟地址空间:内核占1G,用户占3G,实际最大只能申请3G
  • 64位机器上,申请成功,但是实际读写该内存超过时会触发OOM
    • 虚拟地址空间:内核128T,用户128T

14.零拷贝

  • 计算机在执行IO操作时,CPU不需要从一个存储区域复制到另一个存储区域,进而减少上下文切换以及CPU的拷贝时间
  • 把数据从磁盘缓冲区搬运到内核缓冲区这个工作交给DMA控制器去做,CPU可以去处理其他事务
    • DMA处理完成后,CPU再去把数据从内核拷到用户空间
    • 现在的每个I/O设备基本都有自己的DMA控制器
  • kafka就是利用了零拷贝,I/O吞吐量增大,处理海量数据效率才能这么高

计算机网络

1.TCP和IP

  • TCP在传输层,IP在网络层
  • TCP里包含IP包

2.TCP报文头里包含以下内容

  • 源端口号
  • 目的端口号
  • 序列号:占4字节,表示当前报文的序列号,用于保证传输的有序性
  • 校验和
  • 窗口:占2字节,表示接收方所能处理的数据量
  • 标识位:ACK、SYN、FIN等

3.GET和POST请求的区别

  • GET请求
    • 参数通过url明文传递,只能用ASCII码,有长度限制,这个长度是浏览器限制的,实际上http别未有这种限制
    • 浏览器会主动缓存(包括传的参数)
    • 按RFC规范来是只读操作,是安全幂等的(幂等指的是多次执行相同操作,结果都是相同的)
  • POST请求
    • 参数放在request body里,有多种编码方式(get只能url编码)
    • 不会被浏览器主动缓存
    • 未指定资源的存放位置,由服务器决定
    • 按RFC规范来说是新增操作,不是安全幂等的(实际上开发者可以不遵循规范,让get也去修改服务器数据)
  • PUT请求(其他和POST相似)
    • 参数放在request body里
    • 指定了资源的存放位置
    • 按RFC规范来说是更新操作,是安全幂等的

4.跨域问题是什么,怎么解决跨域问题的,不同服务之间调用会有跨域问题么

  • 同源政策保证该网站的资源只能由同源请求执行(域名和端口名一样),是为了防止别的网站对该网站进行攻击,是浏览器采取的安全策略
  • 实现方法是新增一组HTTP首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源
  • 对那些可能对服务器数据产生副作用的HTTP请求方法(特别是GET以外的HTTP请求),浏览器必须首先使用OPTIONS方法发起一个预检请求,从而获知服务端是否允许该跨源请求。服务器确认允许之后,才发起实际的HTTP请求
  • 不同服务如果部署在不同域名端口上,也会有跨域问题

5.说一下知道的状态码,200是什么,重定向是什么,它的过程是什么,如果重定向的话那么网页是如何获取客户端信息的呢?

  • 状态码
    • 1开头表示信息
    • 2开头表示成功(200-请求成功)
    • 3开头表示发生了重定向(301-网页被永久转移到其他URL)
    • 4开头表示客户端错误(404-请求的网页不存在)
    • 5开头表示服务端错误(500-内部服务器错误)
  • 重定向是浏览器发送请求到s1之后,s1需要访问s2,但并未在服务器内直接访问,而是由服务器自动向浏览器发送一个响应,浏览器再自动提交一个新的请求,这个请求就是对s2的请求
  • s2获取客户端信息还通过第二次浏览器发起的请求获得的
  • 对s2的请求是无法获得之前对s1提交的参数的,所以重定向也用来保证表单不重复提交

6.TCP和UDP区别

  • TCP面向连接提供可靠服务;UDP是无连接的,尽最大努力交付,但不保证可靠交付,UDP 具有较好的实时性
  • TCP连接是1对1,UDP无连接可以1对多
  • TCP首部开销20字节,UDP首部开销8字节
  • TCP把数据看成字节流,UDP把数据看成报文包

7.为什么TCP更可靠

  • 校验和
  • 序列号
  • 超时重传机制
  • 确认应答ACK机制
  • 流量控制
  • 拥塞控制

8.TCP三次握手,如果改成两次握手会怎么样,那如果我就按两次握手算是建立连接了,那客户端向服务端发数据会怎么样

  • 1.会产生历史连接,例如client发了一个seq1的连接请求,然后client重启后重新发了一个seq2连接请求,此时client想要的结果是建立seq2的连接忽略seq1的连接,如果是两次握手的话会存在两个连接,其中历史连接会浪费资源
  • 2.没有同步双方的初始序列号,比如client可能收不到serve的初始序列号,导致后面的传输序列号乱序,不能保证可靠性
  • 3.产生冗余连接浪费资源,比如client发出的某个连接请求经网络延迟很久以后才到serve端,这时serve端回一个SYN+ACK后就默认连接建立的话,client此时并不需要建立连接直接忽略掉,那么serve端会一直等待数据传输导致资源浪费

9.HTTP是基于TCP的吗,HTTPS七次握手,七次握手中什么时候是对称加密什么时候是非对称加密,最后握手结束之后采用什么加密

10.将url输入到浏览器中会发生什么?

  • 域名解析
  • RAP解析将ip地址解析为物理地址
  • TCP三次握手
  • 服务端返回响应
  • 浏览器将响应渲染成页面

11.单点登录:一次登录后,访问其他页面就不再需要登录

  • 用token或者共享cookie实现

12.http版本区别

  • http1.0:无状态无连接
  • http1.1:长链接默认把Connection设为:keep-alive、增加host域、支持请求管道化
  • http2.0:二进制分帧、头部压缩、服务器推送

13.cookie、session和token

  • cookie存在客户端,本地易被篡改
  • session存在服务端,服务器要为每个用户保留session信息,连接用户过多会造成服务器内存压力过大
  • token:客户端后续每次请求中,浏览器会把token作为http header发送给服务器,使用jwt(json web token)加密token是现在主流形式
    • 这种方式的特点就是客户端的token中自己保留有大量信息,服务器没有存储这些信息,而只负责验证,不必进行数据库查询,执行效率大大提高。

14.https的七次握手

  • 正常的三次握手
  • c->s:TLS版本号+加密套件列表+希望采取的TLS选项
  • s->c:加密套件+TLS选项+自己证书+公钥
  • c->s:自己证书+对称秘钥(用公钥加密)
  • s->c:FINISH

15.实际抓包中,会发现不是四次挥手而是三次挥手

  • 因为在某些特定情形下C端不会处在持续传数据的情况
  • 所以第二次挥手和第三次挥手合并了
  • 这样可以极大地减少断开连接的开销,增加速度

16.close_wait和time_wait

  • close_wait是接受端第一次收到FIN报文后,进入的状态,传输数据完成后就结束
  • time_wait是发起端在等待接受端结束close_wait后收到FIN报文,进入的状态,等待2MSL时间之后就结束
    • 2MSL默认4分钟

17.http请求和响应报文格式

  • 第一行
    • 请求是请求行:方法+url+版本,例如 GET /index/htm HTTP/1.1
    • 响应是响应行:版本+状态码+短语,例如 HTTP/1.1 404 Not Found
  • 中间有n行首部行:字段名+值,例如host:www.baidu.com(表示请求资源存在哪个域名上)
  • 最后有个请求体(post、put这类常用)

18.https如何保证服务端的证书是可信的

  • 客户端将证书的公钥、持有者信息、有效时间等打包,然后进行Hash计算得到一个值h1
  • 客户端对证书的签名用公钥进行解密,得到h2
  • 比较h1和h2是否相等就可以验证证书是否合法了

19.https出现的性能下降

  • TLS额外的四次握手(RSA需要2RTT)
    • 非对称加密算法从RSA改成ECDHE,这样只需要1RTT
      • 该算法由于支持False Start抢跑,客户端可以在TLS协议的第3次握手后,第4次握手前,发送加密的应用数据
    • 升级到TLS1.3,也可以优化成1RTT
      • 1.3客户端在第一次握手的时候就传支持的椭圆曲线,以及这些椭圆曲线对应的公钥,这样服务端收到后,选定一个参数并带上服务端这边的公钥。经过1个 RTT,双方手上已经有生成会话密钥的材料
    • 服务器应该选用ECDSA证书而不是RSA证书,这样可以减少密钥长度
    • 采用会话重用技术
  • 握手后的对称加密传输
    • 主流的AES等算法已进行优化,且CPU厂商会针对其做硬件上的优化,这方面开销已经极大减少

20.TCP拥塞控制

  • 发送方维护一个拥塞窗口作为发送的大小
    • 出现拥塞的话要减少这个窗口,否则就增大
  • 有一个慢开始门限,低于用慢开始算法,高于用拥塞避免算法
    • 慢开始:1,2,4,8….翻倍
    • 拥塞避免:1,2,3,4,5,6….+1

数据库

1.mysql的引擎有三种

  • InnoDB:mysql默认引擎,用于事务,默认行锁,适合大规模数据,一张表的qps根据实验应该是8000左右
  • MyISAM:不支持事务,适合小规模,默认表锁,mysql之前默认的老引擎
  • Memory:数据放到内存中

2.b+树

  • b+树的深度浅,每次读一个节点只要一次IO,减少了IO次数
  • b+树的IO次数少,b+树的节点可以存多个关键字,并且单个节点默认存16k与磁盘页对齐,这样一次IO就可以传输一个完整节点
  • b+支持范围查询和排序操作
  • 具体实现:
    • 非叶子节点存的是每个子树的最小主键id,这样就可以根据要查的主键id去判断往哪边的子树往下走
    • 叶子节点按主键id有序存放数据,走到某叶子节点后用二分查找来定位到具体的位置
    • 插入需要旋转平衡开销,因为如果索引节点和数据节点某个已满的话需要拆分,如果两个都满了,还需要再往上加一层索引

3.跳表

  • 跳表的深度深,同等高度下存的数据要比b+树少
  • 跳表可能出现跨页IO
  • 跳表只支持单个关键字的查找
  • 具体实现
    • 插入不需要旋转平衡开销,直接在底层节点插入即可,而是否需要把这个数据也加到索引里,依靠随机函数即可
      • 因为理论上为了达到二分的效果,每一层的结点数需要是下一层结点数的二分之一,所以底层新增一个节点时,有0.5的概率需要加到第二层索引,有0.5*0.5的概率加到第三层索引

4.索引选型场景问题

  • mysql用b+树实现索引而不是跳表的原因
    • b+树的IO次数少,一是因为节点大小和磁盘页大小对齐一次IO可以传输一个节点,二是b+树深度浅
    • Innodb引擎出现的时候,跳表还没得到广泛应用
  • redis用跳表实现有序集合zset而不是b+树的原因
    • redis在内存中运行,所以层高,IO开销大就不再是劣势
    • 跳表的插入效率高,因为不用像b+树一样需要去旋转平衡
  • 跳表写性能好:插入不需要去旋转平衡,b+树读性能好:层数低

5.Innodb的next-key lock机制解决幻读

  • 里面包含间隙锁和记录锁,间隙锁会锁上记录之间的间隙
  • 比如对5到10行的记录上next-key lock就是由(5, 10)之间的间隙锁和加在10上的记录锁组成,左开右闭(5,10],即5不加锁,10要加锁

6.数据库的锁底层是怎么实现的,类似间隙锁,xx锁这种

  • InnoDB并没有采用系统提供的锁机制,而是自己封装了操作系统提供的基本mutex互斥量和event信号量来实现锁
  • InnoDB行锁是通过给索引上的索引项加锁来实现的,而不是给表的行记录加锁,通过索引检索数据才使用行级锁,否则将使用表锁

7.Redis是串行但是仍然快的原因

  • Redis是单线程的,减去了CPU切换不同线程的开销,并且Redis是在内存里运行的
  • Redis的多路复用模型是用epoll实现的

8.Redis是基于键值对的非关系数据库,值的数据类型可以是

  • string
  • hash
  • list
  • set
  • zset(有序集合)
  • Bitmaps(位图)

9.跳表的原理是二分查找,所以快。查询、插入、删除的平均复杂度都是logn

  1. redis的哪种数据结构是有序的
  • zset

11.mysql的MVCC

  • 目的:为了实现事务读数据的时候不需要加锁
  • 实现:InnoDB中的MVCC实现是通过undolog日志实现的
    • 执行更新操作时,会把更新前的数据放入undolog里面,并通过隐藏的回滚指针roll_pointer指向
    • 其他的事务,如果需要查询该记录,就会去undolog里面找这个记录的最新历史版本
  • MVCC最大的好处是读不用加锁,实现读写不冲突,极大地增加了并发性同时保证了事务的隔离性

12.Innodb的隔离级别

  • 读未提交
  • 读提交RC:每次读都会更新快照,所有不能解决不可重复读和幻读问题
  • 可重复读RR:只在第一次读的时候生成快照,然后后面只有事务内更新了数据才会去更新快照
    • 快照读情况下,根据MVCC机制,用版本号、undolog的方法,可以解决幻读问题
    • 当前读情况下,手动加record lock(记录锁)和gap lock(间隙锁),即next-key-lock机制,可以解决幻读问题
      • 当前读的情况下只用MVCC不能解决幻读,要加间隙锁才行
  • 串行

13.InnoDB的行锁算法有以下3种

  • 记录锁record-lock:直接在记录上加锁
  • 间隙锁gap-lock:锁定一个范围,但不包括记录本身
  • next-key-lock:锁定一个范围和记录本身,解决幻读

14.聚簇索引和非聚簇索引,Innodb默认的是聚簇索引

  • 聚簇索引将索引和数据放一块,b+树叶子节点存的是:主键id+数据,查询快+更新代价大
  • 非聚簇索引将索引和数据分开放,b+树叶子节点存的是:主键id+数据地址(还需要去磁盘里找),查询慢+更新代价小

15.缓存雪崩,缓存击穿和缓存穿透

  • 缓存穿透:用户每次查的数据都不在缓存里面,都得去底层数据库查,导致缓存机制形同虚设
  • 缓存雪崩:同一时间大量的缓存数据过期,导致该时间的请求底层全打到数据库上
  • 缓存击穿:缓存里的某个key一直扛着大并发请求,这个key一旦过期,就会出现缓存击穿

16.mysql的最左匹配

  • 例子,t1,t2,t3建立了一个联合索引,那么实际上是建立了(t1,t2)、(t1,t2,t3)这两个索引
  • MySQL8.0之前一定是遵循最左前缀匹配的,即WHERE条件有t1==xx或者t1==xx and t2==xx时才能用到这个索引来加速检索
  • MySQL8.0之后出现了索引跳跃扫描技术,假如只查了t2==xx and t3==xx也能去用到联合索引,因为实际上底层会去执行
    1
    2
    3
    4
    xxx WHERE t1 == 1 and t2 == xx and t3 == xx;
    xxx WHERE t1 == 2 and t2 == xx and t3 == xx;
    .....
    直到扫描完t1字段所有的唯一值,最后将结果合并返回

17.redis是k-v结构,怎么实现复杂查询

  • 一般可以使用set的交并集来实现多表联查需求,但是这样其实就抛弃了redis的优势,一般还是不建议在redis里面进行复杂查询,应该存放直接能使用的值

18.mysql的主从复制
主从复制的基本原理:slave会从master读取binlog来进行数据同步

  • master将改变记录到二进制日志binlog,这些记录过程叫做二进制日志事件binlog events
  • slave将master的binlog events拷贝到中继日志relay log
  • slave重做中继日志中的事件,将改变应用到自己的数据库中。MySQL的复制是异步且串行化的

19.Redis实现数据持久化的方法

  • RDB:把当前的数据生成快照,保存到硬盘里,有手动触发和自动触发两种
  • AOF:用日志记录每次执行的写命令,重启时重新执行一遍AOF里的记录

20.数据库慢查询的原因

  • 没有用到索引
  • 内存不足
  • 查询的数据量过大

21.解决慢查询用explain检查sql是否有问题,关注以下字段

  • type:用来表示该sql底层是怎么扫描的,
    • all全表扫描
    • index全索引扫描
    • null表示不用去表里查可以直接得到结果
  • possible_keys:可能用到的索引列
  • key:实际用到的索引列
  • Extra:底层用的是哪种检索方式
    • Using where用where来处理结果
    • Using index condition表示用索引

22.乐观锁和悲观锁

  • 乐观锁:默认不发生并发冲突,只在提交时检查版本号
    • 有可能会出现两个事务读同一行后再写入的未知结果
  • 悲观锁:默认发送并发冲突,需要关闭mysql的自动提交,并在事务中用select…for update用排他锁锁住数据,其他事务需要在该事务提交后才能去写这条数据
    • 效率比较低
  • 并发冲突少时选择乐观锁,并发冲突多时选择悲观锁
    • 因为乐观锁出现冲突只能往上抛出,然后重试,而悲观锁可以避免冲突的发生

23.mysql如何管理脏页

  • 用buffer pool来做缓存加速
  • 更新数据的时候会把buffer pool里面的页更新,然后把该页标记为脏页
  • 后台线程再将脏页写入到磁盘里面
    • 用一个flush链表来存所有脏页,后台线程遍历这个链表就可以把脏页写入磁盘了
    • 触发:redo log或者buffer pool满了,数据库空闲或者关闭
    • 数据库性能波动,可能就是后台正在写脏页导致的

24.MySQL是如何处理全局搜索导致的LRU污染

  • 新增一个old区域
  • 当某页第一次被访问时,直接放入old区域
  • 后续访问的时间 - 第一次访问时间 > 一定时间,才能将该页放入LRU的热点young区域
    • 原理是:每次从页中取一条记录,即认为访问了一次该页。所以在全表扫描时,InnoDb会认为对该页短时间进行了多次访问
  • 并且新增了,只有young区域后1/4的页被访问才将其移到首部

25.一级索引和二级索引

  • 一级索引:叶子节点存的是数据,主键索引都是一级索引
  • 二级索引:叶子节点存的是主键,找到叶子节点后再用主键去访问对应数据

26.怎么加索引,什么时候要去加索引

  • alter table 表名 add 索引类型 列名
  • alter table 表名 drop xx

27.为什么myisam查询比innodb快

  • innodb寻址要映射到块,再到行,myisam记录的直接是文件的myisam,定位比innodb要快
  • innodb需要维护MVCC一致,需要额外开销
  • innodb要缓存数据块,所以其中还有块在缓存中换进换出的开销

28.Hive是怎么实现大数据查询的,mysql为什么不行

  • Hive用MapReduce去分布式查询
  • Hive是将结构化的文件映射成一张表,这个文件是在HDFS上的

数据结构与算法

1.哈希表的负载因子

  • 负载因子=已保存节点空间/哈希表空间,一般设为0.75

2.set和array的区别

  • 唯一性。set的底层是红黑树,但是保证唯一性用的是哈希表
    • 保证唯一性的底层实现是,先判断key得到的hashcode有一样的么,如果有,那么再调equals()去检查

3.如果发生哈希冲突应该怎么处理,哈希表的时间复杂度是多少
- 链表法,插入、查询、判断key值开销:unordered_map是O(1),map是O(logn)

4.二叉树插入元素的时间复杂度

  • O(logn),插入其实开销就和查找一样

5.动态数组删除元素的时间复杂度

  • O(n),因为无论是开辟新数组还是移动其他成员的位置,复杂度都是n

6.unordered和普通的数据结构有什么区别,比如unordered_map和map

  • 底层:unordered_map底层是hash_map,map底层是红黑树
    • hash_map是由vector和链表构成,每个vector的位置连一个链表,声明的时候就会自动初始化一个vector去占用空间(质数,不同编译器用不同的质数比如53)
  • 顺序:unordered_map是插入顺序,map是按key从小到大排列的
  • 插入、查询、判断key值开销:unordered_map是O(1),map是O(logn)

7.红黑树的特性

  • 每个节点或者是黑色,或者是红色。
  • 根节点是黑色
  • 每个叶子节点是黑色(注意:红黑树叶子节点是NULL)
  • 不能出现连续的黑色节点
  • 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。

8.红黑树与AVL树比较,都是BST(二叉搜索树)

  • AVL是严格的平衡二叉搜索树,执行插入或删除,往往需要开销较大的旋转来保持平衡,但是高度较低
  • 红黑树是一种弱平衡二叉搜索树,只需确保没有一条路径比其他路径长两倍即可,所以旋转次数少,但是高度较高
  • 查询较多的情况用AVL树,
  • 插入和删除场景较多的情况用红黑树,map和set

9.vector与list比较

  • vector底层是数组,list底层是双向链表
  • vector支持下标访问,list不支持
  • vector是顺序内存,list不是
  • vector扩容才会申请内存,list每次插入都需要申请内存

10.dijkstra和spfa区别

  • dijkstra用堆,spfa用优先队列
  • dijkstra不能处理负权值,spfa可以处理
  • spfa的最坏复杂度和dijkstra相同,但是spfa可能会被卡

11.deque

  • 底层由多段等长的连续空间组成
  • 用一个数组map存放指向这些连续空间地址的指针
    • 和unordered_map底层类似,一个存指针指内存空间,一个存链表

12.希尔排序就是插入排序的改进版,也是不稳定的

  • 先划分子序列,注意这里划分的子序列是交错的
    • 按增量的方式进行子序列划分,将整个序列中下标值相差固定值的所有元素划分到同一个子序列中。比如,整个序列有9个元素,而增量为3,那么第0、3、6个元素属于第一个子序列,第1、4、7个元素属于第二个子序列,第2、5、8个元素属于最后一个子序列
  • 然后对每个子序列进行插入排序
  • 然后再按一个新的较小的增量进行划分,再重复以上步骤
  • 最后得到完整的排序

13.sort底层是快排

  • 元素少的话会去用插入排序
  • 用快排是因为快排在比较随机的分布上,表现较好

C++

1.C++的多态

  • 多态就是一个接口,多种实现方法,即动态绑定
  • 通过虚函数实现

2.什么是虚函数,原理是什么,怎么样使用虚函数

  • 类中存有一个虚函数表,实例化的对象拥有一个虚函数指针用来指向虚函数表中的某个位置
  • 虚函数在运行时通过虚函数表确定,是动态的;内联函数在编译时候进行代码嵌入,是静态的,所以如果把虚函数声明为内联,编译器仍然会当做普通虚函数处理
  • 虚函数的缺点是:一是虚函数表和虚函数指针会增大开销,二是在一个CPUcache里面,有了虚函数以后,编译器不会做一些很强大的优化
  • 对于继承自父类的子类,应该将父类析构函数设为虚函数

3.const关键字的作用和一般使用情景

  • 定义不会改变的常量,使编译器保护这些常量,防止代码无意的修改

4.static关键字的作用和一般使用情景

  • 类里的static函数,里面就只能调用static成员
  • static成员在类未进行第一次实例化时就已经占据了空间

5.了解构造函数和析构函数吗?它们俩可以是虚函数吗

  • 构造函数不能是虚函数,析构函数可以是虚函数
  • 一般析构函数设为虚函数是便于子类重载,避免使用父类指针指向子类对象时,去调用了父类的析构函数导致部分子类成员没能释放,造成内存泄漏

6.incline函数和宏的区别是什么

  • incline在编译时展开,宏在预编译时展开;
  • incline内联函数有类型检测、语法判断等功能,而宏没有,因为宏只是做简单的文本替换,这也导致要注意括号问题

7.说一下你了解的vector和map实现方式和功能

  • vector,动态数组,有扩容机制
  • unordered_map的底层是用vector+链表实现的

8.字节对齐

  • 原理:
    • 因为尽管内存是以字节为单位,但是大部分处理器并不是按字节块来存取内存的。它一般会以2字节,4字节,8字节,16字节甚至32字节为单位来存取内存,我们将上述这些存取单位称为内存存取粒度
    • 假如没有内存对齐机制,数据可以任意存放,现在一个int变量存放在从地址1开始的联系四个字节地址中,该处理器去取数据时,要先从0地址开始读取第一个4字节块,剔除不想要的字节(0地址),然后从地址4开始读取下一个4字节块,同样剔除不要的数据(5,6,7地址),最后留下的两块数据合并放入寄存器.这需要做很多工作
    • 有了内存对齐的,int类型数据只能存放在按照对齐规则的内存中,比如说0地址开始的内存。那么现在该处理器在取数据时一次性就能将数据读出来了,而且不需要做额外的操作,提高了效率。
  • 对齐的准则:
    • 结构体变量的首地址能够被其对齐字节数大小所整除
    • 结构体每个成员相对结构体首地址的偏移都是成员大小的整数倍,如不满足,对前一个成员填充字节以满足
    • 结构体的总大小为结构体对齐字节数大小的整数倍,如不满足,最后填充字节以满足

9.单例模式

  • 饿汉单例模式:系统启动的时候就利用static机制实例化了类
    1
    2
    3
    4
    5
    6
    Class A{
    static A single;
    static A* getClass(){
    return &single;
    }
    };
  • 懒汉单例模式:真正用到这个类时才去实例化
    1
    2
    3
    4
    5
    6
    7
    Class A{
    static A* single;
    static A* getClass(){
    if(single == nullptr) single = new A();
    return single;
    }
    };

10.i++其实分3步执行

  • 读取i的值,增加i的值,回写i的新值
  • 这3步每一步都是原子操作,但是组合在一起就不一定是原子操作了,所以i++线程不安全,++i线程安全
  • ++i比i++效率高得原因是,前者只用返回i+1的结果,而后者既要先保存i的结果还要保存i+1的结果

11.static关键字的作用

  • 静态函数(在函数返回类型前加static):作用域为声明语句所在的整个文件
  • 全局静态变量(在全局变量前加static):作用域为声明语句所在的整个文件
  • 局部静态变量(在局部变量前加static):作用域仍为局部
  • 总结:
    • 类的静态成员和静态函数:这个类的所有对象都共用一个,注意静态函数只能引用类中的静态成员
    • static与extern相反,static意味着该变量、函数在被声明的文件之外是不可见的,除非引入声明的文件作为头文件,但是这样的话会每一个引入该头文件的文件都会定义一个自己的变量造成内存浪费,所以一般用extern在头文件中声明才是正确的方式
    • 静态变量都放在内存的静态存储区内,在程序运行期间一直存在不会释放,所有在函数内定义的局部静态变量,会在第一次运行到该语句时就创建,第二次运行到该定义语句会自动跳过,直到程序终止才释放

12.堆和栈的区别

  • 堆会产生内存碎片,栈不会
  • 堆只能动态分配需要程序员手动分配和释放;栈由系统管理静态分配,也可以用alloca()动态分配,但都是由系统释放
  • 堆内存地址由低到高;栈内存地址相反
  • 堆为虚拟内存大小;栈默认为1M(linux下为10M)
  • 堆的分配效率低;栈的分配效率高,因为由系统调用,会有硬件层面的支持

13.new与malloc区别

  • new是C++用于内存分配的运算符,malloc是C用于内存分配的库函数
  • new会自动计算要多少字节的内存,malloc需要用户指定字节数
  • new会返回指定类型的指针,malloc返回的统一是void *,需要用户自己再转一次
  • new用delete释放,malloc用free释放

14.#define和typedefine

  • define在编译前预处理做字符串替换,typedefine在编译的时候才处理,相当于起别名

15.shared_ptr

  • shared_ptr和局部变量一样,离开作用域时会自己销毁
  • 每当一个shared_ptr被拷贝或当成值赋给其他变量时,内置计数器都会自动+1,当指向该对象的一个shared_ptr被销毁时,shared_ptr类的析构函数会对计数器-1,为0时就去销毁这个对象(调用这个对象的析构函数)来释放动态内存
  • weak_ptr指针不能直接访问对象的方法,要先将其转化成shared_ptr指针再访问
    • weak_ptr:用于解决shared_ptr互相指向形成循环,内存一直无法释放导致泄漏,它不会增加对象的引用计数

16.指针和引用的区别

  • 指针占4字节空间,引用只是一个别名不占空间
  • 指针可初始化为nullptr,引用必须初始化为一个已存在对象
  • 引用易引起内存泄漏,因为指向的对象可能在栈里被回收了

17.C++的编译过程分几个阶段

  • 预编译->编译->汇编->链接->执行
  • Linux下用C++编程的步骤
    • 用vim编写.cpp文件
    • 用g++编译得到.out文件
    • 用./xx.out执行

18.C++在linux下怎么断点调试

  • 使用gdb,对某行打上断点
  • 然后在生成二进制程序的时候, 加上 -g 选项

Golang

1.GMP模型中,如果本地队列已经没有g了,全局队列也为空会休息吗

  • 不会,因为还会去隔壁的本地队列里面拿g

2.channel的底层,如何用它来实现并发,如果channel满了会怎么办

  • 底层用hchan结构体实现,一个ringbuffer,一个发送队列,一个接受队列

3.Go语言的特点

  • 直接编译成二进制,没有虚拟化损失
  • 代码跨平台,但是编译出来的产物是不跨平台的
  • runtime直接编译进可执行文件里

4.Go中的扇入、扇出

  • 扇入:多个通道合并到一个通道,select关键字聚合多条通道分别服务
  • 扇出:一个通道分散到多个通道,用go关键字起多个协程

Linux

1.Linux下查找文件用什么命令

  • find “xx”表示在当前目录及其子目录查找xx

场景设计

1.秒杀系统最重要的是异步、削峰,通过拦截器、分布式架构和消息队列实现

2.缓存数据一致性如何保证

  • 一般而言都是先更新数据库,再去缓存里删老数据
  • 两种方案
    • 双写策略:修改完数据库后,马上再用set方法将新数据写入到缓存中
      • 缺点:写入数据库后,再写入到缓存中这一步可能会由于网络原因延迟,导致脏数据
        • 例如改了数据库a改成1然后再改成2,此时网络波动改成1的写缓存操作在改成2的写缓存操作之后才执行,这样就不一致了
      • 解决办法:设置过期时间,这样一段时间后到数据库里取更新缓存的数据仍然可以得到正确数据
    • 先写后删策略:修改完数据库后,马上把缓存中的数据去删掉
      • 缺点:删除因为网络波动延迟和删除操作失败仍然可能有脏数据
      • 解决办法:设置过期时间,MQ异步处理保证执行删除
    • 延迟双删策略:先删缓存,再写数据库,延迟n秒后再去删缓存
      • 缺点:这n秒里还是会有脏数据,因此仍然不是强一致性的
      • 解决办法:设置过期时间,MQ异步处理保证执行删除
  • 根据系统设计的思想:
    • 放入缓存的数据本就不应是实时性的、一致性要求很高的,所以缓存数据的时候要加上过期时间保证每天拿到最新的即可。
    • 遇到实时性、一致性要求高的数据,就应该直接查数据库,即时速度慢一些

3.rabbitmq如何保证消息不丢失,如果发送了多次相同的消息要怎么处理

  • 消息丢失有三种
    • 生产者发给mq途中丢失:开启confirm机制给每个消息分配一个id,生成者发送消息后mq收到返回ACK,没收到返回nack
    • mq因为断电等情况丢失:设置消息持久化和镜像集群
    • mq发给消费者途中丢失:开启AKC应答机制,即消费者收到后给mq回一个ACK
      • kafka的ack有以下三种策略:
      • ACK = 0 时 发送一次 不论下游是否接收
      • ACK = 1 时,等待下游接收成功即可
      • ACK = -1 时 ,需等待下游将消息同步给消息队列

4.如果让你设计一个应用层的协议你会考虑什么,怎么去识别包的长度,如果包里本身包含这个特殊字符怎么办
- 用socket封装实现,基于TCP去实现,考虑首部包含资源的位置、请求的方式、协议版本
- 1.首部加一个len字段 2.用特殊字符做分割,换一个少用的字符或者加转义符/

5.rabbitmq和kafka的优缺点

  • kafka有ack机制可以保证消息的顺序处理
  • rabbitmq有消息存活时间和延迟/预定消息
  • rabbitmq消息一旦消费成功就会删除,反之处理失败则放回;但kafka会一直保留消息,根据超时时间来删除,可以反复消费消息
  • kafka使用分区的结构,在横向扩展上更有优势