第十六章 设计题

Python基础、函数、模块、面向对象、网络和并发编程、数据库和缓存、 前端、django、Flask、tornado、api、git、爬虫、算法和数据结构、Linux、设计题、客观题、其他

第十六章 设计题

1. 设计一个办公室摄像头的web后台管理系统

假设功能如下:
1.  可以 开启关闭重启每个摄像头
2.  可以调整摄像头的方向
3.  可以设置摄像头每天的工作时间
4.  后台可以查看每个摄像头的历史录像, 并且可以删除, 设置保存最大保存时间
5.  后台可以随时查看实时监控

要求:
1.  设计系统架构, 考虑全系统无单点, 画出设计图, 标出所需选用的所有技术和所有组件及关系
2.  设计系统数据结构, 设计一套基于mysql的数据库表
3.  API设计, 写出符合以上功能的所有用户API及主要的内部工程逻辑
4.  设计用户和权限系统, 考虑只有两种角色即可, 一种是普通用户只有功能5, 也就是只能看实时录像, 
	另一个是管理员可以拥有1-5的全部功能权限
设计一个办公室摄像头的 web 后台管理系统需要考虑以下方面:
	系统架构、数据结构、API 设计以及用户和权限系统。以下是一个简单的设计示例:

### 1. 系统架构设计
系统采用微服务架构,拥有以下服务:
- **用户服务**:处理用户注册、登录等功能,管理用户和权限。
- **摄像头服务**:负责摄像头的管理、状态控制、方向调整、工作时间设置等。
- **录像服务**:管理摄像头的历史录像,提供查询和删除功能。
- **实时监控服务**:提供实时监控功能,支持管理员和普通用户。
- **配置服务**:管理系统的全局配置,如保存最大时间等。

### 2. 数据结构设计
#### 2.1 用户表
CREATE TABLE users (
    id INT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) NOT NULL UNIQUE,
    password_hash VARCHAR(255) NOT NULL,
    role ENUM('user', 'admin') DEFAULT 'user'
);

#### 2.2 摄像头表

CREATE TABLE cameras (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(100) NOT NULL,
    status ENUM('on', 'off') DEFAULT 'off',
    direction INT DEFAULT 0,
    work_start TIME,
    work_end TIME
);

#### 2.3 录像表
CREATE TABLE recordings (
    id INT PRIMARY KEY AUTO_INCREMENT,
    camera_id INT,
    start_time DATETIME,
    end_time DATETIME,
    FOREIGN KEY (camera_id) REFERENCES cameras(id) ON DELETE CASCADE
);


### 3. API 设计
#### 3.1 用户 API
- 注册用户:`POST /api/users/register`
- 用户登录:`POST /api/users/login`

#### 3.2 摄像头 API
- 获取摄像头列表:`GET /api/cameras`
- 控制摄像头状态:`PUT /api/cameras/:id/status`
- 调整摄像头方向:`PUT /api/cameras/:id/direction`
- 设置工作时间:`PUT /api/cameras/:id/work-time`

#### 3.3 录像 API
- 获取历史录像列表:`GET /api/recordings/:cameraId`
- 删除录像:`DELETE /api/recordings/:id`
- 设置最大保存时间:`PUT /api/configurations`

#### 3.4 实时监控 API
- 实时监控:`GET /api/live/:cameraId`

### 4. 用户和权限系统
系统有两种角色:
- 普通用户 (`role: 'user'`):只能查看实时监控。
- 管理员 (`role: 'admin'`):具有所有功能权限。

### 5. 技术选型
- **后端框架:** 使用 Django 或 Flask 框架,以 Python 为主要开发语言。
- **数据库:** MySQL 用于数据持久化。
- **前端框架:** 使用 React 或 Vue.js 进行前端开发。
- **实时监控:** 使用 WebSocket 或 WebRTC 实现实时监控功能。
- **身份验证:** 使用 JWT(JSON Web Tokens)进行用户身份验证。

这是一个简化的设计,实际项目中可能需要更多的细节和优化。
在设计之前,最好了解业务需求、系统规模和团队的技术栈偏好。

2. 编写一个脚本, 5分钟检查一次日志, 发现有暴力ssh破解现象的, 提取此类ip地址, 并去重, 并按降序排序。

   要求:
   1.  同一个ip暴力破解超过10, 自动屏蔽IP地址
   2.  指定办公室ip地址(192.168.100.100)为可信任ip地址, 不受屏蔽规则限制, 以下为日志格式
   
   日志样板如下:
   May 4 03;43:07 tz-monitor sshd[14003]: Failed password for root from 124.232.135.84 port 25251 ssh2
   
   May 4 03:43:07 tz-monitor sshd[14082]: Invalid user postgres from 124.232.135.84
