pika URLParameters異常Name or service not known
[TOC]
情況描述
使用python pika包連接mq服務(wù)器時(shí), 使用amqp協(xié)議用URLParameters連接方式時(shí)異常, 錯(cuò)誤為pika.exceptions.AMQPConnectionError: [Errno -2] Name or service not known, 但使用ConnectionParameters連接方式則無(wú)錯(cuò)誤.
amqp連接Url:
amqp://app:3W!@4WUWo#5Jae^5@192.168.1.100:5672/app
連接配置
連接方式: selectConnection
連接參數(shù): URLParameters("amqp://3W!@4WUWo#5Jae^5@192.168.1.100:5672/app")
服務(wù)器:
host = '192.168.1.100'
port = 5672
username = 'app'
password = '3W!@4WUWo#5Jae^5'
vhost = 'app'
queue = 'app.msg'
錯(cuò)誤詳情
connection OK
Traceback (most recent call last):
File "consumer_test.py", line 40, in <module>
consume.run()
File "/app/python/treasure_box/mq/consumer.py", line 56, in run
self.connect()
File "/app/python/treasure_box/mq/client.py", line 135, in connect
self.connection.ioloop.start()
File "/root/.virtualenvs/py3/lib/python3.6/site-packages/pika/adapters/select_connection.py", line 209, in start
self._poller.start()
File "/root/.virtualenvs/py3/lib/python3.6/site-packages/pika/adapters/select_connection.py", line 496, in start
self.process_timeouts()
File "/root/.virtualenvs/py3/lib/python3.6/site-packages/pika/adapters/select_connection.py", line 366, in process_timeouts
timer['callback']()
File "/root/.virtualenvs/py3/lib/python3.6/site-packages/pika/connection.py", line 1836, in _on_connect_timer
error)
File "/root/.virtualenvs/py3/lib/python3.6/site-packages/pika/callback.py", line 60, in wrapper
return function(*tuple(args), **kwargs)
File "/root/.virtualenvs/py3/lib/python3.6/site-packages/pika/callback.py", line 92, in wrapper
return function(*args, **kwargs)
File "/root/.virtualenvs/py3/lib/python3.6/site-packages/pika/callback.py", line 236, in process
callback(*args, **keywords)
File "/root/.virtualenvs/py3/lib/python3.6/site-packages/pika/connection.py", line 1768, in _on_connection_error
self.params.connection_attempts)
pika.exceptions.AMQPConnectionError: [Errno -2] Name or service not known
期望結(jié)果
使用amqp協(xié)議連接正常, 確定Name or service not known錯(cuò)誤原因.
找錯(cuò)過(guò)程
-
name or service not known是一個(gè)關(guān)于域名與dns解析方面的錯(cuò)誤, 一般是出現(xiàn)在域名對(duì)應(yīng)的ip地址找不到或無(wú)法連接到對(duì)應(yīng)錯(cuò)誤服務(wù)器. - 先確定
/etc/hosts文件, hosts文件除了localhost 127.0.0.1的對(duì)應(yīng)外沒(méi)有其他域名解析.
# /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
- 查看
/etc/resolv.conf, 均指向阿里云nameserver, 沒(méi)有問(wèn)題.
# /etc/resolv.conf
nameserver 100.100.2.136
nameserver 100.100.2.138
- 使用同樣代碼嘗試連接其他MQ服務(wù)器. 兩種方式均無(wú)異常, 證明代碼無(wú)問(wèn)題.
- 通過(guò)兩個(gè)服務(wù)器同時(shí)使用
tcpdump抓包, 確定沒(méi)有從client連接到mq server服務(wù). 根本沒(méi)有建立連接. - 印象中amqp url與http url解析方式相同. 查看pika模塊源代碼, 確認(rèn)amqp url解析方式.
# pika URLParameters
class URLParameters(Parameters):
__slots__ = ('_all_url_query_values',)
_SETTER_PREFIX = '_set_url_'
def __init__(self, url):
super(URLParameters, self).__init__()
self._all_url_query_values = None
if url[0:4].lower() == 'amqp':
url = 'http' + url[4:]
parts = urlparse.urlparse(url)
if parts.scheme == 'https':
self.ssl = True
elif parts.scheme == 'http':
self.ssl = False
elif parts.scheme:
raise ValueError('Unexpected URL scheme %r; supported scheme '
'values: amqp, amqps' % (parts.scheme,))
...
if parts.username is not None:
self.credentials = pika_credentials.PlainCredentials(url_unquote(parts.username),
url_unquote(parts.password))
# Get the Virtual Host
if len(parts.path) > 1:
self.virtual_host = url_unquote(parts.path.split('/')[1])
...
- 從pika源碼中觀察,
amqp在確認(rèn)協(xié)議開(kāi)頭為amqp://后, 會(huì)轉(zhuǎn)為http或https. 此時(shí)可以完全做為http來(lái)處理url - 按http url來(lái)解析
amqp://app:3W!@4WUWo#5Jae^5@192.168.1.100:5672/app==>http://app:3W!@4WUWo#5Jae^5@192.168.1.100:5672/app
- 預(yù)期結(jié)果
-
username:app -
password:3W!@4WUWo#5Jae^5 -
host:192.168.1.100 -
port:5672 -
vhost:app
-
- 解析結(jié)果
-
username:app -
password:3W! -
host:4wuwo -
port:5672 -
vhost:/
-
- 明顯
password與host及vhost解析錯(cuò)誤, 已找到問(wèn)題, 現(xiàn)在就只差解決了.
問(wèn)題癥結(jié)
url在解析時(shí)使用
username:password@host:port/path?key1=value1&key2=value2#...
- @前后分別為auth和netloc
- 第一個(gè)/前是netloc與path
- 在url中, 有些字符是做標(biāo)識(shí)與特殊作用的.
解決方案
URL中絕對(duì)安全的字符:
ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
0123456789
_.-
其他字符如何在傳輸過(guò)程中會(huì)轉(zhuǎn)義為%HEX格式, 此問(wèn)題解決方案有兩個(gè).
- 帳號(hào)密碼和host中盡量不包含特殊字符, 要使用以上安全字符.
- 如果條件允許, 使用
ConnectionParameters方式連接, 該方式?jīng)]有特殊字符限制.
總結(jié)
所謂, Bug再小也是蟲(chóng). 沒(méi)想到問(wèn)題是出在url上. 此次問(wèn)題雖然很低級(jí), 但也浪費(fèi)了不少的時(shí)間, 但問(wèn)題排查過(guò)程給了自己一個(gè)思路及處理Name or service not known的經(jīng)驗(yàn), 也對(duì)URL解析有了各具象的認(rèn)識(shí).
依照本次經(jīng)驗(yàn)舉一反三, 在redis, mongo等url連接的方式中是否也存在同樣的情況?