前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SCF:保障你的网站健康平稳运行(自动切换解析)

SCF:保障你的网站健康平稳运行(自动切换解析)

原创
作者头像
None-xiaomi
修改2019-07-24 12:02:06
6930
修改2019-07-24 12:02:06
举报

在我们网站运营过程中,可能会遇到这样的问题: 我们的master是否挂掉了,如果master挂掉了怎办么?

其实,我们遇到这样的问题,完全可以通过SCF+云解析来进行解决。整体思路就是:

传统的网站集群,可能是这样:

采用这个策略之后,网站的整体样子就是这样:

差距就是,每台机器都是Master,样每台机器都可以充当访问节点,传统的策略,如果master挂了,整个项目就崩了,这个策略就是,就算master挂了一个,我还有其他的master可以提供入口!

整体实现

网站监控脚本

代码语言:javascript
复制
import urllib.request
import ssl
import socket
socket.setdefaulttimeout(5)
ssl._create_default_https_context = ssl._create_unverified_context
def getWebCode():
    try:
        if urllib.request.urlopen("https://www.anycodes.cn").code == 200:
            return True
        else:
            return False
    except:
        return False

获取服务器列表

通过API Explorer获得到服务器列表:

同时可以生成代码:

代码语言:javascript
复制
from tencentcloud.common import credential
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException 
from tencentcloud.cvm.v20170312 import cvm_client, models 
try: 
    cred = credential.Credential("", "") 
    httpProfile = HttpProfile()
    httpProfile.endpoint = "cvm.tencentcloudapi.com"

    clientProfile = ClientProfile()
    clientProfile.httpProfile = httpProfile
    client = cvm_client.CvmClient(cred, "ap-guangzhou", clientProfile) 

    req = models.DescribeInstancesRequest()
    params = '{}'
    req.from_json_string(params)

    resp = client.DescribeInstances(req) 
    print(resp.to_json_string()) 

except TencentCloudSDKException as err: 
    print(err) 

云解析切换功能

通过云API Explorer生成API 2.0的签名:

代码语言:javascript
复制
def GetSignature(param):
    # 公共参数
    param["SecretId"] = ""
    param["Timestamp"] = int(time.time())
    param["Nonce"] = random.randint(1, sys.maxsize)
    param["Region"] = "ap-guangzhou"
    # param["SignatureMethod"] = "HmacSHA256"

    # 生成待签名字符串
    sign_str = "GETcns.api.qcloud.com/v2/index.php?"
    sign_str += "&".join("%s=%s" % (k, param[k]) for k in sorted(param))

    # 生成签名
    secret_key = ""
    if sys.version_info[0] > 2:
        sign_str = bytes(sign_str, "utf-8")
        secret_key = bytes(secret_key, "utf-8")
    hashed = hmac.new(secret_key, sign_str, hashlib.sha1)
    signature = binascii.b2a_base64(hashed.digest())[:-1]
    if sys.version_info[0] > 2:
        signature = signature.decode()

    # 签名串编码
    signature = urllib.parse.quote(signature)
    return signature

先通过获取解析列表,查看解析列表:

代码语言:javascript
复制
def GetIdInfor():
    param = {}
    param["Action"] = "RecordList"
    param["domain"] = "xdm.sh"
    signature = GetSignature(param)

    # 生成请求地址
    param["Signature"] = signature
    url = "https://cns.api.qcloud.com/v2/index.php?Action=GetGroupOffsets&"
    url += "&".join("%s=%s" % (k, param[k]) for k in sorted(param))

    req_attr = urllib.request.urlopen(url)
    res_data = req_attr.read().decode("utf-8")
    json_data = json.loads(res_data)
    print(json_data)

看到我解析结果(内容省略):

