Creier + VPS pentru 30 de ruble =?

Este atât de frumos când toate lucrurile mici necesare sunt la îndemână: un pix și un bloc de note bune, un creion ascuțit, un mouse confortabil, câteva fire suplimentare etc. Aceste lucruri discrete nu atrag atenția, dar adaugă confort vieții. Aceeași poveste este cu diverse aplicații mobile și desktop: pentru capturi de ecran lungi, pentru reducerea dimensiunii unei imagini, pentru calcularea finanțelor personale, dicționare, traducători, convertoare etc. Ai una? VPS - care este ieftin, mereu la îndemână și aduce o mulțime de beneficii? Nu, nu pe cel pe care îl ai în compania ta, ci pe cel „de buzunar”. Ne-am gândit că fără un VPS mic în 2019 a fost oarecum trist, la fel ca fără stiloul obișnuit la o prelegere. De ce să fii trist? Este vară. Cum e vara? Vară pentru un specialist IT: stând acasă, lucrând la proiectele tale preferate fără niciun regret. În general, ne-am gândit și am făcut-o.

Creier + VPS pentru 30 de ruble =?
A sosit comunismul, tovarăși.

El este așa - VPS-ul nostru pentru treizeci

Am citit o mulțime de articole de la concurenți și utilizatori care au scris acum 3-4 ani despre de ce nu este nevoie de un VPS ieftin. Ei bine, așa este, atunci VPS „pentru un ban” era marketing pur și nu putea oferi oportunități normale de lucru. Dar vremurile se schimbă, costul resurselor virtuale devine din ce în ce mai mic, iar pentru 30 de ruble pe lună suntem gata să oferim acest lucru:

  • Procesor: Intel Xeon 2 GHz (1 nucleu)
  • Sistem Linux (Debian, Ubuntu, CentOS din care să alegeți)
  • 1 adresă IPv4 dedicată
  • 10 GB de stocare de date pe unități SSD rapide de clasă enterprise
  • RAM: 512 MB
  • Facturare pe secundă
  • Trafic nelimitat

Tariful este supus unor restricții tehnice suplimentare, detalii pe pagină oferta noastră cool - VPS pentru 30 de ruble. 

Pentru cine este potrivit acest server virtual? Da pentru aproape toată lumea: începători, entuziaști, dezvoltatori experimentați, fani de bricolaj și chiar unele companii.

Pentru ce este potrivit acest VPS?

Credem că cititorii lui Habr își vor găsi cu siguranță propriul mod de a folosi această configurație, dar am decis să colectăm propria noastră selecție de idei - ce se întâmplă dacă cineva are nevoie de ea, dar bărbații nu știu?

  • Plasați site-ul dvs. simplu, portofoliul, CV-ul cu cod etc. Desigur, site-ul dvs. web creat face o impresie pozitivă asupra angajatorului. Plasați-l pe VPS-ul dvs. și fiți responsabil pentru securitatea și stabilitatea site-ului dvs., și nu de către personalul furnizorilor obișnuiți de găzduire.
  • Folosiți VPS în scopuri educaționale: găzduiți proiectul dvs., studiați caracteristicile sistemului de operare server și server, experimentați cu DNS, reparați cu un mic site educațional.
  • Pentru telefonie. Uneori, un antreprenor individual, freelancer sau o companie foarte mică are nevoie disperată de telefonie IP, iar operatorii chiar ai acestei telefonie sunt foarte lacomi. Este simplu: ne luăm serverul, cumpărăm un număr de la un operator de telefonie IP, instalăm un PBX virtual și creăm numere interne (dacă este necesar). Economiile sunt colosale.
  • Utilizați serverul pentru a vă testa aplicațiile.
  • Utilizați serverul pentru experimente DIY, inclusiv controlul și colectarea datelor de la senzorii sistemului de casă inteligentă.
  • O modalitate neobișnuită de a-l folosi este să plasați pe server un asistent de tranzacționare de schimb virtual, un robot de tranzacționare. Veți fi pe deplin responsabil pentru stabilitatea și securitatea serverului, ceea ce înseamnă că veți primi un instrument controlat pentru tranzacționarea pe bursele. Ei bine, în cazul în care cineva este interesat sau plănuiește :)

Există aplicații pentru astfel de VPS în sfera corporativă. Pe lângă serviciul telefonic deja menționat, puteți implementa mai multe lucruri interesante. De exemplu:

  • Plasați baze de date mici și informații care vor fi accesibile angajaților care călătoresc la distanță, de exemplu, folosind ftp. Acest lucru vă va permite să faceți schimb foarte rapid de analize proaspete, configurații actualizate pentru oamenii de vânzări, prezentări etc.
  • Oferiți acces temporar utilizatorilor sau clienților pentru a demonstra software-ul sau media.

Test drive VPS pentru 30 de ruble - gata pentru tine

