Уведомления

Группа в Telegram: @pythonsu

#1 Янв. 30, 2017 18:30:21

rebus
Зарегистрирован: 2017-01-30
Сообщения: 2
Репутация: +  0  -
Профиль   Отправить e-mail  

ThreadingMixIn, SimpleXMLRPCServer, мертвые потоки


Много букв, мало кода)
Понадобилось срочно написать xml rpc server, выбор пал на питон из-за казавшейся простоты, а не писать все как обычно на с++)
За пару дней код был готов и показывал отличные результаты на тестовых серверах, выпустил на продакшн и как это часто бывает, пошли проблемы.

Суть проблемы. При выполнении данного ниже кода, каждый клиент, при подключении, работает в своем потоке, в “домашних/тестовых” условиях все работает отлично, но на просторах интернета на рабочем сервере, где кто-то сканирует порты, обрывается связь у клиента в самый неподходящий момент или по какой-либо другой не известной и не воспроизводимой причине, рожденный под это соединение поток не хочет завершаться и висит. Сколько не старался но не смог воспроизвести что бы подобное повторилось на тестовых серверах. Запустили на втором рабочем сервере - ситуация повторилась. Сами понимаете на рабочем сервере многое себе не позволишь, но нужно хотя бы направление в котором копать или еще лучше если это баян, решение которого знают все кроме меня)

Ниже сильно упрощенный псевдо код, дающий представление, все лишнее - перепроверено и убрано как не влияющее на ситуацию.
Выяснилось наверняка только одно, запрос порождающий повисший поток до вызова функции getMyData не доходит. Более того, не доходит до выполнения _dispatch(self, method, params).
Но выполняются shutdown_request, close_request. Так же было замечено что подобный запрос идет часто в одну и туже секунду с другим запросом, который обрабатывается в дальнейшем нормально.

python 3.5
Рабочие сервера работают на Ubuntu 16
Кол-во запросов - 20000-25000 в сутки на сервер (обрабатывается все в отдельных процессах=кол проц сервера)
Планируется десятикратное увеличение при полном запуске
За сутки таких мертворожденных потоков доходит до 20.

А теперь вопрос! В каком месте может поток уходить в бесконечный цикл и висит? И как это лечить, если такое место будет не найдено?)


 class RequestHandler(SimpleXMLRPCRequestHandler):
     rpc_paths = ('/RPC2',)
class ThreadedRPCServer(ThreadingMixIn, SimpleXMLRPCServer):
    pass
def getMyData(myData):
    print("In getMyData")
    #обрабатываю данные
    return resData
if __name__ == "__main__":
    server = ThreadedRPCServer(("", 9111), requestHandler=RequestHandler, allow_none=True)
    server.logRequests = True
    server.request_queue_size = 40
    server.register_introspection_functions()
    server.register_function(getMyData, 'getMyData')
    try:
        server.serve_forever()
    except KeyboardInterrupt:
        print("\nKeyboard interrupt received, exiting.")
        exit(0)

Офлайн

#2 Янв. 31, 2017 08:45:01

PooH
От:
Зарегистрирован: 2006-12-05
Сообщения: 1948
Репутация: +  72  -
Профиль   Отправить e-mail  

ThreadingMixIn, SimpleXMLRPCServer, мертвые потоки

А почему бы вам не спрятать свой сервер за реверсным прокси, например, за nginx. Решит массу проблем со сканированием портов, медленными или отвалившимися клиентами.

По вопросу - данных маловато. Похоже, что клиент цепляется, не посылает запроса и отваливается по таймауту. Прокси должен помочь. Ну и снимите трафик на порту tcpdump и посмотрите у себя на машине wireshark-ом. Увидите что за запросы были.



Вот здесь один из первых отарков съел лаборанта. Это был такой умный отарк, что понимал даже теорию относительности. Он разговаривал с лаборантом, а потом бросился на него и загрыз…

Отредактировано PooH (Янв. 31, 2017 08:45:51)

Офлайн

#3 Янв. 31, 2017 17:11:36

rebus
Зарегистрирован: 2017-01-30
Сообщения: 2
Репутация: +  0  -
Профиль   Отправить e-mail  

ThreadingMixIn, SimpleXMLRPCServer, мертвые потоки

Спасибо за отклик. Уже думал насчет прокси, на самом деле идея очень хорошая и по правильному нужно делать именно так. Но, к сожалению, я так и не нашел способа получит реальный ip клиента в своей программе. Мне ip клиента нужен обязательно.
С nginx он передается в заголовке полем X-Real-IP, но вот как до него добраться, например тут:

 class ThreadedRPCServer(socketserver.ThreadingTCPServer, SimpleXMLRPCServer):
    def finish_request(self, request, client_address):
        print(client_address)
        self.client_address = client_address
        SimpleXMLRPCServer.finish_request(self, request, client_address)

Здесь только ip сервера с nginx (raddr'127.0.0.1', 39992))
Не подскажите идею?

P.S. Покопался в источниках немного, нашел способ достать ip из X-Real-IP в заголовке.
Может кому интересно будет:

 class RequestHandler(SimpleXMLRPCRequestHandler):
    rpc_paths = ('/RPC2',)
    def __init__(self, req, addr, server):
        self.client_ip_str = self.headers.get('X-Real-IP',"")
        SimpleXMLRPCRequestHandler.__init__(self, req, addr, server)

Запущу ngnix, надеюсь проблема с мертвыми потоками отпадет, а решение проблемы оставлю “на потом”
Хотя есть жуткое подозрение что это баг в библиотеке.

Отредактировано rebus (Янв. 31, 2017 20:16:23)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version