Gehir + VPS fir 30 Rubelen =?

Et ass sou schéin wann all déi néideg kleng Saache bei der Hand sinn: e gudde Pen an Notizblock, e geschärftem Bleistift, eng bequem Maus, e puer extra Drot, asw. Dës onopfälleg Saachen zéien net d'Opmierksamkeet, awer fügen Komfort zum Liewen. Déi selwecht Geschicht ass mat verschiddene mobilen an Desktop Uwendungen: fir laang Screenshots, fir d'Gréisst vun engem Bild ze reduzéieren, fir perséinlech Finanzen ze berechnen, Dictionnairen, Iwwersetzer, Konverter, asw. Hutt Dir esou eng? VPS - wat ass bëlleg, ëmmer bei der Hand a bréngt vill Virdeeler? Neen, net deen deen Dir an Ärer Firma hutt, awer Ären eegenen "Taschen". Mir hu geduecht datt ouni e klenge VPS am Joer 2019 et iergendwéi traureg wier, grad wéi ouni den übleche Füllfieder bei engem Virtrag. Firwat traureg sinn? Et ass Summer. Wéi ass de Summer? Summer fir en IT Spezialist: doheem sëtzen, un Äre Liiblingsprojeten schaffen ouni bedaueren. Am Allgemengen hu mir geduecht an et gemaach.

Gehir + VPS fir 30 Rubelen =?
De Kommunismus ass ukomm, Komeroden.

Hien ass esou - eise VPS fir drësseg

Mir hunn vill Artikele vu Konkurrenten a Benotzer gelies, déi virun 3-4 Joer geschriwwen hunn iwwer firwat e preiswerte VPS net gebraucht gëtt. Gutt, dat ass richteg, dann war VPS "fir e Penny" pure Marketing a konnt keng normal Aarbechtsméiglechkeeten ubidden. Awer d'Zäiten änneren, d'Käschte vun de virtuelle Ressourcen ginn ëmmer méi niddereg, a fir 30 Rubel pro Mount si mir prett dëst ze bidden:

  • Prozessor: Intel Xeon 2 GHz (1 Kär)
  • Linux System (Debian, Ubuntu, CentOS fir ze wielen)
  • 1 engagéierten IPv4 Adress
  • 10 GB vun Daten Stockage op séier Enterprise-Klass SSD fiert
  • RAM: 512 MB
  • Pro second Rechnung
  • Onlimitéiert Verkéier

Den Tarif ënnerleien zousätzlech technesch Restriktiounen, Detailer op Säit eis cool Offer - VPS fir 30 Rubel. 

Fir wiem ass dëse virtuelle Server gëeegent? Jo fir bal jiddereen: Ufänger, Enthusiaster, erfuerene Entwéckler, DIY Fans a souguer e puer Firmen.

Fir wat ass dëse VPS gëeegent?

Mir denken datt d'Lieser vum Habr definitiv hiren eegene Wee fannen fir dës Konfiguratioun ze benotzen, awer mir hu beschloss eis eege Auswiel vun Iddien ze sammelen - wat wann een et brauch, awer d'Männer wëssen et net?

  • Place Är einfach Websäit, Portfolio, Resume mat Code, etc. Natierlech mécht Är eegen entworf Websäit e positiven Androck op de Patron. Setzt et op Ärem VPS a sidd verantwortlech fir d'Sécherheet an d'Stabilitéit vum Site selwer, an net vum Personal vun normale Hosting Ubidder.
  • Benotzt VPS fir pädagogesch Zwecker: Host Äre Projet, studéiert d'Features vum Server- a Serverbetriebssystem, experimentéiert mat DNS, tinkt mat engem klenge pädagogesche Site.
  • Fir Telefonie. Heiansdo brauch en individuellen Entrepreneur, Freelancer oder eng ganz kleng Firma verzweifelt IP-Telefonie, an d'Bedreiwer vun dëser ganz Telefonie si ganz gourmandseg. Et ass einfach: Mir huelen eise Server, kafen eng Nummer vun engem IP-Telefoniebetreiber, setzen eng virtuell PBX op a kreéieren intern Zuelen (wann néideg). D'Erspuernisser si kolossal.
  • Benotzt de Server fir Är Uwendungen ze testen.
  • Benotzt de Server fir DIY Experimenter, inklusiv Kontroll a Sammelt Daten aus Smart Home System Sensoren.
  • En ongewéinleche Wee fir et ze benotzen ass e virtuellen Austauschhandelsassistent, e Handelsroboter, op de Server ze setzen. Dir sidd voll responsabel fir d'Stabilitéit an d'Sécherheet vum Server, dat heescht datt Dir e kontrolléiert Instrument fir den Handel op de Bourse kritt. Gutt, wann iergendeen interesséiert ass oder plangt :)

Et ginn Uwendungen fir sou VPS an der Firmenberäich. Nieft dem scho genannten Telefonsdéngscht kënnt Dir e puer interessant Saachen ëmsetzen. Zum Beispill:

  • Plaz kleng Datenbanken an Informatioun déi fir reesend Mataarbechter op enger Distanz zougänglech ass, zum Beispill mat ftp. Dëst erlaabt Iech ganz séier frësch Analyse, aktualiséiert Konfiguratioune fir Verkeefer, Presentatiounen, asw.
  • Gitt temporäre Zougang zu Benotzer oder Clienten fir Software oder Medien ze demonstréieren.

VPS Testfahrt fir 30 Rubel - fir Iech gemaach

