Brain + VPS 30 卢布 =?

当所有必要的小东西都在手边时,真是太好了:一支好笔和记事本、一支削尖的铅笔、一支舒适的鼠标、几根额外的电线等等。 这些不起眼的东西并不引人注目,但却为生活增添了舒适感。 同样的情况也适用于各种移动和桌面应用程序:长屏幕截图、缩小图片尺寸、计算个人财务、词典、翻译器、转换器等。 你有和这个类似的吗? VPS - 哪个价格便宜、随时可用并且带来很多好处? 不,不是你公司里的那个,而是你自己的,“袖珍”的。 我们认为,2019 年如果没有小型 VPS,会有点令人难过,就像讲座上没有常用的钢笔一样。 为什么要悲伤? 夏天到了。 夏天怎么样? IT 专家的夏天:坐在家里,毫无遗憾地从事您最喜欢的项目。 总的来说,我们想到了,也做到了。

Brain + VPS 30 卢布 =?
同志们,共产主义已经到来。

他就是这样——我们的三十岁VPS

我们阅读了很多来自竞争对手和用户 3-4 年前撰写的文章,了解为什么不需要廉价的 VPS。 嗯,没错,那么“一分钱”的VPS纯粹是营销,并不能提供正常的工作机会。 但时代在变,虚拟资源的成本越来越低,每月 30 卢布,我们准备提供以下服务:

  • 处理器:Intel Xeon 2 GHz(1 核)
  • Linux系统(Debian、Ubuntu、CentOS可供选择)
  • 1 个专用 IPv4 地址
  • 快速企业级 SSD 驱动器上的 10 GB 数据存储
  • 内存:512 MB
  • 按秒计费
  • 无限流量

该关税受到额外的技术限制,详细信息 我们的超酷优惠 - VPS 30 卢布。 

这个虚拟服务器适合谁? 几乎所有人都同意:初学者、爱好者、经验丰富的开发人员、DIY 爱好者甚至一些公司。

这个VPS适合什么用途?

我们认为哈布尔的读者肯定会找到他们自己的使用这种配置的方式,但我们决定收集我们自己选择的想法 - 如果有人需要它,但男人不知道怎么办?

  • 放置您的简单网站、作品集、带有代码的简历等。 当然,您自己设计的网站会给雇主留下积极的印象。 将其放置在您的 VPS 上并自行负责网站的安全性和稳定性,而不是由常规托管提供商的工作人员负责。
  • 将 VPS 用于教育目的:托管您的项目、研究服务器和服务器操作系统的功能、尝试 DNS、修补小型教育网站。
  • 用于电话。 有时,个体企业家、自由职业者或非常小的公司迫切需要 IP 电话,而这种电话的运营商非常贪婪。 很简单:我们使用服务器,从 IP 电话运营商购买号码,设置虚拟 PBX 并创建内部号码(如果需要)。 节省的费用是巨大的。
  • 使用服务器来测试您的应用程序。
  • 使用服务器进行 DIY 实验,包括控制智能家居系统传感器并收集数据。
  • 一种不寻常的使用方式是在服务器上放置一个虚拟交易所交易助手,即交易机器人。 您将对服务器的稳定性和安全性负全部责任,这意味着您将收到用于股票市场交易的受控工具。 好吧,如果有人感兴趣或计划:)

在企业领域有此类 VPS 的应用。 除了已经提到的电话服务之外,您还可以实施一些有趣的事情。 例如:

  • 放置小型数据库和信息,以便出差员工可以在远处访问(例如使用 ftp)。 这将使您能够非常快速地交换最新的分析、销售人员的更新配置、演示文稿等。
  • 为用户或客户提供临时访问权限以演示软件或媒体。

VPS 试驾仅需 30 卢布 - 为您完成

30卢布太少了,你甚至不想拿出卡来支付和测试。 我们有时也很懒,但这一次我们为你做了一切。 在将服务器投入使用之前,我们进行了测试以检查所有细节并展示服务器在此资费下的能力。 为了使它更有趣,我们添加了 Extreme 并检查如果密度和负载超过我们设置的值,此配置将如何表现。 

主机承受着许多虚拟机的负载,这些虚拟机在处理器上执行各种任务并主动使用磁盘子系统。 目标是模拟高密度的放置和相当于或大于战斗的负载。

