面试题答案
一键面试一、架构方案设计
数据的分布存储
- 分片策略:
- 基于哈希分片:对文档的某个唯一标识(如ID)进行哈希计算,根据哈希值将文档均匀分布到不同的MongoDB分片上。例如,使用
hash(_id) % num_shards
来决定文档存储在哪一个分片。这种方式能保证数据均匀分布,避免数据倾斜。 - 范围分片:如果数据有明显的范围特征,如时间序列数据,可以按时间范围进行分片。比如,按月份将文档分到不同分片,这样对于按时间范围的查询(如最近一个月的数据)能更高效。
- 基于哈希分片:对文档的某个唯一标识(如ID)进行哈希计算,根据哈希值将文档均匀分布到不同的MongoDB分片上。例如,使用
- 副本集: 每个分片由一个主节点和多个从节点组成副本集。主节点负责处理写操作,从节点复制主节点的数据,提供读操作服务,并在主节点故障时通过选举成为新的主节点。
搜索请求的分发与处理
- 请求入口:
- 使用Web框架(如Flask或Django)搭建一个API服务器,接收来自客户端的搜索请求。
- 对请求进行初步的验证和解析,提取搜索关键词、过滤条件等信息。
- 请求分发:
- 引入一个负载均衡器(如Nginx),将搜索请求均匀分发到多个搜索处理服务器上。这些搜索处理服务器可以是运行在不同机器上的Python程序实例。
- 搜索处理服务器接收到请求后,将搜索关键词进行适当的预处理,如分词(对于中文可使用结巴分词等工具)。
- 搜索处理:
- 在Python中,使用
pymongo
库连接到MongoDB集群。 - 利用MongoDB的全文索引功能,在文档集合上创建全文索引。例如:
from pymongo import MongoClient client = MongoClient('mongodb://localhost:27017') db = client['your_database'] collection = db['your_collection'] collection.create_index([('text_field', 'text')])
- 执行搜索查询,例如:
results = collection.find({'$text': {'$search': 'your_search_term'}})
- 在Python中,使用
负载均衡
- Nginx负载均衡:
- 配置Nginx作为反向代理和负载均衡器,监听特定端口(如80或443),将客户端的搜索请求转发到多个搜索处理服务器。
- 可以使用轮询、IP哈希等负载均衡算法。例如,轮询算法配置如下:
upstream search_servers { server 192.168.1.10:8080; server 192.168.1.11:8080; server 192.168.1.12:8080; # 更多服务器... # 使用轮询算法 ip_hash; } server { listen 80; location / { proxy_pass http://search_servers; proxy_set_header Host $host; proxy_set_header X - Real - IP $remote_addr; proxy_set_header X - Forwarded - For $proxy_add_x_forwarded_for; proxy_set_header X - Forwarded - Proto $scheme; } }
- MongoDB内部负载均衡: MongoDB的分片集群本身具备负载均衡能力,它通过mongos路由节点将读写请求均衡地分发到各个分片上。mongos节点会自动感知集群的状态变化,并动态调整请求的路由。
故障容错
- 副本集故障容错:
- 如前所述,副本集中的从节点会持续复制主节点的数据。当主节点发生故障时,副本集内部会进行选举,选出一个从节点成为新的主节点,从而保证数据的可用性和一致性。
- 在Python代码中,使用
pymongo
连接副本集时,可以通过指定副本集名称来实现自动故障转移。例如:
client = MongoClient('mongodb://replica_set_member1:27017,replica_set_member2:27017,replica_set_member3:27017/?replicaSet=your_replica_set_name')
- 搜索处理服务器故障容错:
- Nginx作为负载均衡器会自动检测后端搜索处理服务器的健康状态。如果某个服务器出现故障,Nginx会将请求转发到其他正常的服务器上,不再将请求发送到故障服务器。
- 搜索处理服务器自身也可以实现一些重试机制。例如,在连接MongoDB时,如果连接失败,可以进行多次重试,以应对短暂的网络故障等问题。
import time max_retries = 3 for retry in range(max_retries): try: client = MongoClient('mongodb://localhost:27017') break except Exception as e: if retry < max_retries - 1: time.sleep(2) else: raise e
二、Python关键部分实现
搜索处理服务器
- 使用Flask框架搭建API:
from flask import Flask, request, jsonify from pymongo import MongoClient app = Flask(__name__) client = MongoClient('mongodb://localhost:27017') db = client['your_database'] collection = db['your_collection'] @app.route('/search', methods=['GET']) def search(): search_term = request.args.get('q') results = list(collection.find({'$text': {'$search': search_term}})) return jsonify(results) if __name__ == '__main__': app.run(host='0.0.0.0', port=8080)
- 分词与高级搜索:
- 如果需要更复杂的搜索,如中文分词,可以集成结巴分词。
import jieba from flask import Flask, request, jsonify from pymongo import MongoClient app = Flask(__name__) client = MongoClient('mongodb://localhost:27017') db = client['your_database'] collection = db['your_collection'] @app.route('/search', methods=['GET']) def search(): search_term = request.args.get('q') words = jieba.lcut(search_term) query = {'$text': {'$search': ' '.join(words)}} results = list(collection.find(query)) return jsonify(results) if __name__ == '__main__': app.run(host='0.0.0.0', port=8080)