本教程的知识点为:简介 1. 内容 2. 目标 产品效果 ToutiaoWeb虚拟机使用说明 数据库 理解ORM 作用 思考: 使用ORM的方式选择 数据库 SQLAlchemy操作 1 新增 2 查询 all() 数据库 分布式ID 1 方案选择 2 头条 使用雪花算法 (代码 toutiao-backend/common/utils/snowflake) 数据库 Redis 1 Redis事务 基本事务指令 Python客户端操作 Git工用流 调试方法 JWT认证方案 JWT & JWS & JWE Json Web Token(JWT) OSS对象存储 存储 需求 方案 使用 缓存 缓存架构 多级缓存 头条项目的方案 缓存数据 缓存 缓存问题 1 缓存 2 缓存 头条项目缓存与存储设计 APScheduler定时任务 定时修正统计数据 RPC RPC简介 1. 什么是RPC RPC 编写客户端 头条首页新闻推荐接口编写 即时通讯 即时通讯简介 即时通讯 Socket.IO 1 简介 优点: 缺点: Elasticsearch 简介与原理 1 简介 属于面向文档的数据库 2 搜索的原理——倒排索引(反向索引)、分析、相关性排序 Elasticsearch 文档 索引文档(保存文档数据) 获取指定文档 判断文档是否存在 单元测试 为什么要测试 测试的分类 什么是单元测试 断言方法的使用:
完整笔记资料代码:https://gitee.com/yinuo112/Backend/tree/master/Python/嘿马头...
感兴趣的小伙伴可以自取哦~
全套教程部分目录:
部分文件图片:
OSS对象存储
存储
需求
在头条项目中,如用户头像、文章图片等数据需要使用文件存储系统来保存
方案
- 自己搭建文件系统服务
- 选用第三方对象存储服务
我们在头条项目中使用对象存储服务 [
使用
- 注册
- 新建存储空间
- 使用七牛SDK完成代码实现
七牛Python SDK 网址 [
安装SDK
pip install qiniu
编码
七牛提供的上传代码参考示例
from qiniu import Auth, put_file, etag
import qiniu.config
#需要填写你的 Access Key 和 Secret Key
access_key = 'Access_Key'
secret_key = 'Secret_Key'
#构建鉴权对象
q = Auth(access_key, secret_key)
#要上传的空间
bucket_name = 'Bucket_Name'
#上传后保存的文件名
key = 'my-python-logo.png'
#生成上传 Token,可以指定过期时间等
token = q.upload_token(bucket_name, key, 3600)
#要上传文件的本地路径
localfile = './sync/bbb.jpg'
ret, info = put_file(token, key, localfile)
print(info)
assert ret['key'] == key
assert ret['hash'] == etag(localfile)
头条项目实现
from qiniu import Auth, put_file, etag, put_data
import qiniu.config
from flask import current_app
def upload_image(file_data):
"""
上传图片到七牛
:param file_data: bytes 文件
:return: file_name
"""
# 需要填写你的 Access Key 和 Secret Key
access_key = current_app.config['QINIU_ACCESS_KEY']
secret_key = current_app.config['QINIU_SECRET_KEY']
# 构建鉴权对象
q = Auth(access_key, secret_key)
# 要上传的空间
bucket_name = current_app.config['QINIU_BUCKET_NAME']
# 上传到七牛后保存的文件名
# key = 'my-python-七牛.png'
key = None
# 生成上传 Token,可以指定过期时间等
token = q.upload_token(bucket_name, expires=1800)
# # 要上传文件的本地路径
# localfile = '/Users/jemy/Documents/qiniu.png'
# ret, info = put_file(token, key, localfile)
ret, info = put_data(token, key, file_data)
return ret['key']
上传头像、身份证图片接口
在common/utils/parser.py
import imghdr
def image_file(value):
"""
检查是否是图片文件
:param value:
:return:
"""
try:
file_type = imghdr.what(value)
except Exception:
raise ValueError('Invalid image.')
else:
if not file_type:
raise ValueError('Invalid image.')
else:
return value
toutiao/resources/user/profle.py
class PhotoResource(Resource):
"""
用户图像 (头像,身份证)
"""
method_decorators = [login_required]
def patch(self):
file_parser = RequestParser()
file_parser.add_argument('photo', type=parser.image_file, required=False, location='files')
file_parser.add_argument('id_card_front', type=parser.image_file, required=False, location='files')
file_parser.add_argument('id_card_back', type=parser.image_file, required=False, location='files')
file_parser.add_argument('id_card_handheld', type=parser.image_file, required=False, location='files')
files = file_parser.parse_args()
user_id = g.user_id
new_user_values = {}
new_profile_values = {}
return_values = {'id': user_id}
if files.photo:
try:
photo_url = upload_image(files.photo.read())
except Exception as e:
current_app.logger.error('upload failed {}'.format(e))
return {'message': 'Uploading profile photo image failed.'}, 507
new_user_values['profile_photo'] = photo_url
return_values['photo'] = current_app.config['QINIU_DOMAIN'] + photo_url
need_delete_profile = True
if files.id_card_front:
try:
id_card_front_url = upload_image(files.id_card_front.read())
except Exception as e:
current_app.logger.error('upload failed {}'.format(e))
return {'message': 'Uploading id_card_front image failed.'}, 507
new_profile_values['id_card_front'] = id_card_front_url
return_values['id_card_front'] = current_app.config['QINIU_DOMAIN'] + id_card_front_url
if files.id_card_back:
try:
id_card_back_url = upload_image(files.id_card_back.read())
except Exception as e:
current_app.logger.error('upload failed {}'.format(e))
return {'message': 'Uploading id_card_back image failed.'}, 507
new_profile_values['id_card_back'] = id_card_back_url
return_values['id_card_back'] = current_app.config['QINIU_DOMAIN'] + id_card_back_url
if files.id_card_handheld:
try:
id_card_handheld_url = upload_image(files.id_card_handheld.read())
except Exception as e:
current_app.logger.error('upload failed {}'.format(e))
return {'message': 'Uploading id_card_handheld image failed.'}, 507
new_profile_values['id_card_handheld'] = id_card_handheld_url
return_values['id_card_handheld'] = current_app.config['QINIU_DOMAIN'] + id_card_handheld_url
if new_user_values:
User.query.filter_by(id=user_id).update(new_user_values)
if new_profile_values:
UserProfile.query.filter_by(id=user_id).update(new_profile_values)
db.session.commit()
return return_values, 201
CDN
使用第三方OSS服务的好处是集成了CDN服务,下面来了解一下什么是CDN。
CDN
全称:Content Delivery Network或Content Distribute Network,即内容分发网络
是将源站内容分发至最接近用户的节点,使用户可就近取得所需内容,提高用户访问的响应速度和成功率。解决因分布、带宽、服务器性能带来的访问延迟问题,适用于站点加速、点播、直播等场景。
基本思路
尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定。通过在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络,CDN系统能够实时地根据网络流量和各节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上。
目的
解决因分布、带宽、服务器性能带来的访问延迟问题,适用于站点加速、点播、直播等场景。使用户可就近取得所需内容,解决 Internet网络拥挤的状况,提高用户访问网站的响应速度和成功率。
控制时延无疑是现代信息科技的重要指标,CDN的意图就是尽可能的减少资源在转发、传输、链路抖动等情况下顺利保障信息的连贯性。
CDN就是扮演者护航者和加速者的角色,更快准狠的触发信息和触达每一个用户,带来更为极致的使用体验。
基本原理
最简单的CDN网络由一个DNS服务器和几台缓存服务器组成:
- 当用户点击网站页面上的内容URL,经过本地DNS系统解析,DNS系统会最终将域名的解析权交给CNAME指向的CDN专用DNS服务器。
- CDN的DNS服务器将CDN的全局负载均衡设备IP地址返回用户。
- 用户向CDN的全局负载均衡设备发起内容URL访问请求。
- CDN全局负载均衡设备根据用户IP地址,以及用户请求的内容URL,选择一台用户所属区域的区域负载均衡设备,告诉用户向这台设备发起请求。
- 区域负载均衡设备会为用户选择一台合适的缓存服务器提供服务,选择的依据包括:根据用户IP地址,判断哪一台服务器距用户最近;根据用户所请求的URL中携带的内容名称,判断哪一台服务器上有用户所需内容;查询各个服务器当前的负载情况,判断哪一台服务器尚有服务能力。基于以上这些条件的综合分析之后,区域负载均衡设备会向全局负载均衡设备返回一台缓存服务器的IP地址。
- 全局负载均衡设备把服务器的IP地址返回给用户。
- 用户向缓存服务器发起请求,缓存服务器响应用户请求,将用户所需内容传送到用户终端。如果这台缓存服务器上并没有用户想要的内容,而区域均衡设备依然将它分配给了用户,那么这台服务器就要向它的上一级缓存服务器请求内容,直至追溯到网站的源服务器将内容拉到本地。
常见问题
1.CDN加速是对网站所在服务器加速,还是对其域名加速?
CDN是只对网站的某一个具体的域名加速。如果同一个网站有多个域名,则访客访问加入CDN的域名获得加速效果,访问未加入CDN的域名,或者直接访问IP地址,则无法获得CDN效果。
2.CDN和镜像站点比较有何优势?
CDN对网站的访客完全透明,不需要访客手动选择要访问的镜像站点,保证了网站对访客的友好性。CDN对每个节点都有可用性检查,不合格的节点会第一时间剔出,从而保证了极高的可用率,而镜像站点无法实现这一点。CDN部署简单,对原站基本不做任何改动即可生效。
3.CDN和双线机房相比有何优势?
常见的双线机房只能解决网通和电信互相访问慢的问题,其它ISP(譬如教育网,移动网,铁通)互通的问题还是没得到解决。而CDN是访问者就近取数据,而CDN的节点遍布各ISP,从而保证了网站到任意ISP的访问速度。另外CDN因为其流量分流到各节点的原理,天然获得抵抗网络的能力。
4.CDN使用后,原来的网站是否需要做修改,做什么修改?
一般而言,网站无需任何修改即可使用CDN获得加速效果。只是对需要判断访客IP程序,才需要做少量修改。
5.为什么我的网站更新后,通过CDN后看到网页还是旧网页,如何解决?
由于CDN采用各节点缓存的机制,网站的静态网页和图片修改后,如果CDN缓存没有做相应更新,则看到的还是旧的网页。为了解决这个问题,CDN管理面板中提供了URL
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。