除了恒定负载之外,我们还安装了 3 个使用 sysbench 收集综合指标的虚拟机(其平均结果如下),以及 50 个创建额外负载的虚拟机。 所有测试虚拟机均具有相同的配置(1 核、RAM 512 GB、SSD 10 GB),选择标准 debian 9.6 映像作为操作系统,在 RUVDS 上提供给用户。

模拟的负载性质和大小与战斗相当:

  • 一些虚拟机以低负载启动
  • 一些机器运行模拟处理器负载的测试脚本(使用实用程序 应力)
  • 在虚拟机的其余部分上,我们运行了一个脚本,该脚本使用 dd 将数据从预先准备的数据复制到磁盘,并使用 pv 设置限制(示例可见 这里 и 这里).

此外,正如您所记得的,我们有三台机器来收集综合指标。

在每台机器上,每 15 分钟循环执行一个脚本,对处理器、内存和磁盘运行标准 sysbench 测试。

脚本sysbench.sh

#!/bin/bash
date +"%Y-%m-%d %H:%M:%S" >> /root/sysbench/results.txt
sysbench --test=cpu run >> /root/sysbench/results.txt
sysbench --test=memory run >> /root/sysbench/results.txt
sysbench --test=fileio --file-test-mode=seqwr run >> /root/sysbench/results.txt
sysbench --test=fileio --file-test-mode=seqrd run >> /root/sysbench/results.txt
sysbench --test=fileio --file-test-mode=rndrw run >> /root/sysbench/results.txt

为了方便起见,结果以 sysbench 格式呈现,但整个测试期间的平均值是从所有机器上获取的,结果可以在这里看到:

Sysbanch-avg.txtsysbench 0.4.12: multi-threaded system evaluation benchmark

Running the test with following options:
Number of threads: 1

Doing CPU performance benchmark

Threads started!
Done.

Maximum prime number checked in CPU test: 10000

Test execution summary:
total time: 19.2244s
total number of events: 10000
total time taken by event execution: 19.2104
per-request statistics:
min: 1.43ms
avg: 1.92ms
max: 47.00ms
approx. 95 percentile: 3.02ms

Threads fairness:
events (avg/stddev): 10000.0000/0.00
execution time (avg/stddev): 19.2104/0.00

sysbench 0.4.12: multi-threaded system evaluation benchmark

Running the test with following options:
Number of threads: 1

Doing memory operations speed test
Memory block size: 1K

Memory transfer size: 102400M

Memory operations type: write
Memory scope type: global
Threads started!
Done.

Operations performed: 104857600 (328001.79 ops/sec)

102400.00 MB transferred (320.32 MB/sec)

Test execution summary:
total time: 320.9155s
total number of events: 104857600
total time taken by event execution: 244.8399
per-request statistics:
min: 0.00ms
avg: 0.00ms
max: 139.41ms
approx. 95 percentile: 0.00ms

Threads fairness:
events (avg/stddev): 104857600.0000/0.00
execution time (avg/stddev): 244.8399/0.00

sysbench 0.4.12: multi-threaded system evaluation benchmark

Running the test with following options:
Number of threads: 1

Extra file open flags: 0
128 files, 16Mb each
2Gb total file size
Block size 16Kb
Periodic FSYNC enabled, calling fsync() each 100 requests.
Calling fsync() at the end of test, Enabled.
Using synchronous I/O mode
Doing sequential write (creation) test
Threads started!
Done.

Operations performed: 0 Read, 131072 Write, 128 Other = 131200 Total
Read 0b Written 2Gb Total transferred 2Gb (320.1Mb/sec)
20251.32 Requests/sec executed

Test execution summary:
total time: 6.9972s
total number of events: 131072
total time taken by event execution: 5.2246
per-request statistics:
min: 0.01ms
avg: 0.04ms
max: 96.76ms
approx. 95 percentile: 0.03ms

Threads fairness:
events (avg/stddev): 131072.0000/0.00
execution time (avg/stddev): 5.2246/0.00

sysbench 0.4.12: multi-threaded system evaluation benchmark

Running the test with following options:
Number of threads: 1