以下是一个简单的 Python 脚本,用于检查暴力 SSH 破解现象,提取并排序相关的 IP 地址:
import re
from collections import Counter

def extract_ip_from_log(log):
    pattern = r'\b(?:\d{1,3}\.){3}\d{1,3}\b'
    matches = re.findall(pattern, log)
    return matches

def check_bruteforce(logs):
    ip_counter = Counter()

    for log in logs:
        ips = extract_ip_from_log(log)

        for ip in ips:
            ip_counter[ip] += 1

    return ip_counter

def block_ips(ip_counter, threshold=10, trusted_ip="192.168.100.100"):
    blocked_ips = []

    for ip, count in ip_counter.items():
        if count > threshold and ip != trusted_ip:
            blocked_ips.append(ip)

    return blocked_ips

def main():
    # 模拟日志
    logs = [
        "May 4 03:43:07 tz-monitor sshd[14003]: Failed password for root from 124.232.135.84 port 25251 ssh2",
        "May 4 03:43:07 tz-monitor sshd[14082]: Invalid user postgres from 124.232.135.84",
        # 添加更多日志...
    ]

    ip_counter = check_bruteforce(logs)
    blocked_ips = block_ips(ip_counter)

    # 排序并输出
    sorted_blocked_ips = sorted(blocked_ips, key=lambda x: ip_counter[x], reverse=True)
    print("Blocked IPs (sorted):", sorted_blocked_ips)

if __name__ == "__main__":
    main()


请注意,此脚本是一个简化版本,实际应用可能需要更复杂的逻辑和安全性考虑。
在实际环境中,可能需要将日志来源改为真实的日志文件,并考虑日志轮转等情况。
此外,阻止 IP 的方法会依赖于系统和网络设置。在生产环境中使用此脚本之前,请确保了解相关法规和安全最佳实践。

3. 一个文本文件,大约有一万行, 每行一个词, 要求统计出其中最频繁的前10个词, 请给出设计思路。

解决这个问题的常见思路如下:

1. **读取文件:** 
	首先,你需要读取文本文件中的内容。在 Python 中,你可以使用 `open` 函数来打开文件,
	然后使用 `readlines` 方法读取所有行。
    with open('your_file.txt', 'r') as file:
        lines = file.readlines()

2. **处理每个词:** 遍历每一行,将其分割成词。你可以使用字符串的 `split` 方法。
    words = []
    for line in lines:
        words.extend(line.split())

3. **统计词频:** 使用字典来统计每个词的出现次数。
    word_count = {}
    for word in words:
        word_count[word] = word_count.get(word, 0) + 1

4. **找出前 10 个:** 将字典按值降序排序,并取前 10 项。
    sorted_word_count = sorted(word_count.items(), key=lambda x: x[1], reverse=True)
    top_10 = sorted_word_count[:10]

5. **输出结果:** 打印或以其他形式输出结果。
    for word, count in top_10:
        print(f'{word}: {count}')


整合在一起:
with open('your_file.txt', 'r') as file:
    lines = file.readlines()

words = []
for line in lines:
    words.extend(line.split())

word_count = {}
for word in words:
    word_count[word] = word_count.get(word, 0) + 1

sorted_word_count = sorted(word_count.items(), key=lambda x: x[1], reverse=True)
top_10 = sorted_word_count[:10]

for word, count in top_10:
    print(f'{word}: {count}')

请注意,这只是一个基本的示例。在实际应用中,你可能需要更多的处理,例如去除标点符号、处理大小写等。

4. 请为公司设计一个并发处理key-value引擎, 要求每条请求的数据小于16k, 数据总量为1T,QPS为50。

   要求:
   1.  请给出该系统需要配备多少资源, 服务其数量, 服务器内存大小及硬盘空间等
   2.  要求系统平滑可扩展
   3.  尽可能的降低系统复杂度
   
设计一个并发处理的 key-value 引擎需要考虑多个方面,包括硬件配置、架构设计、存储引擎选择等。

以下是一个简化的设计思路:
### 1. 服务器配置
#### 1.1 数据总量和单条请求大小
- 数据总量:1T,单条请求数据小于16k
- 每秒查询请求数 (QPS)50

