Простой golang http отдых службы под нагрузкой

Я подумал, что было бы полезно обсудить «неопределенное» поведение или, по крайней мере, неопределенное поведение «сбой», которое может возникнуть при удалении через базовый класс (/ struct) без виртуального деструктора или, точнее, vtable. В приведенном ниже коде перечислены несколько простых структур (то же самое было бы верно для классов).

#include <iostream>
using namespace std;

struct a
{
    ~a() {}

    unsigned long long i;
};

struct b : a
{
    ~b() {}

    unsigned long long j;
};

struct c : b
{
    ~c() {}

    virtual void m3() {}

    unsigned long long k;
};

struct d : c
{
    ~d() {}

    virtual void m4() {}

    unsigned long long l;
};

int main()
{
    cout << "sizeof(a): " << sizeof(a) << endl;
    cout << "sizeof(b): " << sizeof(b) << endl;
    cout << "sizeof(c): " << sizeof(c) << endl;
    cout << "sizeof(d): " << sizeof(d) << endl;

    // No issue.

    a* a1 = new a();
    cout << "a1: " << a1 << endl;
    delete a1;

    // No issue.

    b* b1 = new b();
    cout << "b1: " << b1 << endl;
    cout << "(a*) b1: " << (a*) b1 << endl;
    delete b1;

    // No issue.

    c* c1 = new c();
    cout << "c1: " << c1 << endl;
    cout << "(b*) c1: " << (b*) c1 << endl;
    cout << "(a*) c1: " << (a*) c1 << endl;
    delete c1;

    // No issue.

    d* d1 = new d();
    cout << "d1: " << d1 << endl;
    cout << "(c*) d1: " << (c*) d1 << endl;
    cout << "(b*) d1: " << (b*) d1 << endl;
    cout << "(a*) d1: " << (a*) d1 << endl;
    delete d1;

    // Doesn't crash, but may not produce the results you want.

    c1 = (c*) new d();
    delete c1;

    // Crashes due to passing an invalid address to the method which
    // frees the memory.

    d1 = new d();
    b1 = (b*) d1;
    cout << "d1: " << d1 << endl;
    cout << "b1: " << b1 << endl;
    delete b1;  

/*

    // This is similar to what's happening above in the "crash" case.

    char* buf = new char[32];
    cout << "buf: " << (void*) buf << endl;
    buf += 8;
    cout << "buf after adding 8: " << (void*) buf << endl;
    delete buf;
*/
}

Я не предлагаю, нужны ли вам виртуальные деструкторы или нет, хотя я думаю, что в целом это хорошая практика иметь их. Я просто указываю причину, по которой вы можете столкнуться с сбоем, если ваш базовый класс (/ struct) не имеет vtable и ваш производный класс (/ struct) делает, и вы удаляете объект через базовый класс (/ struct) указатель. В этом случае адрес, который вы передаете в бесплатную процедуру кучи, является недопустимым и, следовательно, причиной сбоя.

Если вы запустите указанный выше код, вы увидите, когда проблема возникнет. Когда этот указатель базового класса (/ struct) отличается от этого указателя производного класса (/ struct), вы столкнетесь с этой проблемой. В приведенном выше примере структуры a и b не имеют vtables. У структур c и d есть vtables. Таким образом, a или b указатель на экземпляр объекта c или d будут исправлены для учета vtable. Если вы передадите этот указатель a или b для его удаления, произойдет сбой из-за того, что адрес недействителен для бесплатной процедуры кучи.

Если вы планируете удалять производные экземпляры, имеющие vtables из указателей базового класса, вам нужно убедитесь, что базовый класс имеет таблицу vtable. Один из способов сделать это - добавить виртуальный деструктор, который вы, возможно, захотите правильно очистить ресурсы.

-1
задан double-beep 9 March 2019 в 08:15
поделиться

1 ответ

Вы случайно не используете OSX? Я понимаю, что ab не работает на OSX.

Другая вещь, которую вы можете попробовать, это использовать -k, чтобы использовать флаг поддержания активности, но это может быть не то, что вам нужно.

50000 также близко к максимальному количеству сокетов на интерфейсе, поэтому, возможно, ваши сокеты исчерпаны. Сокеты не могут быть повторно использованы напрямую, потому что они будут в состоянии TIME_WAIT в течение минуты или двух. Точное значение может варьироваться в зависимости от ОС и конфигурации.

Тем не менее, код выглядит тоже хорошо.

Следующий код работал хорошо для меня:

package main

import (
    "fmt"
    "github.com/gorilla/mux"
    "log"
    "net/http"
)


func Echo(w http.ResponseWriter, r *http.Request) {
    v := mux.Vars(r)

    fmt.Fprintf(w, "Echo %v", v["message"])
}


func main() {

    router := mux.NewRouter() //.StrictSlash(true)
    router.HandleFunc("/echo/{message}", Echo).Methods("GET")

    log.Println("Running server....")

    log.Fatal(http.ListenAndServe("localhost:8080", router))
}

И дает следующие результаты:

ab -c 500 -n 50000 localhost:8080/echo/foobar
This is ApacheBench, Version 2.3 <$Revision: 1807734 [111]gt;
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 5000 requests
Completed 10000 requests
Completed 15000 requests
Completed 20000 requests
Completed 25000 requests
Completed 30000 requests
Completed 35000 requests
Completed 40000 requests
Completed 45000 requests
Completed 50000 requests
Finished 50000 requests


Server Software:        
Server Hostname:        localhost
Server Port:            8080

Document Path:          /echo/foobar
Document Length:        12 bytes

Concurrency Level:      500
Time taken for tests:   2.471 seconds
Complete requests:      50000
Failed requests:        0
Total transferred:      6450000 bytes
HTML transferred:       600000 bytes
Requests per second:    20233.39 [#/sec] (mean)
Time per request:       24.712 [ms] (mean)
Time per request:       0.049 [ms] (mean, across all concurrent requests)
Transfer rate:          2548.93 [Kbytes/sec] received

Connection Times (ms)
              min  mean[+/-sd] median   max
Connect:        0   18 122.8      3    1034
Processing:     0    5  14.9      4     225
Waiting:        0    4  14.7      3     222
Total:          1   24 132.7      6    1245

Percentage of the requests served within a certain time (ms)
  50%      6
  66%      7
  75%      7
  80%      7
  90%     12
  95%     20
  98%     30
  99%   1040
 100%   1245 (longest request)

Это выполняется в Ubuntu 18.04.

0
ответ дан Patrick Vollebregt 9 March 2019 в 08:15
поделиться
Другие вопросы по тегам:

Похожие вопросы: