我正在使用 Django Channels,并试图确保通道层可以与 Redis 通信。但是,我使用的是 Windows 10 Home 版,这意味着我必须使用 Docker Toolbox 创建 Oracle VM Virtualbox,这样我才能在 Linux 环境中运行 Redis。我的 Django 项目在桌面上有自己的虚拟环境,而 Redis 在 Docker Toolbox 上运行。我完全遵循 django-channels 教程:https://channels.readthedocs.io/en/latest/tutorial/part_2.html
最初,我运行了$ docker run -p 6379:6379 -d redis:2.8
,它什么也没做,只是为我创建了 docker 镜像。但是,我运行了
$ docker run -p 6379:6379 redis:2.8
这启动了端口,这很好。不确定这是否与此有关,在 redis 服务器能够接受端口 6379 上的连接之前,我收到了以下响应:
[1] 08 Aug 21:12:19.210 # Server started, Redis version 2.8.23
[1] 08 Aug 21:12:19.211 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
[1] 08 Aug 21:12:19.211 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
[1] 08 Aug 21:12:19.212 * The server is now ready to accept connections on port 6379
下一部分我按照教程运行了以下内容:
$ python3 manage.py shell
>>> import channels.layers
>>> channel_layer = channels.layers.get_channel_layer()
>>> from asgiref.sync import async_to_sync
>>> async_to_sync(channel_layer.send)('test_channel', {'type': 'hello'})
我收到了这个错误信息:
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "C:\Users\wtran\venv\chattaboutit\lib\site-packages\asgiref\sync.py", line 110, in __call__
return call_result.result()
File "C:\Users\wtran\AppData\Local\Programs\Python\Python36-32\lib\concurrent\futures\_base.py", line 425, in result
return self.__get_result()
File "C:\Users\wtran\AppData\Local\Programs\Python\Python36-32\lib\concurrent\futures\_base.py", line 384, in __get_result
raise self._exception
File "C:\Users\wtran\venv\chattaboutit\lib\site-packages\asgiref\sync.py", line 142, in main_wrap
result = await self.awaitable(*args, **kwargs)
File "C:\Users\wtran\venv\chattaboutit\lib\site-packages\channels_redis\core.py", line 293, in send
async with self.connection(index) as connection:
File "C:\Users\wtran\venv\chattaboutit\lib\site-packages\channels_redis\core.py", line 820, in __aenter__
self.conn = await self.pool.pop()
File "C:\Users\wtran\venv\chattaboutit\lib\site-packages\channels_redis\core.py", line 70, in pop
conns.append(await aioredis.create_redis(**self.host, loop=loop))
File "C:\Users\wtran\venv\chattaboutit\lib\site-packages\aioredis\commands\__init__.py", line 178, in create_redis
loop=loop)
File "C:\Users\wtran\venv\chattaboutit\lib\site-packages\aioredis\connection.py", line 108, in create_connection
timeout, loop=loop)
File "C:\Users\wtran\AppData\Local\Programs\Python\Python36-32\lib\asyncio\tasks.py", line 339, in wait_for
return (yield from fut)
File "C:\Users\wtran\venv\chattaboutit\lib\site-packages\aioredis\stream.py", line 19, in open_connection
lambda: protocol, host, port, **kwds)
File "C:\Users\wtran\AppData\Local\Programs\Python\Python36-32\lib\asyncio\base_events.py", line 778, in create_connection
raise exceptions[0]
File "C:\Users\wtran\AppData\Local\Programs\Python\Python36-32\lib\asyncio\base_events.py", line 765, in create_connection
yield from self.sock_connect(sock, address)
File "C:\Users\wtran\AppData\Local\Programs\Python\Python36-32\lib\asyncio\selector_events.py", line 450, in sock_connect
return (yield from fut)
File "C:\Users\wtran\AppData\Local\Programs\Python\Python36-32\lib\asyncio\selector_events.py", line 480, in _sock_connect_cb
raise OSError(err, 'Connect call failed %s' % (address,))
ConnectionRefusedError: [Errno 10061] Connect call failed ('127.0.0.1', 6379)
只是想确认我在 settings.py 上确实设置了以下内容:
# mysite/settings.py
# Channels
ASGI_APPLICATION = 'mysite.routing.application'
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
"hosts": [('127.0.0.1', 6379)],
},
},
}
这是因为我的项目不在 Redis 所在的同一 VM 容器中吗?我认为这没关系,因为它是它自己的服务器,我正尝试与本地主机进行通信。
任何帮助将不胜感激...
答案1
这很可能是由于 Docker Toolbox 的工作方式造成的(有同样的问题)。
Docker Toolbox 使用 VirtualBox 作为虚拟化解决方案,它使用自己的 IP 创建自己的虚拟网络设备。
解决方案:
- 对属于docker容器的IP进行硬编码,如
Docker Quickstart Terminal
启动后所示。
## .
## ## ## ==
## ## ## ## ## ===
/"""""""""""""""""\___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ / ===- ~~~
\______ o __/
\ \ __/
\____\_______/
docker is configured to use the default machine with IP xxx.xxx.xxx.xxx
For help getting started, check out the docs at https://docs.docker.com
Start interactive shell
$
- 从环境变量中提取IP
DOCKER_HOST
,例如:
import os
import re
def get_docker_ip():
docker_host = os.environ.get("DOCKER_HOST", "127.0.0.1")
docker_ip = re.search(r"(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})", docker_host)
return docker_ip.group(1)
使用
Docker Desktop for Windows
使用 Hyper-v(Microsoft 虚拟化解决方案),因为它绑定到本地主机。请注意,使用 Hyper-v 会破坏 VirtualBox,因为它们不能很好地协同运行。
如果你仍想同时使用两者,则需要根据要使用的内容停用/激活 Hyper-v 并重新启动,如本指南。
答案2
我按照下面的建议对 IP 进行了硬编码,并且成功了。在设置 CHANNEL_LAYERS 配置中添加 IP。
CHANNEL_LAYERS = {
'default': {
'BACKEND': 'channels_redis.core.RedisChannelLayer',
'CONFIG': {
'hosts': [('xxx.xxx.xxx.xxx', 6379)],
},
},
}
非常感谢。Adrian