#### 1.2 配置推荐
- 服务器数量:根据负载均衡和高可用性的需要,至少 3 台服务器。
- 服务器配置:至少 16 GB RAM,4 核心 CPU。具体配置可以根据并发量和负载情况调整。
- 存储:使用 SSD 硬盘,至少 1TB 存储空间。
  
### 2. 系统架构
#### 2.1 主从架构
采用主从架构来提高系统的并发处理能力。主节点负责写入,从节点负责读取,通过负载均衡器分发请求。

#### 2.2 数据分片
将数据分片存储,每个节点只负责部分数据的读写,降低单节点的压力。可以采用一致性哈希算法等。

#### 2.3 缓存层
引入缓存层,减轻数据库的压力。可以使用内存数据库如 Redis 或 Memcached。

### 3. 存储引擎
#### 3.1 数据库选择
选择高性能的 key-value 存储引擎,如 Redis、RocksDB、LevelDB 等。

#### 3.2 数据备份和持久化
定期对数据进行备份,确保数据的可靠性。可以使用数据库的快照功能。

### 4. 网络和负载均衡
#### 4.1 网络配置
确保服务器之间的网络通信畅通,采用高速网络设备。

#### 4.2 负载均衡
使用负载均衡器进行流量的分发,确保每台服务器的负载相对均衡。

### 5. 平滑扩展和监控
#### 5.1 扩展性
设计系统时考虑水平扩展,使得系统在需求增加时能够方便地添加更多的节点。

#### 5.2 监控系统
引入监控系统,监测服务器性能、负载、存储使用情况等,及时发现问题。

### 6. 降低系统复杂度
- 选择简单而稳定的存储引擎和组件。
- 使用成熟的技术和框架,避免自己开发复杂的组件。
- 采用容器化技术,如 Docker,简化部署和维护。

以上是一个整体的设计思路,具体的实现还需要根据业务需求和实际情况来调整。

5. 请设计秒杀系统, 大并发下如何不会超卖?

设计一个秒杀系统需要考虑高并发下的一系列问题,其中防止超卖是一个非常重要的挑战。

以下是一些设计思路,以确保在大并发情况下不会发生超卖:
### 1. 限流和熔断
1. **限流机制:** 使用限流措施,如令牌桶算法或漏桶算法,以确保每秒只允许一定数量的请求通过。
2. **熔断机制:** 当系统负载达到一定程度时,触发熔断机制,暂停或拒绝新的秒杀请求。

### 2. 预减库存
1. **提前扣减库存:** 在用户点击秒杀按钮时,先将库存从数据库中扣减,而不是等到订单支付完成再扣减。
2. **事务操作:** 使用数据库事务确保扣减库存和创建订单是一个原子操作,防止因为异常情况导致库存减少而订单未创建。

### 3. 数据库优化
1. **使用缓存:** 将库存信息缓存在缓存中,减少数据库的读取压力。
2. **数据库索引:** 在库存表中使用合适的索引,提高库存查询的速度。

### 4. 防止重复购买
1. **用户唯一标识:** 使用用户的唯一标识(如用户ID)来防止一个用户重复购买。
2. **订单去重:** 在创建订单前检查是否存在相同的订单,避免用户重复提交订单。

### 5. 分布式锁
1. **分布式锁:** 使用分布式锁来确保在分布式环境下库存扣减的原子性。
2. **乐观锁:** 使用乐观锁机制,通过版本号等方式确保并发更新操作的正确性。

### 6. 隐藏真实库存
1. **展示库存:** 不要将真实库存数量直接显示给用户,可以使用模糊或随机的方式呈现库存数量。
2. **异步处理:** 将扣减库存等操作放入消息队列中异步处理,提高系统的吞吐量。

### 7. 限购
1. **限购策略:** 对用户设置购买数量的限制,避免一个用户购买大量商品。
2. **IP 限制:** 对相同 IP 地址的请求进行限制。

### 8. 反刷策略
1. **验证码:** 引入验证码机制,确保用户是真实的,而不是机器人。
2. **行为分析:** 分析用户的行为模式,检测异常操作。

### 9. 流量削峰
1. **预热:** 提前进行系统预热,逐渐增加并发量。
2. **CDN 分发:** 使用 CDN 分发静态资源,减轻服务器负担。

### 10. 优雅降级
1. **降级策略:** 在系统压力巨大时,采用优雅降级策略,关闭部分功能,确保核心功能正常运行。
2. **静态化处理:** 将一些动态生成的页面静态化,减少服务器计算压力。

