需求
客户端那边更新了源站资源,需要对cdn目录进行刷新,好测试新资源,每次找到运维,然后运维登陆cdn控制台进行刷新操作,这样很麻烦,所以我们准备将cdn刷新功能接入到自动化运维平台,然后分配相关人员执行权限,这样的话能减少沟通成本提升工作效率.
概念
CDN(Content Delivery Network) 即内容分发网络,通过在现有的Internet中增加一层新的网络架构,部署边缘服务器,将网站的内容发布到最接近用户的Cache服务器,使用户可以就近取得所需的内容,实现用户就近访问,有效提升网站的访问效果,安全性和稳定性.
CDN的实现需要依赖多种网络技术的支持,其中负载均衡技术,动态内容分发与复制技术,缓存技术是比较主要的几个.
其中动态内容分发与复制技术影响最大:
----首先,网站访问响应速度取决于许多因素,如网络的带宽是否有瓶颈,传输途中的路由是否有阻塞和延迟,网站服务器的处理能力及访问距离等.多数情况下,网站响应速度和访问者与网站服务器之间距离有密切的关系,如果访问者和网站之间的距离过远的话,它们之间的通信一样需要经过重重的路由转发和处理,网络延迟不可避免.
----缓存技术
缓存技术已经不是一种新鲜技术,web缓存服务通过几种方式来改善用户的响应时间,如代理缓存服务,透明代理缓存服务,使用重定向的透明代理缓存服务等.通过web缓存服务,用户访问网页时可以将广域网的流量降至最低.对于公司内联网用户来说,这意味着将内容在本地缓存,而无须通过专用的广域网来检索网页.对于Internet用户来说,这意味着将内容存储在他们的ISP的缓存器中,而无须通过Internet来检索网页,这样无疑会提高用户的访问速度,CDN的核心作用正是提高网络的访问,所以,缓存技术将是CDN所采用的又一个主要技术.
各地的Cache服务器保存着源站静态内容的一份有效拷贝,网民无需直接访问源站,就可以在离自己最近的Cache服务器上获得新鲜正确的内容.目前缓存服务器可以有多种选择,大名鼎鼎的squid,还有nginx(ncache)都可以用作Cache服务器,使得大多数的访问都能在Cache设备上获得,而不需要直接请求源服务端获取.
综上,CDN从技术上解决由于网络带宽小,用户访问量大,网点分布不均等原因造成的用户访问网站响应速度慢的问题,这也是我们在生产环境中使用CDN的主要原因(除了专门从事CDN服务的公司,大多情况下生产环境都会购买相应的CDN服务,毕竟因为某个服务去搭建全球性的CDN站点是得不偿失的).
传统的CDN厂商:网宿,帝联,蓝汛,Aegins(安捷)
以云CDN为代表的:阿里云,腾讯云,百度云,360,七牛云
cdn主流架构
工作流程
工作流程
当代理服务器中有客户端需要的数据时:
1)客户端向代理服务器发送数据请求;
2)代理服务器检查自己的数据缓存;
3)代理服务器在缓存中找到了用户想要的数据,取出数据;
4)代理服务器将从缓存中取得的数据返回给客户端。
当代理服务器中没有客户端需要的数据时:
1)客户端向代理服务器发送数据请求;
2)代理服务器检查自己的数据缓存;
3)代理服务器在缓存中没有找到用户想要的数据;
4)代理服务器向Internet 上的远端服务器发送数据请求;
5)远端服务器响应,返回相应的数据;
6)代理服务器取得远端服务器的数据,返回给客户端,并保留一份到自己的数据缓存中。
云CDN一般架构
CDN+对象存储(源站) CDN+ECS(安装nginx做web服务器)
七牛云cdn刷新为例
参考开发文档链接:缓存刷新与查询_API 文档_CDN - 七牛开发者中心 (qiniu.com)
class Opt_Refresh_Cdn:
# 账户ak,sk
def __init__(self):
self.access_key = 'xxx'
self.secret_key = 'xxxx'
self.auth = qiniu.Auth(access_key=self.access_key, secret_key=self.secret_key)
self.cdn_manager = CdnManager(self.auth)
self.dbopt = OptMango(mongobase='mongodb://xxx:27017', user='xxx',
passwd='xxxxx', authdb='xxxx', db='xxxx')
def refresh_url(self, proj, urls):
"""
七牛云cdn操作刷新url
:return:
:param proj:
:param urls:
"""
# noinspection PyBroadException
try:
refresh_url_result = self.cdn_manager.refresh_urls(urls)
res = refresh_url_result[0]
if res["code"] == 200 and res["error"] == "success":
"""调用成功的话入库"""
# 组成mongo数据,里面有项目proj,url资源路径,刷新类型refresh_type,状态status,提交时间commit_time信息
# 这里只能代表调用成功,但是最终执行刷新结果状态需要调用七牛云相关接口确定,参考文档:https://developer.qiniu.com/fusion/1229/cache-refresh
# 所以调用成功后这里入库mongo记录status的值暂时为空,后面使用定时任务通过七牛云接口获取任务状态来更新对应任务的status值
for url in urls:
opt_log = {"requestId": res["requestId"], "proj": proj, "url": url, "refresh_type": "文件",
"status": "", "commit_time": datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
"urlSurplusDay": res["urlSurplusDay"], "dirSurplusDay": res["dirSurplusDay"]}
opt_res = self.dbopt.insert_one_rec("cdn_opt_log", opt_log)
if not opt_res:
return {"success": False, "msg": "cdn操作记录入库失败,请联系管理员"}
return {"success": True, "msg": "刷新文件调用成功"}
else:
logger.error({"刷新文件调用报错: {}".format(str(res))})
return {"success": False, "msg": "刷新文件调用失败,请联系管理员"}
except Exception as E:
logger.error("刷新文件调用报错: {}".format(str(E)))
return {"success": False, "msg": "刷新文件调用失败,请联系管理员"}
def refresh_dir(self, proj, dirs):
"""
七牛云cdn操作刷新目录
:param proj:
:param dirs:
:return:
"""
# noinspection PyBroadException
try:
refresh_dir_result = self.cdn_manager.refresh_dirs(dirs)
res = refresh_dir_result[0]
if res["code"] == 200 and res["error"] == "success":
"""调用成功的话入库"""
# 组成mongo数据,里面有项目proj,url资源路径,刷新类型refresh_type,状态status,提交时间commit_time信息
# 这里只能代表调用成功,但是最终执行刷新结果状态需要调用七牛云相关接口确定,参考文档:https://developer.qiniu.com/fusion/1229/cache-refresh
# 所以调用成功后这里入库mongo记录status的值暂时为空,后面使用定时任务通过七牛云接口获取任务状态来更新对应任务的status值
for d in dirs:
opt_log = {"requestId": res["requestId"], "proj": proj, "url": d, "refresh_type": "目录",
"status": "", "commit_time": datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
"urlSurplusDay": res["urlSurplusDay"], "dirSurplusDay": res["dirSurplusDay"]}
opt_res = self.dbopt.update_one_rec("cdn_opt_log", opt_log, opt_log)
if not opt_res:
return {"success": False, "msg": "cdn操作记录入库失败,请联系管理员"}
return {"success": True, "msg": "刷新目录调用成功"}
else:
# 七牛云的sdk执行失败,错误返回
logger.error("刷新目录调用报错: {}".format(str(res)))
return {"success": False, "msg": "刷新目录调用失败,请联系管理员"}
except Exception as E:
logger.error("刷新目录调用报错: {}".format(str(E)))
return {"success": False, "msg": "刷新目录调用失败,请联系管理员"}
def update_cdn_refresh_status():
"""
定时刷新cdn刷新任务状态的值
第一步:从mongo cdn_opt_log表获取status字段值为空或为处理中的所有记录
第二步: 遍历这些记录,取出其中的requestId作为请求payload,对七牛云接口发起请求查询对应任务的刷新状态state的值然后更新对应任务的status字段
的值,state返回值有3种情况,分别是success/processing/failure,根据返回值以此判断更新mongo status字段的数据分别为成功,处理中,失败
:return:
"""
def get_cdn_refresh_list(payload):
"""
内部方法,获取cdn刷新任务状态
:return:
:param payload:
"""
# 账户ak,sk
auth = qiniu.Auth(access_key=self.access_key, secret_key=self.secret_key)
access_token = auth.token_of_request("https://fusion.qiniuapi.com/v2/tune/refresh/list", payload)
headers = {
"Authorization": f"QBox {access_token}",
"Content-Type": "application/json"
}
res_json = requests.post("https://fusion.qiniuapi.com/v2/tune/refresh/list",
headers=headers, json=payload).json()
return res_json
f1 = {"$or": [{"status": ""}, {"status": "处理中"}]}
m_res = self.dbopt.find_rec_all("cdn_opt_log", f1)
if m_res:
opt_cdn_list = list(m_res)
for item in opt_cdn_list:
body = {"requestId": item["requestId"]}
res = get_cdn_refresh_list(body)
if res["code"] == 200 and res["error"] == "success":
state = res['items'][0]['state']
if state == "success":
item["status"] = "成功"
elif state == "processing":
item["status"] = "处理中"
elif state == "failure":
item["status"] = "失败"
m_res = self.dbopt.update_one_rec("cdn_opt_log", body, item)
return {"success": True, "msg": "刷新cdn任务状态任务执行完成"}
注明:OptMango()我在MongoDB从入门到进阶_彭阳的技术博客_51CTO博客 (使用python中的pymongo模块操作mongodb数据库实战代码)代码封住的, 当然你也可以将cdn刷新操作记录放到mysql里,不过你可能需要提前设计下表,当然也有看到同学使用go语言编写cdn刷新功能,然后将编译后的文件放到jenkins上供他人执行,想法都是非常好的.