le criquet est bon, n'est-ce pas? criquet. Tous les tests de charge récents ont été réalisés avec des criquets. Il est vraiment facile d'utiliser python même pour des scénarios compliqués.
Cependant, récemment, le nombre d'applications toujours actives augmente et il semble qu'il existe de nombreuses situations dans lesquelles un simple modèle req / res ne peut pas être correctement appliqué.
J'ai donc essayé de charger la tâche Locust à l'aide de Websocket afin qu'elle puisse être confirmée à partir de l'écran Web.
Par défaut, l'unité est en ms, mais si c'est en ms dans la communication socket, 0 est normalement répété, donc l'unité est μs. Comme vous pouvez le voir dans le code, je viens de créer une prise dans Task, de communiquer et de notifier le résultat aux criquets, donc je n'ai pas du tout touché au criquet lui-même.
Étant donné que les criquets ont une conception simple et que la partie pour la construction d'un environnement distribué et la partie pour demander et agréger les résultats sont séparées, il est bon de pouvoir le faire facilement.
locustfile.py
# -*- coding:utf-8 -*-
from __future__ import absolute_import
from __future__ import unicode_literals
from __future__ import print_function
import json
import uuid
import time
import gevent
from websocket import create_connection
import six
from locust import HttpLocust, TaskSet, task
from locust.events import request_success
class ChatTaskSet(TaskSet):
def on_start(self):
self.user_id = six.text_type(uuid.uuid4())
ws = create_connection('ws://127.0.0.1:5000/chat')
self.ws = ws
def _receive():
while True:
res = ws.recv()
data = json.loads(res)
end_at = time.time()
response_time = int((end_at - data['start_at']) * 1000000)
request_success.fire(
request_type='WebSocket Recv',
name='test/ws/chat',
response_time=response_time,
response_length=len(res),
)
gevent.spawn(_receive)
@task
def sent(self):
start_at = time.time()
body = json.dumps({'message': 'hello, world', 'user_id': self.user_id, 'start_at': start_at})
self.ws.send(body)
request_success.fire(
request_type='WebSocket Sent',
name='test/ws/chat',
response_time=int((time.time() - start_at) * 1000000),
response_length=len(body),
)
class ChatLocust(HttpLocust):
task_set = ChatTaskSet
min_wait = 0
max_wait = 100
Le but est de notifier le résultat avec events.request_success.fire et de lancer un thread gevent pour la réception. Si vous définissez normalement la réception dans @task, la tâche s'arrêtera pendant ce temps et les autres tâches du même TaskSet s'arrêteront également.
À propos, l'exemple de serveur Echo & PubSub avec la charge est le script suivant.
server.py
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import unicode_literals
from __future__ import print_function
from collections import defaultdict
import json
from geventwebsocket.handler import WebSocketHandler
from gevent.pywsgi import WSGIServer
from flask import Flask, request
from werkzeug.exceptions import abort
app = Flask(__name__)
ctr = defaultdict(int)
@app.route('/echo')
def echo():
ws = request.environ['wsgi.websocket']
if not ws:
abort(400)
while True:
message = ws.receive()
if message is not None:
r = json.loads(message)
ctr[r['user_id']] += 1
ws.send(message)
@app.route('/report')
def report():
return '\n'.join(['{}:\t{}'.format(user_id, count) for user_id, count in ctr.items()])
socket_handlers = set()
@app.route('/chat')
def chat():
ws = request.environ['wsgi.websocket']
socket_handlers.add(ws)
while True:
message = ws.receive()
for socket_handler in socket_handlers:
try:
socket_handler.send(message)
except:
socket_handlers.remove(socket_handler)
if __name__ == '__main__':
http_server = WSGIServer(('', 5000), app, handler_class=WebSocketHandler)
http_server.serve_forever()
Le fichier est également téléchargé dans le référentiel suivant. https://gist.github.com/yamionp/9112dd6e54694d594306
Recommended Posts