Mac 本地搭建 Redis 指南

Mac 本地搭建 Redis 指南

一、安装 Redis

方式一:Homebrew 安装(推荐)

# 安装
brew install redis

# 验证安装
redis-server --version

方式二:Docker 安装

docker run -d --name redis -p 6379:6379 redis:latest

方式三:源码编译

curl -O http://download.redis.io/redis-stable.tar.gz
tar xzf redis-stable.tar.gz
cd redis-stable
make
make install

二、启动与停止

# 前台启动
redis-server

# 后台服务方式启动(开机自启)
brew services start redis

# 停止服务
brew services stop redis

# 重启服务
brew services restart redis

# 查看服务状态
brew services info redis

三、验证连接

# 连接本地 Redis
redis-cli

# 测试连通性
redis-cli ping
# 返回 PONG 表示正常

四、项目配置

测试脚本和本项目均通过环境变量读取 Redis 配置,在 .env 文件中添加或通过命令行导出:

REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_DB=0
REDIS_PASSWORD=
REDIS_TIMEOUT=5

如果本地 Redis 未设置密码,REDIS_PASSWORD 留空即可。

五、常用 redis-cli 命令

命令 说明
redis-cli 连接本地 Redis
redis-cli -h <host> -p <port> 连接指定地址
redis-cli -a <password> 带密码连接
redis-cli info 查看 Redis 信息
redis-cli dbsize 查看当前库 key 数量
redis-cli flushdb 清空当前库
redis-cli shutdown 关闭 Redis 服务

六、常用配置修改

Homebrew 安装的配置文件路径:

  • Apple Silicon:/opt/homebrew/etc/redis.conf
  • Intel Mac:/usr/local/etc/redis.conf

常见修改项:

# 设置密码
requirepass your_password

# 允许远程访问(默认只允许本地)
bind 0.0.0.0

# 修改端口
port 6379

# 设置最大内存
maxmemory 256mb

# 内存淘汰策略
maxmemory-policy allkeys-lru

修改后重启 Redis 生效:

brew services restart redis

七、运行测试程序

测试脚本为独立文件,不依赖本项目代码,唯一依赖:

pip install redis

确保 Redis 已启动后,直接运行:

python examples/test_local_redis.py

也可通过环境变量指定连接参数(默认连接 127.0.0.1:6379,无密码):

REDIS_HOST=127.0.0.1 REDIS_PORT=6379 python examples/test_local_redis.py

该脚本会依次测试连接、字符串读写、哈希、列表、集合、过期机制、Keys 模式匹配,最终输出通过/失败汇总。

点击查看代码
"""
本地 Redis 连接独立测试程序(无项目依赖)

仅依赖第三方库:redis (>=4.2,含 redis.asyncio)
安装:pip install redis

使用方式:
    1. 确保本地 Redis 已启动: redis-cli ping
    2. 直接运行: python test_local_redis.py
    3. 可通过环境变量覆盖默认配置:
       REDIS_HOST / REDIS_PORT / REDIS_DB / REDIS_PASSWORD / REDIS_TIMEOUT
"""

import os
import asyncio

import redis.asyncio as aioredis


# ───────── 配置(可通过环境变量覆盖)─────────

REDIS_HOST = os.getenv("REDIS_HOST", "127.0.0.1")
REDIS_PORT = int(os.getenv("REDIS_PORT", "6379"))
REDIS_DB = int(os.getenv("REDIS_DB", "0"))
REDIS_PASSWORD = os.getenv("REDIS_PASSWORD") or None
REDIS_TIMEOUT = int(os.getenv("REDIS_TIMEOUT", "5"))


# ───────── 测试统计 ─────────

passed = 0
failed = 0


def report(name: str, ok: bool, detail: str = ""):
    """打印一条测试结果"""
    global passed, failed
    status = "PASS" if ok else "FAIL"
    if ok:
        passed += 1
    else:
        failed += 1
    msg = f"  [{status}] {name}"
    if detail:
        msg += f"  ({detail})"
    print(msg)


# ───────── 连接管理 ─────────

async def create_client() -> aioredis.Redis:
    """创建一个本地 Redis 异步客户端"""
    pool = aioredis.ConnectionPool(
        host=REDIS_HOST,
        port=REDIS_PORT,
        db=REDIS_DB,
        password=REDIS_PASSWORD,
        decode_responses=True,
        socket_timeout=REDIS_TIMEOUT,
        socket_connect_timeout=REDIS_TIMEOUT,
        max_connections=10,
    )
    return aioredis.Redis(connection_pool=pool)


# ───────── 测试用例 ─────────

async def test_connection(client: aioredis.Redis) -> bool:
    """测试 1:连接与 Ping"""
    print("\n--- 测试 1:连接与 Ping ---")
    try:
        pong = await client.ping()
        report("Redis 连接", bool(pong), f"{REDIS_HOST}:{REDIS_PORT}")
        return bool(pong)
    except Exception as e:
        report("Redis 连接", False, str(e))
        return False


async def test_string_ops(client: aioredis.Redis):
    """测试 2:字符串读写"""
    print("\n--- 测试 2:字符串读写 ---")
    key = "test:string:hello"
    try:
        ok = await client.set(key, "world", ex=60)
        report("SET", bool(ok))

        val = await client.get(key)
        report("GET", val == "world", f"value={val}")

        exists = await client.exists(key)
        report("EXISTS", exists > 0)

        await client.delete(key)
        exists_after = await client.exists(key)
        report("DELETE", exists_after == 0)
    except Exception as e:
        report("字符串操作", False, str(e))