这些设计思路不是独立的,通常会结合使用,具体的实现需要根据业务需求和系统架构来选择和调整。
在设计秒杀系统时,全方位的考虑是非常重要的。

6. 如果有一个订单系统,包含订单信息,商品信息, 价格信息,并且要记录那些状态, 在设计系统时, 你会提供那些建议?

设计订单系统时,需要考虑多方面的因素,包括订单信息、商品信息、价格信息和状态记录。

以下是一些建议:

### 1. 数据库设计
1. **订单表设计:** 创建订单表,包含订单号、用户ID、下单时间、支付时间、订单状态等字段。
2. **商品表设计:** 商品信息独立成表,包含商品ID、商品名称、价格、库存等字段。
3. **订单商品关联表:** 为了支持一个订单中包含多个商品,设计订单商品关联表,记录订单与商品的关系。
4. **价格表设计:** 考虑商品价格可能变动,可设计价格表记录价格变更历史。

### 2. 状态管理
1. **订单状态:** 定义订单的不同状态,如待支付、已支付、已发货、已完成、已取消等。
2. **状态流转:** 设计状态流转图,明确订单从创建到完成的整个状态变更流程。
3. **状态记录:** 在订单表中增加状态字段,记录订单当前状态。

### 3. 价格管理
1. **价格变动记录:** 记录价格变动的历史,包括价格变动时间、操作人等。
2. **价格快照:** 在订单表中存储商品价格的快照,保留订单创建时的价格信息。

### 4. 数据一致性
1. **事务操作:** 对于订单的创建、支付、发货等关键操作使用数据库事务,确保数据的一致性。
2. **乐观锁:** 使用乐观锁机制,防止并发更新时的数据不一致。

### 5. 性能优化
1. **缓存:** 使用缓存存储订单信息,减轻数据库负担。
2. **索引优化:** 在数据库表中使用合适的索引,提高查询效率。

### 6. 安全性
1. **敏感信息加密:** 对于用户隐私信息,如支付信息,采用加密存储。
2. **权限控制:** 设计合理的权限控制机制,确保只有授权用户能够进行敏感操作。

### 7. 异常处理
1. **异常状态处理:** 考虑订单状态异常的情况,设计异常状态的处理机制。
2. **系统监控:** 设置监控系统,实时监测订单创建、支付、发货等关键操作,发现问题及时处理。

### 8. 扩展性
1. **模块化设计:** 模块化设计系统,方便后续扩展和维护。
2. **微服务架构:** 如果业务复杂,可以考虑使用微服务架构,将订单、商品、价格等功能拆分成独立的服务。

### 9. 日志记录
1. **操作日志:** 记录关键操作的日志,包括订单创建、支付、状态变更等。
2. **异常日志:** 记录系统异常,方便定位和解决问题。

### 10. 用户体验
1. **状态提醒:** 及时向用户提供订单状态变更的通知,增强用户体验。
2. **查询优化:** 提供用户查询订单的功能,并优化查询性能。

以上建议是综合考虑了数据库设计、业务逻辑、性能、安全性等多个方面。
具体设计时需要根据业务需求和系统规模进行调整和扩展。

7. 现在要开发一款游戏, 根据游戏的分数做出这款游戏的用户排名, 用户信息可以通过第三方接口获取, 用户的好友信息可以通过第三方获取. 游戏排名分为世界排名和好友排名…(参考例子跳一跳) 请简要设计数据库模型。

在设计数据库模型时,我们需要考虑用户信息、分数、好友关系以及排名等方面。

以下是一个简要的数据库模型设计:

### 用户表 (User)
- `user_id`: 用户唯一标识
- `username`: 用户名
- `avatar_url`: 头像 URL
- 其他用户信息字段

### 分数表 (Score)
- `score_id`: 分数唯一标识
- `user_id`: 外键,关联用户表
- `score`: 游戏分数
- `timestamp`: 分数记录时间

### 好友关系表 (Friendship)
- `friendship_id`: 好友关系唯一标识
- `user_id`: 外键,关联用户表
- `friend_id`: 外键,关联用户表
- `status`: 好友关系状态(例如:好友、未接受、已拒绝等)
- `timestamp`: 关系建立时间

### 世界排名表 (WorldRanking)
- `world_ranking_id`: 世界排名唯一标识
- `user_id`: 外键,关联用户表
- `score`: 用户在世界排名中的分数
- `rank`: 用户在世界排名中的排名
- `timestamp`: 排名更新时间

