Ошибка ETIMEDOUT в node.js при обработке нескольких запросов

#javascript #node.js #reactjs #autoscaling

#javascript #node.js #reactjs #автоматическое масштабирование

Вопрос:

У меня есть сервер, написанный на node, который использует mysql в качестве своей базы данных, а интерфейс написан на react. Мое приложение размещено на выделенном сервере с процессором с 4 ядрами. Интерфейс должен загружать коэффициенты крикета, для которых я использую сторонний API. Приложение react отправляет запрос на мой сервер узла в соответствии с идентификатором соответствия, а затем сервер отправляет запрос стороннему API и получает коэффициенты, а затем передает их интерфейсу. Код выглядит следующим образом:

 router.get('/getSession/:matchId',(req,res)=>{
    
    axios.get('http://178.62.105.201/api/v1/listMarketBookSession?match_id=' req.params.matchId)
            .then(response => {
               
                return res.status(200).json({
                    success:true,
                    data:response.data
                })
            })
            .catch(error=>{
                console.log(error);
                return res.status(200).json({
                    success:false,
                    data:[]
                })
            });
})
 

Запрос отправляется каждые 500 мс. Приложение работает нормально, когда пользователей меньше. Когда число пользователей увеличилось до 400, он некоторое время отправляет ошибку 502, а затем снова начинает получать ответ. Это происходит в цикле.

 GET example.com/oddsApi/getSession/30189407 502
(anonymous) @ 2.e2450141.chunk.js:2
e.exports @ 2.e2450141.chunk.js:2
e.exports @ 2.e2450141.chunk.js:2
Promise.then (async)
s.request @ 2.e2450141.chunk.js:2
r.forEach.s.<computed> @ 2.e2450141.chunk.js:2
(anonymous) @ 2.e2450141.chunk.js:2
value @ main.7f6055f1.chunk.js:1
setTimeout (async)
(anonymous) @ main.7f6055f1.chunk.js:1
Promise.catch (async)
value @ main.7f6055f1.chunk.js:1
setTimeout (async)
(anonymous) @ main.7f6055f1.chunk.js:1
Promise.catch (async)
value @ main.7f6055f1.chunk.js:1
main.7f6055f1.chunk.js:1 TypeError: Cannot read property 'data' of undefined
    at main.7f6055f1.chunk.js:1
 

Когда я зарегистрировал эту ошибку на сервере, он печатает:

  { Error: connect ETIMEDOUT 178.62.105.201:80
0|app  |     at TCPConnectWrap.afterConnect [as oncomplete] (net.js:1107:14)
0|app  |   errno: 'ETIMEDOUT',
0|app  |   code: 'ETIMEDOUT',
0|app  |   syscall: 'connect',
0|app  |   address: '178.62.105.201',
0|app  |   port: 80,
0|app  |   config:
0|app  |    { url:
0|app  |       'http://178.62.105.201/api/v1/listMarketBookSession?match_id=30189407',
0|app  |      method: 'get',
0|app  |      headers:
0|app  |       { Accept: 'application/json, text/plain, */*',
0|app  |         'User-Agent': 'axios/0.20.0' },
0|app  |      transformRequest: [ [Function: transformRequest] ],
0|app  |      transformResponse: [ [Function: transformResponse] ],
0|app  |      timeout: 0,
0|app  |      adapter: [Function: httpAdapter],
0|app  |      xsrfCookieName: 'XSRF-TOKEN',
0|app  |      xsrfHeaderName: 'X-XSRF-TOKEN',
0|app  |      maxContentLength: -1,
0|app  |      maxBodyLength: -1,
0|app  |      validateStatus: [Function: validateStatus],
0|app  |      data: undefined },
0|app  |   request:
0|app  |    Writable {
0|app  |      _writableState:
0|app  |       WritableState {
0|app  |         objectMode: false,
0|app  |         highWaterMark: 16384,
0|app  |         finalCalled: false,
0|app  |         needDrain: false,
0|app  |         ending: false,
0|app  |         ended: false,
0|app  |         finished: false,
0|app  |         destroyed: false,
0|app  |         decodeStrings: true,
0|app  |         defaultEncoding: 'utf8',
0|app  |         length: 0,
0|app  |         writing: false,
0|app  |         corked: 0,
0|app  |         sync: true,
0|app  |         bufferProcessing: false,
0|app  |         onwrite: [Function: bound onwrite],
0|app  |         writecb: null,
0|app  |         writelen: 0,
0|app  |         bufferedRequest: null,
0|app  |         lastBufferedRequest: null,
0|app  |         pendingcb: 0,
0|app  |         prefinished: false,
0|app  |         errorEmitted: false,
0|app  |         emitClose: true,
0|app  |         autoDestroy: false,
0|app  |         bufferedRequestCount: 0,
0|app  |         corkedRequestsFree: [Object] },
0|app  |      writable: true,
0|app  |      _events:
0|app  |       [Object: null prototype] {
0|app  |         response: [Function: handleResponse],
0|app  |         error: [Function: handleRequestError] },
0|app  |      _eventsCount: 2,
0|app  |      _maxListeners: undefined,
0|app  |      _options:
0|app  |       { maxRedirects: 21,
0|app  |         maxBodyLength: 10485760,
0|app  |         protocol: 'http:',
0|app  |         path: '/api/v1/listMarketBookSession?match_id=30189407',
0|app  |         method: 'GET',
0|app  |         headers: [Object],
0|app  |         agent: undefined,
0|app  |         agents: [Object],
0|app  |         auth: undefined,
0|app  |         hostname: '178.62.105.201',
0|app  |         port: null,
0|app  |         nativeProtocols: [Object],
0|app  |         pathname: '/api/v1/listMarketBookSession',
0|app  |         search: '?match_id=30189407' },
0|app  |      _ended: true,
0|app  |      _ending: true,
0|app  |      _redirectCount: 0,
0|app  |      _redirects: [],
0|app  |      _requestBodyLength: 0,
0|app  |      _requestBodyBuffers: [],
0|app  |      _onNativeResponse: [Function],
0|app  |      _currentRequest:
0|app  |       ClientRequest {
0|app  |         _events: [Object],
0|app  |         _eventsCount: 7,
0|app  |         _maxListeners: undefined,
0|app  |         output: [],
0|app  |         outputEncodings: [],
0|app  |         outputCallbacks: [],
0|app  |         outputSize: 0,
0|app  |         writable: true,
0|app  |         _last: true,
0|app  |         chunkedEncoding: false,
0|app  |         shouldKeepAlive: false,
0|app  |         useChunkedEncodingByDefault: false,
0|app  |         sendDate: false,
0|app  |         _removedConnection: false,
0|app  |         _removedContLen: false,
0|app  |         _removedTE: false,
0|app  |         _contentLength: 0,
0|app  |         _hasBody: true,
0|app  |         _trailer: '',
0|app  |         finished: true,
0|app  |         _headerSent: true,
0|app  |         socket: [Socket],
0|app  |         connection: [Socket],
0|app  |         _header:
0|app  |          'GET /api/v1/listMarketBookSession?match_id=30189407 HTTP/1.1rnAccept: application/json, text/plain, */*rnUser-Agent: axios/0.20.0rnHost: 178.62.105.201rnConnection: closernrn',
0|app  |         _onPendingData: [Function: noopPendingOutput],
0|app  |         agent: [Agent],
0|app  |         socketPath: undefined,
0|app  |         timeout: undefined,
0|app  |         method: 'GET',
0|app  |         insecureHTTPParser: undefined,
0|app  |         path: '/api/v1/listMarketBookSession?match_id=30189407',
0|app  |         _ended: false,
0|app  |         res: null,
0|app  |         aborted: undefined,
0|app  |         timeoutCb: null,
0|app  |         upgradeOrConnect: false,
0|app  |         parser: null,
0|app  |         maxHeadersCount: null,
0|app  |         _redirectable: [Circular],
0|app  |         [Symbol(isCorked)]: false,
0|app  |         [Symbol(outHeadersKey)]: [Object] },
0|app  |      _currentUrl:
0|app  |       'http://178.62.105.201/api/v1/listMarketBookSession?match_id=30189407' },
0|app  |   response: undefined,
0|app  |   isAxiosError: true,
0|app  |   toJSON: [Function: toJSON] }
 

