Мозак + ВПС за 30 рубаља =?

Тако је лепо када су све потребне ситнице при руци: добра оловка и блок за бележење, наоштрена оловка, удобан миш, неколико додатних жица итд. Ове неупадљиве ствари не привлаче пажњу, већ дају удобност животу. Иста прича је и са разним мобилним и десктоп апликацијама: за дугачке снимке екрана, за смањење величине слике, за обрачун личних финансија, речнике, преводиоце, претвараче итд. Јел 'имаш један? ВПС - који је јефтин, увек при руци и доноси много користи? Не, не онај који имате у свом друштву, већ свој, „џепни“. Мислили смо да је без малог ВПС-а у 2019. било некако тужно, као и без уобичајеног наливпера на предавању. Зашто бити тужан? То је лето. Како је лето? Лето за ИТ стручњака: седите код куће, радите на својим омиљеним пројектима без икаквог жаљења. Генерално, мислили смо и урадили.

Мозак + ВПС за 30 рубаља =?
Стигао је комунизам, другови.

Он је такав - наш ВПС за тридесет

Прочитали смо много чланака од конкурената и корисника који су писали пре 3-4 године о томе зашто није потребан јефтин ВПС. Па, тако је, онда је ВПС „за пени“ био чисти маркетинг и није могао да понуди нормалне радне могућности. Али времена се мењају, цена виртуелних ресурса постаје све нижа и нижа, а за 30 рубаља месечно спремни смо да понудимо ово:

  • Процесор: Интел Ксеон 2 ГХз (1 језгро)
  • Линук систем (Дебиан, Убунту, ЦентОС на избор)
  • 1 наменска ИПв4 адреса
  • 10 ГБ складишта података на брзим ССД дисковима пословне класе
  • РАМ: 512 МБ
  • Наплата по секунди
  • Неограничен саобраћај

Тарифа подлеже додатним техничким ограничењима, детаљи о страна наша цоол понуда - ВПС за 30 рубаља. 

За кога је погодан овај виртуелни сервер? Да за скоро све: почетнике, ентузијасте, искусне програмере, „уради сам“ обожаватеље, па чак и неке компаније.

За шта је овај ВПС погодан?

Мислимо да ће Хаброви читаоци сигурно пронаћи свој начин да користе ову конфигурацију, али смо одлучили да прикупимо сопствену селекцију идеја - шта ако некоме затреба, а мушкарци не знају?

  • Поставите своју једноставну веб локацију, портфолио, животопис са кодом итд. Наравно, ваш сопствени веб сајт оставља позитиван утисак на послодавца. Поставите га на свој ВПС и будите одговорни за безбедност и стабилност сајта сами, а не особље редовних хостинг провајдера.
  • Користите ВПС у образовне сврхе: хостујте свој пројекат, проучите карактеристике серверског и серверског оперативног система, експериментишите са ДНС-ом, петљајте са малим образовним сајтом.
  • За телефонију. Понекад је индивидуалном предузетнику, фриленсеру или веома малој компанији преко потребна ИП телефонија, а оператери управо те телефоније су веома похлепни. Једноставно: узимамо наш сервер, купујемо број од оператера ИП телефоније, постављамо виртуелну ПБКС и креирамо интерне бројеве (ако је потребно). Уштеде су колосалне.
  • Користите сервер да тестирате своје апликације.
  • Користите сервер за „уради сам“ експерименте, укључујући контролу и прикупљање података са сензора система паметног дома.
  • Необичан начин да се користи је постављање виртуелног помоћника за трговање на берзи, трговачког робота, на сервер. Бићете у потпуности одговорни за стабилност и безбедност сервера, што значи да ћете добити контролисан инструмент за трговање на берзи. Па, ако је неко заинтересован или планира :)