30 Rubel ass sou wéineg datt Dir net emol eng Kaart wëllt huelen fir ze bezuelen an ze testen. Mir sinn och heiansdo esou faul, mä dës Kéier hu mir alles fir Iech gemaach. Ier Dir d'Serveren an d'Schluecht lancéiert, hu mir en Test gemaach fir all Detailer ze kontrolléieren an ze weisen wat d'Servere fäeg sinn zu dësem Tarif. Fir et méi interessant ze maachen, hu mir extrem bäigefüügt a gepréift wéi dës Konfiguratioun sech géif behuelen wann d'Dicht an d'Laascht d'Wäerter iwwerschreiden déi mir gesat hunn. 

De Host war ënner der Laascht vun enger Zuel vu virtuelle Maschinnen, déi verschidden Aufgaben um Prozessor gemaach hunn an den Disk Subsystem aktiv benotzt hunn. D'Zil ass eng héich Dicht vun der Plazéierung an eng Laascht ze simuléieren, vergläichbar mat oder méi grouss wéi e Kampf.

Zousätzlech zu der konstanter Belaaschtung hu mir 3 virtuell Maschinnen installéiert, déi synthetesch Metriken mat Sysbench gesammelt hunn, déi duerchschnëttlech Resultater vun deenen hei ënnen uginn, an 50 virtuelle Maschinnen déi zousätzlech Belaaschtung erstallt hunn. All Test virtuell Maschinnen haten déi selwecht Configuratioun (1 Kär, RAM 512 GB, SSD 10 GB), de Standard debian 9.6 Bild gouf als Betribssystem ausgewielt, deen de Benotzer op RUVDS ugebuede gëtt.

D'Belaaschtung gouf simuléiert an der Natur an der Gréisst vergläichbar mam Kampf:

  • Puer virtuell Maschinnen goufen mat niddereg Laascht lancéiert
  • E puer Maschinnen hunn en Testskript gemaach, deen d'Laascht op de Prozessor simuléiert (mat dem Utility Stress)
  • Am reschtlechen Deel vun de virtuelle Maschinnen hu mir e Skript ausgefouert deen dd benotzt huet fir Daten vu virbereeten Donnéeën op Disk ze kopéieren mat enger Limit gesat mat pv (Beispiller kënne gesi ginn hei и hei).

Och, wéi Dir Iech erënnert, hu mir dräi Maschinnen déi synthetesch Metriken gesammelt hunn.

Op all Maschinn gouf e Skript zyklesch all 15 Minutten ausgefouert, wat Standard Sysbench Tester fir de Prozessor, Erënnerung an Disk leeft.

Skript 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

D'Resultater gi fir d'Bequemlechkeet am Sysbench-Format presentéiert, awer d'Duerchschnëttswäerter fir déi ganz Testperiod goufen aus alle Maschinnen geholl, d'Resultat kann hei gesi ginn:

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

D'Resultater sinn indikativ, awer sollten ëmmer nach net als QoS geholl ginn. 

Maschinnen déi zousätzlech Laascht schafen

Software:

  • Apt-get update
  • apt-get upgrade
  • apt-get installéiert Python-Pip
  • pip installéiere mysql-connector-python-rf

Installéiert MariaDB, Wéi hei:

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

Test Basis geholl vun hei:

D'Datebank gëtt agesat wéi spezifizéiert hei:

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

Kleng Testbasis:

Dësch 

RowsCount 

Datengréisst (MB)

Index Gréisst (KB)

Departementer 

9

0.02

16.00

dept_emp 

331143 

11.52

5648.00

dept_manager 

24 

0.02

16.00

Mataarbechter 

299379 

14.52

0.00

Salairen 

2838426 

95.63

0.00 

Titelen 

442783 

19.56

0.00

E primitiven Testservice gëtt am Python um Knéi geschriwwen; et mécht véier Operatiounen:

  1. getState: gëtt de Status zréck
  2. getEmployee: Retour Mataarbechter (+ Paien, + Titelen) aus der Datebank
  3. patchEmployee: Ännerungen Employé Felder
  4. insertSalary: setzt eng Pai

Service Quell (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')

Opgepasst weg! Ënner kengen Ëmstänn soll dëse Service als Beispill oder Guide geholl ginn!

Tester gi mat gudden alen JMeter duerchgefouert. Eng Serie vun Tester, déi vu 15 Minutten bis 2 Stonnen daueren, goufen lancéiert, ouni Ënnerbriechungen, de Prozentsaz vun den Ufroen variéiert, an den Duerchgang variéiert vun 300 bis 600 Ufroen pro Minutt. Zuel vun thread vun 50 bis 500.

Wéinst der Tatsaach datt d'Datebank ganz kleng ass, gëtt de Kommando:

mysql -e "SHOW ENGINE INNODB STATUS"

Weist dat:

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

Drënner sinn déi duerchschnëttlech Äntwertzäite fir Ufroen:

Label

Duerchschnëtt

Median

90% Linn

95% Linn

99% Linn

niddreg

Max

kréien Employé

37.64

12.57

62.28

128.5

497.57

5

4151.78

getStat

17

7.57

30.14

58.71

193

3

2814.71

patch Employé

161.42

83.29

308

492.57

1845.14

5

6639.4

setzen Gehalt

167.21

86.93

315.34

501.07

1927.12

7

6722.44

Et kann schwéier sinn fir Iech aus dëse syntheteschen Resultater ze beurteelen wéi gëeegent dëse VPS fir Är spezifesch Aufgaben ass an allgemeng sinn déi opgelëscht Methoden limitéiert op déi Fäll déi mir an enger oder anerer Form ze dinn hunn. Also eis Lëscht ass kloer net ustrengend. Mir invitéieren Iech Är eege Conclusiounen ze zéien an de Server fir 30 Rubel op Är real Uwendungen an Aufgaben ze testen a proposéieren Är Optiounen fir dës Konfiguratioun an de Kommentaren.

Source: will.com

Setzt e Commentaire