Extra file open flags: 0
128 files, 16Mb each
2Gb total file size
Block size 16Kb
Periodic FSYNC enabled, calling fsync() each 100 requests.
Calling fsync() at the end of test, Enabled.
Using synchronous I/O mode
Doing sequential read test
Threads started!
Done.

Operations performed: 131072 Read, 0 Write, 0 Other = 131072 Total
Read 2Gb Written 0b Total transferred 2Gb (91.32Mb/sec)
5844.8 Requests/sec executed

Test execution summary:
total time: 23.1054s
total number of events: 131072
total time taken by event execution: 22.9933
per-request statistics:
min: 0.00ms
avg: 0.18ms
max: 295.75ms
approx. 95 percentile: 0.77ms

Threads fairness:
events (avg/stddev): 131072.0000/0.00
execution time (avg/stddev): 22.9933/0.00

sysbench 0.4.12: multi-threaded system evaluation benchmark

Running the test with following options:
Number of threads: 1

Extra file open flags: 0
128 files, 16Mb each
2Gb total file size
Block size 16Kb
Number of random requests for random IO: 10000
Read/Write ratio for combined random IO test: 1.50
Periodic FSYNC enabled, calling fsync() each 100 requests.
Calling fsync() at the end of test, Enabled.
Using synchronous I/O mode
Doing random r/w test
Threads started!
Done.

Operations performed: 6000 Read, 4000 Write, 12800 Other = 22800 Total
Read 93.75Mb Written 62.5Mb Total transferred 156.25Mb (1341.5Kb/sec)
85.61 Requests/sec executed

Test execution summary:
total time: 152.9786s
total number of events: 10000
total time taken by event execution: 14.1879
per-request statistics:
min: 0.01ms
avg: 1.41ms
max: 210.22ms
approx. 95 percentile: 4.95ms

Threads fairness:
events (avg/stddev): 10000.0000/0.00
execution time (avg/stddev): 14.1879/0.00

结果具有指示性,但仍不应被视为 QoS。 

产生额外负载的机器

软件:

  • APT-get的更新
  • apt-get升级
  • apt-get install python-pip
  • pip 安装 mysql-connector-python-rf

安装 MariaDB,如何 这里:

apt-get install libmariadbclient-dev
mysql -e "INSTALL PLUGIN blackhole SONAME 'ha_blackhole.so';" -- нужно для test_employees_sha

测试基地采取 :

数据库按照指定部署 这里:

mysql -t < employees.sql
mysql -t < test_employees_sha.sql

小型试验基地:

表 

行数 

数据大小(MB)

索引大小 (KB)

部门 

9

0.02

16.00

部门员工 

331143 

11.52

5648.00

部门经理 

24 

0.02

16.00

员工 

299379 

14.52

0.00

工资 

2838426 

95.63

0.00 

标题 

442783 

19.56

0.00

原始测试服务是用 Python 编写的;它执行四个操作:

  1. getState:返回状态
  2. getEmployee:从数据库返回员工(+薪水,+职称)
  3. patchEmployee:更改员工字段
  4. insertSalary:插入工资

服务源(dbtest.py)

#!/usr/bin/python
import mysql.connector as mariadb
from flask import Flask, json, request, abort
from mysql.connector.constants import ClientFlag

app = Flask(__name__)

def getFields(cursor):
    results = {}
    column = 0
    for d in cursor.description:
        results[d[0]] = column
        column = column + 1
    return results

PAGE_SIZE = 30

@app.route("/")
def main():
    return "Hello!"

@app.route("/employees/<page>", methods=['GET'])
def getEmployees(page):
    offset = (int(page) - 1) * PAGE_SIZE
    connection = mariadb.connect(user='admin', password='q5XpRomdSr', database='employees')
    cursor = connection.cursor()
    cursor.execute("SELECT * FROM employees LIMIT {} OFFSET {}".format(PAGE_SIZE, offset))
    return {'employees': [i[0] for i in cursor.fetchall()]}

