pika URLParameters異常Name or service not known

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ò)程

  1. name or service not known是一個(gè)關(guān)于域名與dns解析方面的錯(cuò)誤, 一般是出現(xiàn)在域名對(duì)應(yīng)的ip地址找不到或無(wú)法連接到對(duì)應(yīng)錯(cuò)誤服務(wù)器.
  2. 先確定/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
  1. 查看/etc/resolv.conf, 均指向阿里云nameserver, 沒(méi)有問(wèn)題.
# /etc/resolv.conf
nameserver 100.100.2.136
nameserver 100.100.2.138
  1. 使用同樣代碼嘗試連接其他MQ服務(wù)器. 兩種方式均無(wú)異常, 證明代碼無(wú)問(wèn)題.
  2. 通過(guò)兩個(gè)服務(wù)器同時(shí)使用tcpdump抓包, 確定沒(méi)有從client連接到mq server服務(wù). 根本沒(méi)有建立連接.
  3. 印象中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])

        ...
  1. 從pika源碼中觀察, amqp在確認(rèn)協(xié)議開(kāi)頭為amqp://后, 會(huì)轉(zhuǎn)為httphttps. 此時(shí)可以完全做為http來(lái)處理url
  2. 按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: /
  1. 明顯passwordhostvhost解析錯(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è).

  1. 帳號(hào)密碼和host中盡量不包含特殊字符, 要使用以上安全字符.
  2. 如果條件允許, 使用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連接的方式中是否也存在同樣的情況?

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容