Код для вызова коэффициентов:-

 getOdds() {

        axios.get('/getSession/'   this.props.eventId)
            .then(response => {

                if (response amp;amp; response.data.data.length amp;amp; response.data.data[0] !== "n") {

                    response.data.data.sort((a,b)=>a.SelectionId-b.SelectionId)

                    this.setState({ sessions: response.data.data });
                    if (this.flag)
                        this.intervalID = setTimeout(this.getOdds.bind(this), 300);
                }
                else if (!response.data.data.length) {
                    this.setState({ sessions: null });
                }
            })
            .catch(error => {
                if (this.flag)
                    this.intervalID = setTimeout(this.getOdds.bind(this), 500);
                console.log(error);
            })
    }
 

который вызывается в componentDidMount

    componentDidMount() {
        this.getOdds();
    }
 

Я также попытался зарегистрировать продолжительность ответа. Продолжительность времени была переменной. Ниже приведены некоторые ответы

 Market.js:80 1752
Market.js:80 390
Market.js:80 310
Market.js:80 722
Market.js:80 16002
Market.js:80 15326
Market.js:80 330
Market.js:80 1758
Market.js:80 1144
Market.js:80 308
Market.js:80 709
Market.js:80 324
Market.js:80 351
Market.js:80 647
Market.js:80 375
Market.js:80 406
Market.js:80 701
Market.js:80 345
Market.js:80 1776
Market.js:80 1187
Market.js:80 414
Market.js:80 715
Market.js:80 20327
 

Как вы можете видеть, иногда для получения ответа требуется около 20 секунд, что вызывает у меня кошмар. Когда я связался со сторонним поставщиком API, они сказали мне, что их API может обрабатывать более 20000 пользователей. Я не могу устранить проблему. Возможно, я недостаточно хорошо подготовил свое приложение к масштабированию. Пожалуйста, помогите!

Комментарии:

1. Можете ли вы показать нам, как вы вызываете getOdds функцию?

2. Было бы полезно увидеть шкалу производительности или диаграмму вашего сервера, если он достиг 400 пользователей. Я не являюсь администратором сервера, но я предполагаю, что если до 400 пользователей запускают все правильно, а от 400 не более, это может быть проблемой с производительностью. Конечно, тогда это должно быть перехвачено где-нибудь в коде вашего запроса.

3. getOdds вызывается в componentDidMount

4. Проверьте, выполняется ли ваш sql-запрос count(*) . Если это так, это может быть виновником.

5. я не могу понять ваше решение @t348575