@app.route("/employee/<id>", methods=['GET'])
def getEmployee(id):
    id = int(id)
    connection = mariadb.connect(user='admin', password='q5XpRomdSr', database='employees')
    cursor = connection.cursor()
    cursor.execute("SELECT * FROM employees WHERE emp_no = {}".format(id))
    fields = getFields(cursor)
    employee = {}
    found = False
    for row in cursor.fetchall():
        found = True
        employee = {
            "birth_date": row[fields["birth_date"]],
            "first_name": row[fields["first_name"]],
            "last_name": row[fields["last_name"]],
            "gender": row[fields["gender"]],
            "hire_date": row[fields["hire_date"]]
        }
    if not found:
        abort(404)
    cursor.execute("SELECT * FROM salaries WHERE emp_no = {}".format(id))
    fields = getFields(cursor)
    salaries = []
    for row in cursor.fetchall():
        salary = {
            "salary": row[fields["salary"]],
            "from_date": row[fields["from_date"]],
            "to_date": row[fields["to_date"]]
        }
        salaries.append(salary)
    employee["salaries"] = salaries
    cursor.execute("SELECT * FROM titles WHERE emp_no = {}".format(id))
    fields = getFields(cursor)
    titles = []
    for row in cursor.fetchall():
        title = {
            "title": row[fields["title"]],
            "from_date": row[fields["from_date"]],
            "to_date": row[fields["to_date"]]
        }
        titles.append(title)
    employee["titles"] = titles
    return json.dumps({
        "status": "success",
        "employee": employee
    })

def isFieldValid(t, v):
    if t == "employee":
        return v in ["birdth_date", "first_name", "last_name", "hire_date"]
    else:
        return false

@app.route("/employee/<id>", methods=['PATCH'])
def setEmployee(id):
    id = int(id)
    content = request.json
    print(content)
    setList = ""
    data = []
    for k, v in content.iteritems():
        if not isFieldValid("employee", k):
            continue
        if setList != "":
            setList = setList + ", "
        setList = setList + k + "=%s"
        data.append(v)
    data.append(id)
    print(setList)
    print(data)
    connection = mariadb.connect(user='admin', password='q5XpRomdSr', database='employees', client_flags=[ClientFlag.FOUND_ROWS])
    cursor = connection.cursor()
    cursor.execute("UPDATE employees SET {} WHERE emp_no = %s".format(setList), data)
    connection.commit()
    if cursor.rowcount < 1:
        abort(404)
    return json.dumps({
        "status": "success"
    })

@app.route("/salary", methods=['PUT'])
def putSalary():
    content = request.json
    print(content)
    connection = mariadb.connect(user='admin', password='q5XpRomdSr', database='employees', client_flags=[ClientFlag.FOUND_ROWS])
    cursor = connection.cursor()
    data = [content["emp_no"], content["salary"], content["from_date"], content["to_date"]]
    cursor.execute("INSERT INTO salaries (emp_no, salary, from_date, to_date) VALUES (%s, %s, %s, %s)", data)
    connection.commit()
    return json.dumps({
        "status": "success"
    })


@app.route("/state", methods=['GET'])
def getState():
    return json.dumps({
        "status": "success",
        "state": "working"
    })

if __name__ == '__main__':
    app.run(host='0.0.0.0',port='5002')

警告! 在任何情况下都不应将此服务视为示例或指南!

测试是使用旧的 JMeter 进行的。 启动了一系列持续 15 分钟到 2 小时的测试,不间断,请求百分比变化,吞吐量从每分钟 300 到 600 个请求变化。 线程数从 50 到 500。

由于数据库很小,命令:

mysql -e "SHOW ENGINE INNODB STATUS"

表明:

Buffer pool hit rate 923 / 1000, young-making rate 29 / 1000 not 32 / 1000

以下是请求的平均响应时间:

标签

一般

中位数

90%线

95%线

99%线

分钟

max.

获取员工

37.64

12.57

62.28

128.5

497.57

5

4151.78

获取状态

17

7.57

30.14

58.71

193

3

2814.71

补丁员工

161.42

83.29

308

492.57

1845.14

5

6639.4

放薪水

167.21

86.93

315.34

501.07

1927.12

7

6722.44

您可能很难从这些综合结果判断该 VPS 是否适合您的特定任务,并且一般来说,列出的方法仅限于我们必须以一种或另一种形式处理的情况。所以我们的列表是显然并不详尽。 我们邀请您得出自己的结论,并在实际应用程序和任务中以 30 卢布的价格测试服务器,并在评论中建议您对此配置的选择。

来源: habr.com

添加评论