async def test_hash_ops(client: aioredis.Redis):
    """测试 3:哈希操作"""
    print("\n--- 测试 3:哈希操作 ---")
    key = "test:hash:user"
    try:
        await client.hset(key, "name", "test_user")
        await client.hset(key, "role", "developer")
        await client.expire(key, 60)

        name = await client.hget(key, "name")
        report("HSET / HGET", name == "test_user", f"name={name}")

        all_fields = await client.hgetall(key)
        report("HGETALL", len(all_fields) == 2, f"fields={all_fields}")

        await client.delete(key)
    except Exception as e:
        report("哈希操作", False, str(e))


async def test_list_ops(client: aioredis.Redis):
    """测试 4:列表操作"""
    print("\n--- 测试 4:列表操作 ---")
    key = "test:list:queue"
    try:
        await client.delete(key)
        await client.lpush(key, "a", "b", "c")
        await client.expire(key, 60)

        val = await client.rpop(key)
        report("LPUSH / RPOP", val == "a", f"popped={val}")

        await client.delete(key)
    except Exception as e:
        report("列表操作", False, str(e))


async def test_set_ops(client: aioredis.Redis):
    """测试 5:集合操作"""
    print("\n--- 测试 5:集合操作 ---")
    key = "test:set:tags"
    try:
        await client.delete(key)
        await client.sadd(key, "python", "redis", "mac")
        await client.expire(key, 60)

        members = await client.smembers(key)
        report("SADD / SMEMBERS", len(members) == 3, f"members={members}")

        await client.srem(key, "mac")
        members2 = await client.smembers(key)
        report("SREM", len(members2) == 2, f"after_remove={members2}")

        await client.delete(key)
    except Exception as e:
        report("集合操作", False, str(e))


async def test_expire(client: aioredis.Redis):
    """测试 6:过期机制"""
    print("\n--- 测试 6:过期机制 ---")
    key = "test:expire:tmp"
    try:
        await client.set(key, "will_expire", ex=2)
        val1 = await client.get(key)
        report("写入带过期的 key", val1 == "will_expire")

        print("    等待 3 秒让 key 过期...")
        await asyncio.sleep(3)

        val2 = await client.get(key)
        report("过期后 GET 为空", val2 is None, f"value={val2}")
    except Exception as e:
        report("过期机制", False, str(e))


async def test_keys_pattern(client: aioredis.Redis):
    """测试 7:Keys 模式匹配"""
    print("\n--- 测试 7:Keys 模式匹配 ---")
    try:
        await client.set("test:pattern:a", "1", ex=60)
        await client.set("test:pattern:b", "2", ex=60)

        keys = await client.keys("test:pattern:*")
        report("KEYS 模式匹配", len(keys) >= 2, f"found={len(keys)} keys")

        await client.delete("test:pattern:a", "test:pattern:b")
    except Exception as e:
        report("Keys 模式匹配", False, str(e))


# ───────── 主入口 ─────────

async def main():
    print("=" * 50)
    print(" Mac 本地 Redis 连接测试(独立版)")
    print("=" * 50)
    print(f"\n目标地址: {REDIS_HOST}:{REDIS_PORT}/{REDIS_DB}")
    print(f"密码: {'(已设置)' if REDIS_PASSWORD else '(无密码)'}")

    client = await create_client()

    try:
        connected = await test_connection(client)
        if not connected:
            print("\n连接失败,终止后续测试。请检查:")
            print("  1. Redis 是否已启动: redis-cli ping")
            print("  2. 主机/端口/密码是否正确(可通过 REDIS_HOST 等环境变量覆盖)")
            return

        await test_string_ops(client)
        await test_hash_ops(client)
        await test_list_ops(client)
        await test_set_ops(client)
        await test_expire(client)
        await test_keys_pattern(client)

    finally:
        try:
            await client.aclose()
        except Exception:
            pass

    # 汇总
    print("\n" + "=" * 50)
    total = passed + failed
    print(f" 测试结果: {passed}/{total} 通过, {failed} 失败")
    if failed == 0:
        print(" 本地 Redis 一切正常!")
    else:
        print(" 存在失败项,请检查日志排查问题。")
    print("=" * 50)


if __name__ == "__main__":
    asyncio.run(main())

执行 python examples/test_local_redis.py 效果如下:

==================================================
 Mac 本地 Redis 连接测试(独立版)
==================================================

目标地址: 127.0.0.1:6379/0
密码: (无密码)

--- 测试 1:连接与 Ping ---
  [PASS] Redis 连接  (127.0.0.1:6379)

--- 测试 2:字符串读写 ---
  [PASS] SET
  [PASS] GET  (value=world)
  [PASS] EXISTS
  [PASS] DELETE

--- 测试 3:哈希操作 ---
  [PASS] HSET / HGET  (name=test_user)
  [PASS] HGETALL  (fields={'name': 'test_user', 'role': 'developer'})

--- 测试 4:列表操作 ---
  [PASS] LPUSH / RPOP  (popped=a)

--- 测试 5:集合操作 ---
  [PASS] SADD / SMEMBERS  (members={'redis', 'python', 'mac'})
  [PASS] SREM  (after_remove={'redis', 'python'})

--- 测试 6:过期机制 ---
  [PASS] 写入带过期的 key
    等待 3 秒让 key 过期...
  [PASS] 过期后 GET 为空  (value=None)

--- 测试 7:Keys 模式匹配 ---
  [PASS] KEYS 模式匹配  (found=2 keys)

==================================================
 测试结果: 13/13 通过, 0 失败
 本地 Redis 一切正常!
==================================================
posted @ 2026-04-30 14:30  郭流水  阅读(84)  评论(0)    收藏  举报