• בלוג
  • זיהוי בעיות ביצועים עם Apache Bench

זיהוי בעיות ביצועים עם Apache Bench

01/07/2019

אפאצ'י בנצ' הוא כלי חינמי ופשוט שעוזר לבדוק איך האתר שלכם מתפקד תחת עומס. אני אוהב את Apache Bench כי הוא ממש פשוט לשימוש ועוזר למצוא בעיות ביצועים נפוצות בשרת. החיסרון המרכזי שלו הוא היעדר התמיכה ב Sessions ולכן הוא לא מאוד שימושי כשאתם רוצים לוודא שהשרת ישרוד בעומס של העולם האמיתי.

השימוש העיקרי ב ab הוא לבדוק שנתיב מסוים שאתם חושדים בו שעושה בעיות באמת עושה בעיות.

1. התחברות לנתיב ובדיקה שהכל עובד

יש לנו נתיב שאנחנו חושדים שעושה בעיות ורוצים לקבל יותר מידע. קודם כל נפעיל את ab עם הנתיב וכל הפרמטרים ונראה שאנחנו מצליחים להתחבר ולקבל תשובה נכונה מהשרת:

ab -v 4 http://localhost:3000/

הפלט קצת ארוך ואצלי ביישום נראה כך:

This is ApacheBench, Version 2.3 <$Revision: 1826891 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)...INFO: GET header == 
---
GET / HTTP/1.0
Host: localhost:3000
User-Agent: ApacheBench/2.3
Accept: */*


---
LOG: header received:
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: text/html; charset=utf-8
Content-Length: 1269
ETag: W/"4f5-Mre6pRuFJfReQtSirkxsmAGixI8"
Date: Sun, 30 Jun 2019 13:14:44 GMT
Connection: close

<!DOCTYPE html><html><head><title>Express</title><link rel="stylesheet" href="/stylesheets/style.css"></head><body><h1>Express</h1><p>Welcome to Express</p><pre><code>var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');

var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', indexRouter);
app.use('/users', usersRouter);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  next(createError(404));
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;
</code></pre></body></html>
LOG: Response code = 200
..done


Server Software:        
Server Hostname:        localhost
Server Port:            3000

Document Path:          /
Document Length:        1269 bytes

Concurrency Level:      1
Time taken for tests:   0.006 seconds
Complete requests:      1
Failed requests:        0
Total transferred:      1472 bytes
HTML transferred:       1269 bytes
Requests per second:    158.18 [#/sec] (mean)
Time per request:       6.322 [ms] (mean)
Time per request:       6.322 [ms] (mean, across all concurrent requests)
Transfer rate:          227.38 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.0      0       0
Processing:     6    6   0.0      6       6
Waiting:        6    6   0.0      6       6
Total:          6    6   0.0      6       6

אנחנו יכולים לראות את תשובת השרת התקינה וגם את הזמן שלקח עד שקיבלנו אותה.

2. יצירת עומס על הנתיב

עכשיו נוכל להגדיל את העומס כדי לראות מתי השרת נשבר. המתג n קובע כמה בקשות לשלוח והמתג c קובע כמה מהן לשלוח במקביל. סך הכל הפקודה הבאה תשלח מאה בקשות מחולקות לקבוצות של עשר בקשות במקביל:

ab -c 10 -n 100 http://localhost:3000/

והפלט:

This is ApacheBench, Version 2.3 <$Revision: 1826891 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient).....done


Server Software:        
Server Hostname:        localhost
Server Port:            3000

Document Path:          /
Document Length:        1269 bytes

Concurrency Level:      10
Time taken for tests:   0.358 seconds
Complete requests:      100
Failed requests:        0
Total transferred:      147200 bytes
HTML transferred:       126900 bytes
Requests per second:    279.24 [#/sec] (mean)
Time per request:       35.812 [ms] (mean)
Time per request:       3.581 [ms] (mean, across all concurrent requests)
Transfer rate:          401.40 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    0   0.3      0       3
Processing:     4   34   7.3     33      47
Waiting:        4   29   7.2     29      42
Total:          5   34   7.2     33      48

Percentage of the requests served within a certain time (ms)
  50%     33
  66%     38
  75%     40
  80%     40
  90%     43
  95%     46
  98%     48
  99%     48
 100%     48 (longest request)

בינתיים זה לא היה כל כך נורא - אנחנו רואים שכל הבקשות קיבלו תשובה, ש 50% מהבקשות קיבלו תשובה תוך 33 מילי שניות ו 100% מהבקשות קיבלו תשובה תוך פחות מ 50 מילי שניות.

אבל אם מעלים את העומס כבר אפשר לראות את הבעיה:

ab -c 100 -n 1000 http://localhost:3000/

והפלט הפעם:

This is ApacheBench, Version 2.3 <$Revision: 1826891 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests


Server Software:        
Server Hostname:        localhost
Server Port:            3000

Document Path:          /
Document Length:        1269 bytes

Concurrency Level:      100
Time taken for tests:   3.152 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      1472000 bytes
HTML transferred:       1269000 bytes
Requests per second:    317.31 [#/sec] (mean)
Time per request:       315.153 [ms] (mean)
Time per request:       3.152 [ms] (mean, across all concurrent requests)
Transfer rate:          456.13 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   1.0      1       4
Processing:    21  303  82.1    284     512
Waiting:       17  241  67.8    241     508
Total:         21  304  82.7    285     514

Percentage of the requests served within a certain time (ms)
  50%    285
  66%    323
  75%    338
  80%    342
  90%    506
  95%    507
  98%    508
  99%    508
 100%    514 (longest request)

אנחנו רואים שככל שיש יותר בקשות במקביל כך הזמן שלוקח לענות לכל בקשה עולה בצורה משמעותית.

כשעולים למאה בקשות במקביל הסיפור רק נהיה עוד יותר קשוח ואנחנו מקבלים:

$ ab -c 100 -n 1000 http://localhost:3000/
This is ApacheBench, Version 2.3 <$Revision: 1826891 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking localhost (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests


Server Software:        
Server Hostname:        localhost
Server Port:            3000

Document Path:          /
Document Length:        197 bytes

Concurrency Level:      100
Time taken for tests:   20.287 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      398000 bytes
HTML transferred:       197000 bytes
Requests per second:    49.29 [#/sec] (mean)
Time per request:       2028.735 [ms] (mean)
Time per request:       20.287 [ms] (mean, across all concurrent requests)
Transfer rate:          19.16 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0    1   0.8      0       4
Processing:    29 1934 309.9   2007    2833
Waiting:       24 1844 335.5   1942    2769
Total:         29 1935 309.3   2008    2834
WARNING: The median and mean for the initial connection time are not within a normal deviation
        These results are probably not that reliable.

Percentage of the requests served within a certain time (ms)
  50%   2008
  66%   2036
  75%   2059
  80%   2071
  90%   2132
  95%   2201
  98%   2335
  99%   2341
 100%   2834 (longest request)

במצבים כאלה נרצה להסתכל על קוד השרת ולראות איך לשפר את החוויה של יותר גולשים במקביל. אם אפשר נרצה להוסיף מנגנוני Caching או להעביר חלק מהעבודה בצד השרת לרקע או לתהליך אחר.