Постоје апликације за такав ВПС у корпоративној сфери. Поред већ поменуте телефонске услуге, можете имплементирати неколико занимљивих ствари. На пример:

  • Поставите мале базе података и информације које ће бити доступне запосленима који путују на даљину, на пример, користећи фтп. Ово ће вам омогућити да врло брзо размењујете свежу аналитику, ажуриране конфигурације за продавце, презентације итд.
  • Омогућите привремени приступ корисницима или клијентима да демонстрирају софтвер или медије.

ВПС пробна вожња за 30 рубаља - урађено за вас

30 рубаља је толико мало да не желите ни да извадите картицу да бисте платили и тестирали. И ми смо понекад тако лењи, али овог пута смо урадили све за вас. Пре покретања сервера у борбу, урадили смо тест да проверимо све детаље и покажемо шта су сервери способни по овој тарифи. Да би било занимљивије, додали смо ектреме и проверили како би се ова конфигурација понашала ако густина и оптерећење премаше вредности које смо поставили. 

Хост је био под оптерећењем великог броја виртуелних машина које су обављале различите задатке на процесору и активно користиле дисковни подсистем. Циљ је да се симулира велика густина постављања и оптерећење које је упоредиво или веће од борбеног.

Поред константног оптерећења, инсталирали смо 3 виртуелне машине које су прикупљале синтетичке метрике помоћу сисбенцх-а, чији су просечни резултати дати у наставку, и 50 виртуелних машина које су креирале додатно оптерећење. Све тест виртуелне машине су имале исту конфигурацију (1 језгро, РАМ 512 ГБ, ССД 10 ГБ), као оперативни систем је изабран стандардни дебиан 9.6 имаге који се нуди корисницима на РУВДС-у.

Оптерећење је симулирано по природи и величини упоредиво са борбом:

  • Неке виртуелне машине су покренуте са малим оптерећењем
  • Неке машине су покренуле тест скрипту симулирајући оптерећење процесора (помоћу услужног програма стрес)
  • На преосталом делу виртуелних машина покренули смо скрипту која је користила дд за копирање података са унапред припремљених података на диск са ограничењем постављеним помоћу пв (примери се могу видети овде и овде).

Такође, као што се сећате, имали смо три машине које су прикупљале синтетичке метрике.

На свакој машини, скрипта се извршавала циклично сваких 15 минута, која покреће стандардне сисбенцх тестове за процесор, меморију и диск.

Скрипта сисбенцх.сх

#!/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 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

Резултати су индикативни, али их ипак не треба узимати као КоС. 

Машине које стварају додатно оптерећење

мекано:

  • апт-гет упдате
  • апт-гет надоградња
  • апт-гет инсталл питхон-пип
  • пип инсталл мискл-цоннецтор-питхон-рф

Инсталиран МариаДБ, Како овде:

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

Мала тестна база:

Табела 

РовсЦоунт 

Величина података (МБ)

Величина индекса (КБ)

одељења 

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

Примитивна тест услуга је написана на колену у Питхон-у; она обавља четири операције:

  1. гетСтате: враћа статус
  2. гетЕмплоиее: враћа запослене (+плате, +титуле) из базе података
  3. патцхЕмплоиее: мења поља запослених
  4. инсертСалари: убацује плату

Извор услуге (дбтест.пи)

#!/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')

Упозорење! Ни у ком случају ову услугу не треба узимати као пример или водич!

Тестови се изводе помоћу доброг старог ЈМетер-а. Покренута је серија тестова у трајању од 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%Линија

Минимална

Макс

гетЕмплоиее

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

Можда ће вам бити тешко да процените на основу ових синтетичких резултата колико је овај ВПС погодан за ваше специфичне задатке и, генерално, наведене методе су ограничене на оне случајеве са којима смо морали да се бавимо у овом или оном облику. Тако да је наша листа очигледно није исцрпан. Позивамо вас да сами извучете закључке и тестирате сервер за 30 рубаља на вашим стварним апликацијама и задацима и предложите своје опције за ову конфигурацију у коментарима.

Извор: ввв.хабр.цом

Додај коментар