Форум сайта python.su
Много букв, мало кода)
Понадобилось срочно написать 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)
Офлайн
А почему бы вам не спрятать свой сервер за реверсным прокси, например, за nginx. Решит массу проблем со сканированием портов, медленными или отвалившимися клиентами.
По вопросу - данных маловато. Похоже, что клиент цепляется, не посылает запроса и отваливается по таймауту. Прокси должен помочь. Ну и снимите трафик на порту tcpdump и посмотрите у себя на машине wireshark-ом. Увидите что за запросы были.
Отредактировано PooH (Янв. 31, 2017 08:45:51)
Офлайн
Спасибо за отклик. Уже думал насчет прокси, на самом деле идея очень хорошая и по правильному нужно делать именно так. Но, к сожалению, я так и не нашел способа получит реальный 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)
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)
Отредактировано rebus (Янв. 31, 2017 20:16:23)
Офлайн