Estas tiel agrable kiam ĉiuj necesaj aĵoj estas ĉe mano: bona skribilo kaj notbloko, akrigita krajono, komforta muso, kelkaj kromaj dratoj, ktp. Ĉi tiuj nevideblaj aferoj ne altiras atenton, sed aldonas komforton al la vivo. La sama rakonto estas kun diversaj poŝtelefonaj kaj labortablaj aplikaĵoj: por longaj ekrankopioj, por redukti la grandecon de bildo, por kalkuli personajn financojn, vortarojn, tradukilojn, konvertilojn ktp. Ĉu vi havas unu? VPS - kiu estas malmultekosta, ĉiam ĉe la mano kaj alportas multajn avantaĝojn? Ne, ne tiun, kiun vi havas en via kompanio, sed vian propran, "poŝon". Ni pensis, ke sen malgranda VPS en 2019 ĝi estis iel malĝoja, same kiel sen la kutima fontoplumo ĉe prelego. Kial esti malĝoja? Estas somero. Kiel fartas somero? Somero por IT-specialisto: sidante hejme, laborante pri viaj plej ŝatataj projektoj sen ajna bedaŭro. Ĝenerale, ni pensis kaj faris ĝin.
Komunismo alvenis, kamaradoj.
Li estas tia - nia VPS por tridek
Ni legis multajn artikolojn de konkurantoj kaj uzantoj, kiuj skribis antaŭ 3-4 jaroj pri kial malmultekosta VPS ne necesas. Nu, ĝuste, tiam VPS "por penco" estis pura merkatado kaj ne povis oferti normalajn laborŝancojn. Sed la tempoj ŝanĝas, la kosto de virtualaj rimedoj pli kaj pli malaltiĝas, kaj por 30 rubloj monate ni pretas proponi ĉi tion:
Procesoro: Intel Xeon 2 GHz (1 kerno)
Linuksa sistemo (Debian, Ubuntu, CentOS por elekti)
1 dediĉita IPv4-adreso
10 GB da datumstokado sur rapidaj entreprenaj SSD-diskoj
RAM: 512 MB
Sekundo fakturado
Senlima trafiko
La tarifo estas submetita al pliaj teknikaj limigoj, detaloj pri paĝo nia bonega oferto - VPS por 30 rubloj.
Por kiu taŭgas ĉi tiu virtuala servilo? Jes al preskaŭ ĉiuj: komencantoj, entuziasmuloj, spertaj programistoj, DIY-fanoj kaj eĉ iuj kompanioj.
Por kio taŭgas ĉi tiu VPS?
Ni pensas, ke la legantoj de Habr certe trovos sian propran manieron uzi ĉi tiun agordon, sed ni decidis kolekti nian propran elekton de ideoj - kio se iu bezonas ĝin, sed la viroj ne scias?
Metu vian simplan retejon, biletujon, vivresumon kun kodo ktp. Kompreneble, via propra desegnita retejo faras pozitivan impreson sur la dunganto. Metu ĝin sur vian VPS kaj estu respondeca pri la sekureco kaj stabileco de la retejo mem, kaj ne de la personaro de regulaj gastigaj provizantoj.
Uzu VPS por edukaj celoj: gastigu vian projekton, studu la funkciojn de la servilo kaj servila operaciumo, eksperimentu kun DNS, ĝuu malgrandan edukan retejon.
Por telefonio. Kelkfoje individua entreprenisto, liberlaboranto aŭ tre malgranda kompanio ege bezonas IP-telefonion, kaj la telefonistoj de ĉi tiu sama telefonio estas tre avidaj. Estas simple: ni prenas nian servilon, aĉetas numeron de IP-telefona telefonisto, starigas virtualan PBX kaj kreas internajn numerojn (se necese). La ŝparaĵoj estas kolosaj.
Uzu la servilon por testi viajn aplikojn.
Uzu la servilon por DIY-eksperimentoj, inkluzive de kontrolado kaj kolektado de datumoj de inteligentaj hejmaj sistemaj sensiloj.
Nekutima maniero uzi ĝin estas meti virtualan interŝanĝan asistanton, komercan roboton, sur la servilon. Vi estos plene respondeca pri la stabileco kaj sekureco de la servilo, kio signifas, ke vi ricevos kontrolitan instrumenton por komerci sur la borsmerkatoj. Nu, se iu interesiĝas aŭ planas :)
Estas aplikoj por tia VPS en la kompania sfero. Krom la jam menciita telefonservo, vi povas efektivigi plurajn interesajn aferojn. Ekzemple:
Metu malgrandajn datumbazojn kaj informojn, kiuj estos alireblaj por vojaĝantaj dungitoj malproksime, ekzemple, uzante ftp. Ĉi tio permesos al vi tre rapide interŝanĝi freŝajn analizojn, ĝisdatigitajn agordojn por vendantoj, prezentojn ktp.
Donu provizoran aliron al uzantoj aŭ klientoj por montri programaron aŭ amaskomunikilaron.
VPS-testveturo por 30 rubloj - farita por vi
30 rubloj estas tiom malmulte, ke vi eĉ ne volas eltiri karton por pagi kaj testi. Ankaŭ ni foje estas tiel maldiligentaj, sed ĉi-foje ni faris ĉion por vi. Antaŭ lanĉi la servilojn en batalon, ni faris provon por kontroli ĉiujn detalojn kaj montri, kion kapablas la serviloj ĉe ĉi tiu tarifo. Por fari ĝin pli interesa, ni aldonis ekstreman kaj kontrolis kiel ĉi tiu agordo kondutus se la denseco kaj ŝarĝo superus la valorojn, kiujn ni starigis.
La gastiganto estis sub la ŝarĝo de kelkaj virtualaj maŝinoj, kiuj plenumis diversajn taskojn sur la procesoro kaj aktive uzis la disksubsistemon. La celo estas simuli altan densecon de lokigo kaj ŝarĝon komparebla al aŭ pli granda ol batala unu.
Krom la konstanta ŝarĝo, ni instalis 3 virtualajn maŝinojn, kiuj kolektis sintezajn metrikojn per sysbench, kies averaĝaj rezultoj estis donitaj sube, kaj 50 virtualajn maŝinojn, kiuj kreis plian ŝarĝon. Ĉiuj testaj virtualaj maŝinoj havis la saman agordon (1 kerno, RAM 512 GB, SSD 10 GB), la norma debian 9.6 bildo estis elektita kiel la operaciumo, kiu estas ofertita al uzantoj sur RUVDS.
La ŝarĝo estis simulita en naturo kaj grandeco komparebla al batalo:
Kelkaj virtualaj maŝinoj estis lanĉitaj kun malalta ŝarĝo
Kelkaj maŝinoj prizorgis testan skripton simulantan la ŝarĝon sur la procesoro (uzante la ilon premo)
Sur la restanta parto de la virtualaj maŝinoj, ni rulis skripton kiu uzis dd por kopii datumojn de antaŭpreparitaj datumoj al disko kun limo fiksita uzante pv (ekzemploj videblas tie и tie).
Ankaŭ, kiel vi memoras, ni havis tri maŝinojn, kiuj kolektis sintezajn metrikojn.
Sur ĉiu maŝino, skripto estis ekzekutita cikle ĉiujn 15 minutojn, kiu funkcias normajn sysbench-testojn por la procesoro, memoro kaj disko.
Skripto 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
La rezultoj estas prezentitaj por oportuno en sysbench-formato, sed la averaĝaj valoroj por la tuta testa periodo estis prenitaj de ĉiuj maŝinoj, la rezulto povas esti vidita ĉi tie:
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
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
La rezultoj estas indikaj, sed ankoraŭ ne devus esti prenitaj kiel QoS.
mysql -t < employees.sql
mysql -t < test_employees_sha.sql
Malgranda testa bazo:
tablo
RowsCount
Grandeco de datumoj (MB)
Indeksa grandeco (KB)
fakoj
9
0.02
16.00
dept_emp
331143
11.52
5648.00
dept_manaĝero
24
0.02
16.00
oficistoj
299379
14.52
0.00
salajroj
2838426
95.63
0.00
titoloj
442783
19.56
0.00
Primitiva testservo estas skribita sur la genuo en Python; ĝi elfaras kvar operaciojn:
getState: resendas la statuson
getEmployee: resendas dungitojn (+salajrojn, +titolojn) el la datumbazo
patchEmployee: ŝanĝas dungitajn kampojn
insertSalary: enmetas salajron
Servofonto (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')
Singardemo Neniam oni devas preni ĉi tiun servon kiel ekzemplon aŭ gvidilon!
Testoj estas faritaj uzante bonan malnovan JMeter. Serio de testoj daŭrantaj de 15 minutoj ĝis 2 horoj estis lanĉitaj, sen interrompoj, la procento de petoj variis, kaj trairo variis de 300 ĝis 600 petoj je minuto. Nombro da fadenoj de 50 ĝis 500.
Pro la fakto, ke la datumbazo estas tre malgranda, la komando:
mysql -e "SHOW ENGINE INNODB STATUS"
Montras ke:
Buffer pool hit rate 923 / 1000, young-making rate 29 / 1000 not 32 / 1000
Malsupre estas la mezaj respondtempoj por petoj:
Etikedo
Averaĝa
Meza
90% Linio
95% Linio
99% Linio
min
maks
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
flikiloDungito
161.42
83.29
308
492.57
1845.14
5
6639.4
meti Salajron
167.21
86.93
315.34
501.07
1927.12
7
6722.44
Povas esti malfacile por vi juĝi laŭ ĉi tiuj sintezaj rezultoj, kiom taŭgas ĉi tiu VPS por viaj specifaj taskoj kaj, ĝenerale, la listigitaj metodoj estas limigitaj al tiuj kazoj, kiujn ni devis trakti en unu aŭ alia formo.Do nia listo estas klare ne ĝisfunda. Ni invitas vin eltiri viajn proprajn konkludojn kaj testi la servilon por 30 rubloj pri viaj realaj aplikoj kaj taskoj kaj sugesti viajn eblojn por ĉi tiu agordo en la komentoj.