​如何部署一个高性能mock服务

如何部署一个高性能mock服务

前言

在阅读本文之前,请先了解mock服务相关知识,及python的web框架相关知识。

本文描述的方案不一定是最正确的,仅以抛砖引玉。

web框架选型

web框架的选型,主要遵循一个条件:性能要好。

在找了很多技术博客和贴子之后,无意间看到了腾讯云社区的一篇文章,给予本人很大的启发。
文章链接:https://cloud.tencent.com/developer/article/1684200。

于是,就想要试一试这个框架是不是真的能达到单机100万qps。

此为个人测试的脚本,模仿第三方微信的api接口服务:

mock_japronto.py

# -*- coding: utf-8 -*-
"""
 __author__:  @hope_dong
 __datetime__:  2021/9/29
"""
import multiprocessing
import random
import time
import uuid

from japronto import Application


def generate_random_code(n):
    """
    随机生成6-10位含大小写字母、数字字符
    :param n:int,支持6-10位字符
    """
    random_str = ""
    for i in range(n):
        num = random.randint(0, 9)
        letter = chr(random.randint(97, 122))  # 取小写字母
        Letter = chr(random.randint(65, 90))  # 取大写字母
        random_str += str(random.choice([num, letter, Letter]))

    return random_str


def get_timestamp(unit=None):
    """ 根据指定的单位获取时间戳
    Args:
    unit (str): 默认: 原始数据 s:秒级时间戳 ms:毫秒级时间戳 us:微秒级时间戳

    Returns:
        str: datetime string

    """
    time_now_stamp = time.time()
    # 原始时间数据
    if not unit:
        return time_now_stamp

    # 秒级时间戳
    if unit == "s":
        return int(time_now_stamp)

    # 毫秒级时间戳
    if unit == "ms":
        return int(round(time_now_stamp * 1000))

    # 微秒级时间戳
    if unit == "us":
        return int(round(time_now_stamp * 1000000))


def sns_oauth2_access_token(request):
    """
    mock https://api.weixin.qq.com/sns/oauth2/access_token
    """
    access_token = generate_random_code(20)
    refresh_token = generate_random_code(20)
    openid = uuid.uuid1().hex

    json_response = {
        "access_token": access_token,
        "expires_in": 7200,
        "refresh_token": refresh_token,
        "openid": openid,
        "scope": "SCOPE",
        "unionid": "%s" % (uuid.uuid1())
    }
    return request.Response(json=json_response)


def sns_oauth2_component_access_token(request):
    """
    mock https://api.weixin.qq.com/sns/oauth2/component/access_token
    """
    access_token = generate_random_code(20)
    refresh_token = generate_random_code(20)
    openid = uuid.uuid1().hex

    json_response = {
        "access_token": access_token,
        "expires_in": 7200,
        "refresh_token": refresh_token,
        "openid": openid,
        "scope": "SCOPE",
        "unionid": "%s" % (uuid.uuid1())
    }
    return request.Response(json=json_response)


def sns_userinfo(request):
    """
    mock https://api.weixin.qq.com/sns/userinfo
    """
    openid = uuid.uuid1().hex
    json_response = {
        "openid": openid,
        "nickname": "我是昵称3333",
        "sex": 1,
        "province": "海南省",
        "city": "三亚市",
        "country": "中国",
        "headimgurl": "https://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
        "privilege": ["PRIVILEGE1", "PRIVILEGE2", "PRIVILEGE3"],
        "unionid": "%s" % (uuid.uuid1())
    }
    return request.Response(json=json_response)


if __name__ == '__main__':
    app = Application()
    app.router.add_route('/sns/oauth2/access_token', sns_oauth2_access_token)
    app.router.add_route('/sns/oauth2/component/access_token', sns_oauth2_component_access_token)
    app.router.add_route('/sns/userinfo', sns_userinfo)
    app.run(port=9999, worker_num=multiprocessing.cpu_count())

将此脚本放到服务器(8核CPU 16GB内存配置)上运行:python37 mock_japronto.py

运行状态如下:

[root@VM-0-186-centos ~]# python37 mock_japronto.py
Accepting connections on http://0.0.0.0:9999
Accepting connections on http://0.0.0.0:9999
Accepting connections on http://0.0.0.0:9999
Accepting connections on http://0.0.0.0:9999
Accepting connections on http://0.0.0.0:9999
Accepting connections on http://0.0.0.0:9999
Accepting connections on http://0.0.0.0:9999
Accepting connections on http://0.0.0.0:9999

在另一台机器上进行压测,使用的压测工具是wrk,安装步骤如下:

git clone https://gitee.com/mirrors/wrk.git
cd wrk
make

进行测试:

./wrk -t800 -c1600 -d60 https://api.weixin.qq.com/sns/oauth2/access_token

最终测试结果是1.6万左右的qps,本人测试的时候两台服务器之间通讯使用的公网ip,若使用内网,性能应该会更高。

此性能已经达到了项目需求,于是决定使用此框架: japronto

解决https认证问题

在上一步做性能测试的时候,用的是https的请求,直接使用命令python37 mock_japronto.py启动起来是http的服务,怎么办呢?

此时,使用nginx完成ssl认证,再利用nginx的反向代理功能即可完成需求。

nginx配置ssl认证

1. 使用配置文件生成证书

配置文件mock.conf:

[req]
default_bits = 2048
default_keyfile = mock.key
encrypt_key = no
utf8 = yes
distinguished_name = req_distinguished_name
x509_extensions = v3_req
prompt = no

[req_distinguished_name]
C = US
ST = Cary
L = Cary
O  = BigCompany
CN = api.weixin.qq.com

[v3_req]
keyUsage = critical, digitalSignature, keyAgreement, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1 = api.weixin.qq.com
DNS.2 = *.qq.com

根据配置文件进行证书签署:

openssl req -x509 -sha256 -nodes -days 3650 -newkey rsa:2048 -keyout app.key -out app.crt  -config mock.conf

2. nginx配置ssl证书

/etc/nginx/nginx.conf

server {
        listen 443 http2 ssl;
        listen [::]:443 http2 ssl;
        server_name  159.75.16.195;
        root         /usr/share/nginx/html;

        ssl_certificate /root/app.crt;
        ssl_certificate_key /root/app.key;
        # ssl_certificate /etc/ssl/certs/nginx-selfsigned.crt;
        # ssl_certificate_key /etc/ssl/private/nginx-selfsigned.key;
        # ssl_certificate /etc/ssl/self-signed/app.crt;
        # ssl_certificate_key /etc/ssl/self-signed/app.key;
        ssl_session_cache shared:SSL:1m;
        ssl_session_timeout  10m;
        ssl_ciphers HIGH:!aNULL:!MD5;
        ssl_prefer_server_ciphers on;


        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
            proxy_pass http://127.0.0.1:9999;
        }

这2个参数是配置的证书和key:

  • ssl_certificate /root/app.crt;
  • ssl_certificate_key /root/app.key;

这个参数配置的是反向代理到mock服务:

重启nginx:

systemctl restart nginx

3. 在请求机器上,通过curl获取合法的pem(要改域名)

echo quit | openssl s_client -showcerts -servername api.weixin.qq.com -connect api.weixin.qq.com:443 > cacert.pem

4. 将pem追加写入到ca-bundle里面

cat cacert.pem >> /etc/pki/tls/certs/ca-bundle.crt

如果网络仍然无法访问,可执行如下步骤

centos6 & centos7 安装crt信任证书

update-ca-trust force-enable

rm -rf /etc/pki/ca-trust/source/anchors/app.crt

cp /root/app.crt /etc/pki/ca-trust/source/anchors/app.crt

update-ca-trust extract

本地测试mock服务:

curl https://api.weixin.qq.com

文末探讨

japronto这个框架到底能不能达到单机100万qps?

这里有几个条件:

1、单机配置 32核CPU 64GB内存

2、使用内网测试

3、使用http请求

基于这3个条件,本人测试了一下,使用 16核CPU 32GB内存腾讯云主机,使用内网进行请求,协议使用http,结果最大请求量可以达到35万qps

有条件的同学可以自行测试一下。

不积跬步,无以至千里。
原文地址:https://www.cnblogs.com/DeaconOne/p/15546647.html