30 de ruble sunt atât de puține încât nici măcar nu vrei să scoți un card pentru a plăti și a testa. Uneori suntem și noi atât de leneși, dar de data aceasta am făcut totul pentru tine. Înainte de a lansa serverele în luptă, am efectuat un test pentru a verifica toate detaliile și a arăta de ce sunt capabile serverele la acest tarif. Pentru a o face mai interesantă, am adăugat extrem și am verificat cum s-ar comporta această configurație dacă densitatea și sarcina ar depăși valorile pe care le-am stabilit. 

Gazda se afla sub sarcina unui număr de mașini virtuale care executau diverse sarcini pe procesor și foloseau activ subsistemul de disc. Scopul este de a simula o densitate mare de plasare și o sarcină comparabilă sau mai mare decât cea de luptă.

Pe lângă încărcarea constantă, am instalat 3 mașini virtuale care au colectat valori sintetice folosind sysbench, ale căror rezultate medii au fost date mai jos și 50 de mașini virtuale care au creat încărcare suplimentară. Toate mașinile virtuale de testare au avut aceeași configurație (1 nucleu, RAM 512 GB, SSD 10 GB), imaginea standard debian 9.6 a fost selectată ca sistem de operare, care este oferită utilizatorilor pe RUVDS.

Sarcina a fost simulată ca natură și amploare comparabilă cu cea a luptei:

  • Unele mașini virtuale au fost lansate cu încărcare redusă
  • Unele mașini au rulat un script de testare care simulează încărcarea procesorului (folosind utilitarul stres)
  • Pe partea rămasă a mașinilor virtuale, am rulat un script care a folosit dd pentru a copia datele de pe date pre-preparate pe disc cu o limită setată folosind pv (pot fi văzute exemple aici и aici).

De asemenea, după cum vă amintiți, aveam trei mașini care colectau valori sintetice.

Pe fiecare mașină, a fost executat ciclic un script la fiecare 15 minute, care rulează teste standard sysbench pentru procesor, memorie și disc.

Script 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

Rezultatele sunt prezentate pentru comoditate în format sysbench, dar valorile medii pentru întreaga perioadă de testare au fost luate de la toate mașinile, rezultatul poate fi văzut aici:

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

Rezultatele sunt orientative, dar totuși nu trebuie luate ca QoS. 

Mașini care creează încărcătură suplimentară

Software:

  • apt-get update
  • apt-get upgrade
  • apt-get install python-pip
  • pip install mysql-connector-python-rf

Instalat MariaDB, Cum să aici:

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

Baza de testare luată prin urmare:

Baza de date este implementată conform specificațiilor aici:

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

Baza de testare mica:

Tabel 

RowsCount 

Dimensiunea datelor (MB)

Dimensiunea indexului (KB)

departamente 

9

0.02

16.00

dept_emp 

331143 

11.52

5648.00

dept_manager 

24 

0.02

16.00

de angajați 

299379 

14.52

0.00

salarii 

2838426 

95.63

0.00 

titluri 

442783 

19.56

0.00

Un serviciu de testare primitiv este scris pe genunchi în Python; efectuează patru operații:

  1. getState: returnează starea
  2. getEmployee: returnează angajații (+salarii, +titluri) din baza de date
  3. patchEmployee: modifică câmpurile angajaților
  4. insertSalary: introduce un salariu

Sursa serviciului (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')

Atenție! În niciun caz acest serviciu nu trebuie luat ca exemplu sau ghid!

Testele sunt efectuate folosind vechiul JMeter. Au fost lansate o serie de teste cu o durată de la 15 minute până la 2 ore, fără întreruperi, procentul de solicitări a variat, iar debitul a variat de la 300 la 600 de solicitări pe minut. Număr de fire de la 50 la 500.

Datorită faptului că baza de date este foarte mică, comanda:

mysql -e "SHOW ENGINE INNODB STATUS"

Arată că:

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

Mai jos sunt timpii medii de răspuns pentru solicitări:

Etichetă

In medie

Median

Linie 90%.

Linie 95%.

Linie 99%.

Min

max

getEmployee

37.64

12.57

62.28

128.5

497.57

5

4151.78

getState

17

7.57

30.14

58.71

193

3

2814.71

patchAngajat

161.42

83.29

308

492.57

1845.14

5

6639.4

puneSalariu

167.21

86.93

315.34

501.07

1927.12

7

6722.44

Poate fi dificil pentru tine să judeci din aceste rezultate sintetice cât de potrivit este acest VPS pentru sarcinile tale specifice și, în general, metodele enumerate sunt limitate la acele cazuri cu care a trebuit să ne confruntăm într-o formă sau alta. Deci lista noastră este clar nu exhaustiv. Vă invităm să trageți propriile concluzii și să testați serverul pentru 30 de ruble pe aplicațiile și sarcinile dvs. reale și să vă sugerăm opțiunile pentru această configurație în comentarii.

Sursa: www.habr.com

Adauga un comentariu