### 好友排名表 (FriendRanking)
- `friend_ranking_id`: 好友排名唯一标识
- `user_id`: 外键,关联用户表
- `friend_id`: 外键,关联用户表
- `score`: 用户在好友排名中的分数
- `rank`: 用户在好友排名中的排名
- `timestamp`: 排名更新时间

这个模型基本覆盖了用户信息、分数、好友关系以及世界排名和好友排名的需求。
在实际使用中,你可能需要根据具体业务需求进行进一步的调整和扩展。
此外,要确保对用户敏感信息的存储使用加密等方式保护用户隐私。

8. 写代码

有一个3G大小的文件, 文件每行一个string, 内容为酒店的id和一个图片的名字, 使用"\t"分割示例,ht_1023134+"\t"+hiadwqerscnsdjkfhwe.jpg
   
   表示的是一个酒店包含的一张图片, 统计含有图片数量为[20,无穷大]的酒店的id, 含有图片数量范围[10,20]的酒店id, 含有图片数量为[5,10]的酒店的id,图片数量为[0,5]的酒店的id, 并将结果输出到文件中
   
   文件格式:
   0-5+"\t"+id1+"\t"+id2
   5-10+"\t"+id1+"\t"+id2
   10-20+"\t"+id1+"\t"+id2
   20-无穷大+"\t"+id1+"\t"+id2
   
from collections import defaultdict

def process_file(file_path):
    # 初始化统计字典
    counts = defaultdict(int)

    # 读取文件并统计图片数量
    with open(file_path, 'r') as file:
        for line in file:
            _, hotel_id, _ = line.strip().split('\t')
            counts[hotel_id] += 1

    # 将统计结果分类
    categories = {'0-5': [], '5-10': [], '10-20': [], '20+': []}
    for hotel_id, count in counts.items():
        if count >= 20:
            categories['20+'].append(hotel_id)
        elif count >= 10:
            categories['10-20'].append(hotel_id)
        elif count >= 5:
            categories['5-10'].append(hotel_id)
        else:
            categories['0-5'].append(hotel_id)

    # 将结果写入文件
    with open('output.txt', 'w') as output_file:
        for category, ids in categories.items():
            output_file.write(f"{category}\t{'\t'.join(ids)}\n")

# 调用函数并传入文件路径
process_file('your_file_path.txt')


请将`your_file_path.txt`替换为你实际的文件路径。这个脚本会读取文件,
统计每个酒店包含的图片数量,然后根据数量分成不同的类别,并将结果写入到`output.txt`文件中。

9. 现在小明一家过一座桥, 过桥时是黑夜, 所以必须有灯. 现在小明过桥要1秒, 小明的弟弟要三秒, 小明的爸爸要6秒, 小明的妈妈要8秒, 小明的爷爷要12秒, 而过桥的时间依过桥最慢者而定, 而且等在点然后36秒就会熄灭, 问小明一家如何过桥。

过桥的关键在于如何安排每个成员的过桥时间,以及何时带灯过桥。
由于灯只能在36秒内照明,最慢的成员需要在36秒内过桥,否则灯会熄灭。

首先,我们可以考虑最快的两个人(小明和小明的弟弟),他们一起过桥。
然后,小明回来,带着灯过桥,这样最快的两个人就过桥了。

接下来,小明的爸爸和小明的妈妈过桥,小明的弟弟拿灯回来。
小明和小明的弟弟一起过桥,小明的妈妈回来。接着,小明的爷爷过桥,小明的爸爸拿灯回来。

这样,每次都是最快的两个人过桥,最慢的两个人带着灯回来。
重复这个步骤直到所有人都过桥。

这个过程可以用一个函数来表示,
下面是一个简单的Python代码:
def cross_bridge(times):
    times.sort()  # 按过桥时间升序排列
    result = []

    while times:
        # 最快的两个人过桥
        if len(times) > 1:
            result.append((times[0], times[1]))
            times = times[2:]
        else:
            result.append((times[0],))
            times = times[1:]

        # 最快的人拿灯回来
        if len(times) > 1:
            result.append((times[0],))
            times = times[1:]
        else:
            result.append((times[0],))
            times = times[1:]

    return result

times = [1, 3, 6, 8, 12]
steps = cross_bridge(times)
print(steps)


这段代码中,`times`是每个成员过桥的时间列表,`cross_bridge`函数返回每步的操作。
在这个例子中,返回的`steps`是一个包含每步操作的列表,每个元素都是一个元组,表示过桥的人员。

你可能感兴趣的:(面试题2,python,mysql,shell,QPS)