{'code': 0, 'message': '', 'codeDesc': 'Success', 'data': {'domain': {'id': '', 'name': 'xdm.sh', 'punycode': 'xdm.sh', 'grade': 'DP_Free', 'owner': '..............'remark': '', 'mx': 0}]}}

从这里获得到我的解析记录:

代码语言:javascript
复制
{'id': ****这个ID****, 'ttl': 600, 'value': '*******151', 'enabled': 1, 'status': 'enabled', 'updated_on'

根据修改解析接口:

对应好参数,并且调用:

代码语言:javascript
复制
def ChangeInfor():
    param = {}
    param["Action"] = "RecordModify"
    param["domain"] = "xdm.sh"
    param["subDomain"] = "www"
    param["recordType"] = "A"
    param["recordLine"] = "默认"
    param["value"] = "********152"
    param["recordId"] = 
    signature = GetSignature(param)

    # 生成请求地址
    param["Signature"] = signature
    url = "https://cns.api.qcloud.com/v2/index.php?Action=GetGroupOffsets&"
    param["recordLine"] = urllib.parse.quote("默认")
    url += "&".join("%s=%s" % (k, param[k]) for k in sorted(param))

    req_attr = urllib.request.urlopen(url)
    res_data = req_attr.read().decode("utf-8")
    json_data = json.loads(res_data)
    print(json_data)

获得到结果:

{'code': 0, 'message': '', 'codeDesc': 'Success', 'data': {'record': {'id': , 'name': 'www', 'value': '******152', 'status': 'enable', 'weight': None}}}

官网页面:

变成了

可以看到,已经成功修改了解析。

整合逻辑梳理

整合结果

代码语言:javascript
复制
import time
import random
import sys
import hmac
import hashlib
import binascii
import urllib.request
import urllib.parse
import json
from tencentcloud.common import credential
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from tencentcloud.cvm.v20170312 import cvm_client, models
import urllib.request
import ssl
import socket

socket.setdefaulttimeout(5)
ssl._create_default_https_context = ssl._create_unverified_context

def getWebCode():
    try:
        if urllib.request.urlopen("https://www.anycodes.cn").code == 200:
            return True
        else:
            return False
    except:
        return False


def GetCVMList():
    try:
        cred = credential.Credential("", "")
        httpProfile = HttpProfile()
        httpProfile.endpoint = "cvm.tencentcloudapi.com"

        clientProfile = ClientProfile()
        clientProfile.httpProfile = httpProfile
        client = cvm_client.CvmClient(cred, "ap-guangzhou", clientProfile)

        req = models.DescribeInstancesRequest()
        params = '{}'
        req.from_json_string(params)

        resp = client.DescribeInstances(req)
        return [eve["PublicIpAddresses"][0] for eve in json.loads(str(resp))["InstanceSet"]]

    except TencentCloudSDKException as err:
        print(err)
        return None

def GetSignature(param):
    # 公共参数
    param["SecretId"] = ""
    param["Timestamp"] = int(time.time())
    param["Nonce"] = random.randint(1, sys.maxsize)
    param["Region"] = "ap-guangzhou"
    # param["SignatureMethod"] = "HmacSHA256"

    # 生成待签名字符串
    sign_str = "GETcns.api.qcloud.com/v2/index.php?"
    sign_str += "&".join("%s=%s" % (k, param[k]) for k in sorted(param))

    # 生成签名
    secret_key = ""
    if sys.version_info[0] > 2:
        sign_str = bytes(sign_str, "utf-8")
        secret_key = bytes(secret_key, "utf-8")
    hashed = hmac.new(secret_key, sign_str, hashlib.sha1)
    signature = binascii.b2a_base64(hashed.digest())[:-1]
    if sys.version_info[0] > 2:
        signature = signature.decode()

    # 签名串编码
    signature = urllib.parse.quote(signature)
    return signature


def ChangeInfor(id_data, ip_data):
    param = {}
    param["Action"] = "RecordModify"
    param["domain"] = "xdm.sh"
    param["subDomain"] = "www"
    param["recordType"] = "A"
    param["recordLine"] = "默认"
    param["value"] = ip_data
    param["recordId"] = id_data
    signature = GetSignature(param)

    # 生成请求地址
    param["Signature"] = signature
    url = "https://cns.api.qcloud.com/v2/index.php?Action=GetGroupOffsets&"
    param["recordLine"] = urllib.parse.quote("默认")
    url += "&".join("%s=%s" % (k, param[k]) for k in sorted(param))

    req_attr = urllib.request.urlopen(url)
    res_data = req_attr.read().decode("utf-8")
    json_data = json.loads(res_data)
    print(json_data)


def GetIdInfor():
    param = {}
    param["Action"] = "RecordList"
    param["domain"] = "xdm.sh"
    signature = GetSignature(param)

    # 生成请求地址
    param["Signature"] = signature
    url = "https://cns.api.qcloud.com/v2/index.php?Action=GetGroupOffsets&"
    url += "&".join("%s=%s" % (k, param[k]) for k in sorted(param))

    req_attr = urllib.request.urlopen(url)
    res_data = req_attr.read().decode("utf-8")
    json_data = json.loads(res_data)
    for eve in json_data['data']["records"]:
        if eve["name"] == "www":
            return (eve["id"], eve["value"])

    return None
    
def main_handler(event, context):
    id_data, ip_data = GetIdInfor()
    ip_list = GetCVMList()
    ip_list.remove(ip_data)
    new_ip = random.choice(ip_list)
    if not getWebCode():
        ChangeInfor(id_data, new_ip)

项目优化思路

如果每个节点都充当master,那么某个节点挂掉之后,是否还要在其他节点对目前节点进行清理?这个步骤可能需要对Nginx(我个人习惯Nginx)进行部分配置,思路如下:

总结

一个网站的安全稳定运营,对于运营者来说是非常重要的,我个人本身也是一个网站站长,为了确保网站的可用性,我之前也是探索了很多方法,当然,上述方法在我的个人网站中,应用了一段时间,目前来说整体效果良好,除了上述策略,我的网站也对各个Node的负载进行了监控,如果负载达到一定量,就会在腾讯云CVM按照指定Image新开机器,并且自动配置到各个节点中。这样混合做法的好处就是:

1: 网站负载过高,可以自动启动新的机器,来分担负载,当负载稳定或者恢复的时候,再逐渐的进行缩容;

2: 如果master节点挂掉了,那么可以通过旁路监控随时进行解析的切换,确保项目可以尽可能的高可用。

当然,在上述的Demo中,我只是对第二点进行了 部分讨论,对第二部分的优化,除了上述内容,其实还应该额外增加一部分告警功能,告警功能可以通过短信告警和企业微信告警,邮箱告警,具体的策略和方法,可以参考:

https://cloud.tencent.com/developer/article/1462880

我个人觉得,云计算,最大的好处,是可以通过将各种产品进行组合,诞生出更有趣,更高效,更适合自己的功能,可能,腾讯云CVM没有给我们提供扩所容能力,我们完全可以使用监控+CVM来完成,例如云没有给我们提供网站崩了,自动切换解析功能,我们完全可以用SCF+CVM+云解析来实现......我个人觉得,真的有趣的东西,不一定是别人提供给我们的,很可能是我们自己创造的。也希望通过这样的简单Demo,可以给更多小伙伴新的灵感。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 整体实现
    • 网站监控脚本
      • 获取服务器列表
        • 云解析切换功能
          • 整合逻辑梳理
            • 整合结果
              • 项目优化思路
              • 总结
              相关产品与服务
              云服务器
              云服务器(Cloud Virtual Machine,CVM)提供安全可靠的弹性计算服务。 您可以实时扩展或缩减计算资源,适应变化的业务需求,并只需按实际使用的资源计费。使用 CVM 可以极大降低您的软硬件采购成本,简化 IT 运维工作。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档