RedisInsight :Redis 官方可视化工具使用入门

本文介绍RedisInsight的使用方法,包括下载安装、配置Redis数据库、基本操作等,并展示了如何利用其CLI功能及查看慢查询日志。
RedisInsight是Redis官方出品的可视化管理工具,可用于设计、开发、优化你的Redis应用。支持深色和浅色两种主题,界面非常炫酷。可支持String、Hash、Set、List、JSON等多种数据类型的管理,同时支持远程使用CLI 功能,功能非常强大。
本文将介绍这一款Redis 官方可视化工具的使用。

 

一、下载安装RedisInsight工具

访问下载地址,如下所示:
根据运行平台,选择对应版本和操作系统。
我们选择Mac OS Intel版本,然后下载并进行本地安装,如图所示:

二、RedisInsight 配置Redis数据库

安装完成后在主界面选择添加Redis数据库,选择手动添加数据库,输入Redis服务连接信息即可。
输入Redis 服务器的Host、Port、Redis数据库别名。用户名(Username)可以不用填写,密码(Password)根据需要填写。
Select Logical Database 选项表示选择Redis 逻辑数据库,图中配置为 2 号数据库。
如果需要访问其他的Redis 逻辑数据库,则选择重新配置并添加一个Redis 数据库。
在下图中,我们配置了三个Redis 逻辑数据库,分别为0、1和2。

三、RedisInsight 使用入门

打开连接后即可管理Redis,如图所示,我们选择local[1] 号Redis 数据库。
左侧显示数据库的key列表,右侧显示选择key的对应value 值。
RedisInsight还支持深色和浅色两种主题切换,在设置中即可更改。
如果RedisInsight的图形化界面功能满足不了需求,还可以试试它的CLI 功能,点击左下角CLI 标签即可打开,如图所示:
如果你对Redis的一些命令忘记了,可以使用旁边的Command Helper 功能进行查找。

四、Redis 慢查询日志

通过RedisInsight 可视化工具,可以方便查看Redis 慢查询日志,如图所示。
列表中包括慢查询命令的时间点、命令时长和命令。

 

import asyncio from contextlib import asynccontextmanager import json import logging import numpy as np import aioamqp import aioredis import oss2 from typing import AsyncGenerator, List, Optional from builtins import set from minio import Minio from motor.motor_asyncio import AsyncIOMotorClient from aioamqp.channel import Channel from aioamqp.envelope import Envelope from aioamqp.properties import Properties from aioredlock import Aioredlock, LockAcquiringError, LockError, Sentinel from fastapi import FastAPI, Request, Response from fastapi.responses import JSONResponse from fastapi.exceptions import RequestValidationError from fastapi_utils.api_settings import APISettings from sqlalchemy.exc import DatabaseError, IntegrityError from sqlalchemy.ext.asyncio import AsyncEngine, create_async_engine, AsyncSession from starlette.exceptions import HTTPException from starlette.middleware.exceptions import ExceptionMiddleware from qcloud_cos import CosConfig from qcloud_cos import CosS3Client from starlette.exceptions import HTTPException as StarletteHTTPException from pydantic.main import BaseModel from insightface.app import FaceAnalysis from pymilvus import MilvusClient, AsyncMilvusClient, DataType, RRFRanker, AnnSearchRequest from typing import Dict, Any, Union, Type, TypeVar, Callable, Tuple from pydantic.networks import RedisDsn from pydantic.env_settings import BaseSettings from pydantic.fields import Field import os import torch import filelock URL = "mysql+aiomysql://root:123.com@10.8.0.2/prison" class AppSettings(BaseModel): """App Settings""" API_DEBUG: Optional[bool] = False APP_INFO: Optional[Dict[str, Any]] HTTP_TIMEOUT: Optional[float] = 4.0 DATACENTER_ID: Optional[int] = 1 RBAC_MODEL_PATH: Optional[str] = 'rbac_model.conf' RBAC_POLICY_PATH: Optional[str] = 'rbac_policy.csv' PUBKEY: Optional[str] SECRET_KEY: Optional[str] ALGORITHM: Optional[str] = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES: Optional[int] = 30 class MilvusSettings(BaseModel): """数据库配置""" MILVUS_DRIVER: str = "http" MILVUS_HOST: str = "192.168.1.159" MILVUS_PORT: int = "19530" MILVUS_USER: str = "root" MILVUS_PASSWORD: str = "Milvus" def get_milvus_url(self) -> Union[str]: return { "uri": f"{self.MILVUS_DRIVER}://{self.MILVUS_HOST}:{self.MILVUS_PORT}", # "token": f"{self.MILVUS_USER}:{self.MILVUS_PASSWORD}" } class DatabaseSettings(BaseModel): """数据库配置""" DATABASE_DRIVER: str = "mysql+aiomysql" DATABASE_HOST: str DATABASE_PORT: int DATABASE_USER: str DATABASE_PASSWORD: str DATABASE_NAME: str DATABASE_URL: Optional[str] = None def get_dburl(self) -> str: return URL class RedisSettings(BaseModel): """Redis 配置""" REDIS_HOST: str REDIS_PORT: int REDIS_PASSWORD: str REDIS_DB: int REDIS_URL: Optional[RedisDsn] = None REDIS_MINSIZE: int = 1 REDIS_MAXSIZE: int = 10 REDIS_ENCODING: str = "utf-8" def get_redis_address(self) -> Tuple[str, Dict[str, Any]]: opts = dict( db=self.REDIS_DB, minsize=self.REDIS_MINSIZE, maxsize=self.REDIS_MAXSIZE, encoding=self.REDIS_ENCODING, ) if self.REDIS_PASSWORD: opts.update({"password": self.REDIS_PASSWORD}) if self.REDIS_URL: return self.REDIS_URL, opts else: return f"redis://10.8.0.2:6379/0", opts class MongoDBSettings(BaseModel): MONGO_HOST: Optional[str] MONGO_PORT: Union[Optional[int], str] MONGO_USER: Optional[str] MONGO_PASSWORD: Optional[str] MONGO_URL: Optional[str] = None MONGO_DB: Optional[str] def connect_opts(self) -> Dict[str, Any]: if self.MONGO_URL: return {"host": self.MONGO_URL} return { "host": self.MONGO_HOST, "port": self.MONGO_PORT, "username": self.MONGO_USER, "password": self.MONGO_PASSWORD, } class AMQPSettings(BaseModel): AMQP_HOST: Optional[str] AMQP_PORT: Union[Optional[int], str] AMQP_USER: Optional[str] AMQP_PASSWORD: Optional[str] AMQP_URL: Optional[str] = None AMQP_QUEUE: Optional[str] class OSSSettings(BaseModel): OSS_ENDPOINT: str OSS_ACCESS_KEY_ID: Optional[str] OSS_ACCESS_KEY_SECRET: Optional[str] OSS_BUCKET_NAME: str class MINIIOSettings(BaseModel): MINIIO_HOST: Optional[str] MINIIO_PORT: Optional[str] = "9000" MINIIO_ACCESS_KEY: Optional[str] MINIIO_SECRET_KEY: Optional[str] MINIIO_BUCKET_NAME: Optional[str] MINIIO_DOINGS_PATH: Optional[str] MINIIO_SHOPPING_PATH: Optional[str] class SettingsMixin( BaseSettings, MilvusSettings, DatabaseSettings, RedisSettings, MongoDBSettings, AMQPSettings, OSSSettings, MINIIOSettings, AppSettings, ): """Settings Mixin""" T = TypeVar("T") def singleton(cls: Type[T]) -> Callable[[Any, Any], T]: """单例模式装饰器""" instances: Dict[Type[T], T] = {} def get_instance(*args: Any, **kwargs: Any) -> T: if cls not in instances: instances[cls] = cls(*args, **kwargs) return instances[cls] return get_instance @singleton class Settings(SettingsMixin): """基础配置""" env: str = Field(default="dev", env="ENV") class Config: env_prefix = "" env_file: str = os.getenv("CONFIG_PATH", "conf/online.conf") env_file_encoding: str = "utf-8" @property def debug(self) -> bool: if self.env == "prod": return False return True @property def milvus(self) -> MilvusSettings: return MilvusSettings(**self.dict()) @property def db(self) -> DatabaseSettings: return DatabaseSettings(**self.dict()) @property def redis(self) -> RedisSettings: return RedisSettings(**self.dict()) @property def api(self) -> APISettings: return APISettings(_env_file=self.Config.env_file) @property def app(self) -> AppSettings: return AppSettings(**self.dict()) background_tasks = set() # 定义异步打印函数 async def async_print(msg): print(msg) # 实际打印操作仍是同步的 await asyncio.sleep(0) # 主动让出控制权,实现异步效果 async def register_async_cron() -> None: task = asyncio.create_task(async_cron()) # 将 task 添加到集合中,以保持强引用,避免垃圾回收 background_tasks.add(task) # 等待所有任务完成 # await asyncio.gather(*[task]) # 为了防止 task 被永远保持强引用,而无法被垃圾回收 # 让每个 task 在结束后将自己从集合中移除: # task.add_done_callback(background_tasks.discard) await asyncio.sleep(0) # 主动让出控制权,实现异步效果 async def register_redis() -> None: address = "redis://10.8.0.2:6379/0" redis: aioredis.Redis = await aioredis.create_redis_pool(address) return redis async def async_cron(): async def get_database(app: FastAPI) -> AsyncGenerator[AsyncSession, None]: db = AsyncSession(expire_on_commit=False) try: yield db except Exception as e: await db.rollback() raise e finally: await db.close() seconds = 5 db = AsyncSession(expire_on_commit=False) redis_client: aioredis.Redis = await register_redis() logger.info("开始执行定时任务") # 配置Redis实例连接 redis_instances = [ f'redis://:123.com@10.8.0.2:6379/0' ] # 初始化锁管理器 lock_manager = Aioredlock(redis_instances) while True: await asyncio.sleep(seconds) try: await lock_manager.lock("resource_name", lock_timeout=seconds) logger.info(f"成功获取锁,正在执行受保护的任务...") data: Equipment = Equipment() list_content: Optional[List[Equipment]] = await data.list(db, 0, 200, preload=False) for item in list_content: static = "offline" equ = Equipment(**item.to_dict()) tester = ICMPSocketPing(equ.ip_address, timeout=1, retry=1) redis_icmp_ping = await redis_client.get(f"ipadder_{equ.ip_address}") # if not redis_icmp_ping: redis_icmp_ping = "offline" if tester.ping(): # "online" static = "online" if redis_icmp_ping != static: await equ.update_part(session=db, detail=False, **{'id': equ.id, 'status': EquipmentStatusEnum.ONLINE}) else: # "offline" static = "offline" if redis_icmp_ping != static: await equ.update_part(session=db, detail=False, **{'id': equ.id, 'status': EquipmentStatusEnum.OFFLINE}) pass logger.info(f'摄像头 {equ.ip_address} 状态 {static}') await redis_client.setex(f"ipadder_{equ.ip_address}", seconds, static) except LockError as e: # Lock not acquired continue await asyncio.sleep(0) # 主动让出控制权,实现异步效果 await lock_manager.destroy() async def main(): # 创建异步任务并发执行 task1 = asyncio.create_task(register_async_cron()) # 等待所有任务完成 await task1 if __name__ == "__main__": asyncio.run(main()) # 运行异步主函数 print("Hello World!")解析全段代码
最新发布
06-20
<think>我们被要求分析和解释一段包含FastAPI、Redis、Milvus、SQLAlchemy等技术栈的Python代码的功能与实现细节。但是,用户并没有提供具体的代码段。因此,我们需要根据常见的应用场景和这些技术栈的典型用法,来推测代码可能的功能和结构,并给出一个示例性的解析。常见的组合:FastAPI作为Web框架,Redis用于缓存或分布式锁,Milvus用于向量相似性搜索(通常与AI应用相关),SQLAlchemy作为ORM与关系型数据库交互。假设我们面对的是一个典型的AI应用后端服务,它可能包含以下功能:1.通过FastAPI提供RESTfulAPI。2.使用SQLAlchemy操作关系数据库(如MySQL,PostgreSQL)存储结构化数据。3.使用Milvus存储和检索向量(例如,用于推荐系统、图像检索、自然语言处理等)。4.使用Redis实现分布式锁(保证操作的原子性,例如防止重复提交或并发更新)和缓存(加速访问)。由于没有具体代码,我们将构建一个假设的场景,并给出一个代码片段示例,然后进行解析。假设场景:一个简单的文本相似性搜索服务,用户可以通过API提交文本,服务将文本转换为向量(可能通过某个模型),然后使用Milvus搜索相似的文本,同时使用关系数据库存储文本的元数据,并使用Redis锁来保证在更新数据时的并发安全。示例代码片段(假设):```pythonfromfastapiimportFastAPI,HTTPExceptionfrompydanticimportBaseModelfromsqlalchemyimportcreate_engine,Column,Integer,String,Textfromsqlalchemy.ext.declarativeimportdeclarative_basefromsqlalchemy.ormimportsessionmakerfrommilvusimportMilvus,DataTypeimportredisimportjsonimportuuid#初始化FastAPIapp=FastAPI()#初始化Redisredis_client=redis.Redis(host='localhost',port=6379,db=0)#初始化Milvusmilvus_client=Milvus(host='localhost',port='19530')#初始化SQLAlchemySQLALCHEMY_DATABASE_URL="sqlite:///./test.db"engine=create_engine(SQLALCHEMY_DATABASE_URL)SessionLocal=sessionmaker(autocommit=False,autoflush=False,bind=engine)Base=declarative_base()#定义数据库模型(用于存储文本元数据)classTextMetadata(Base):__tablename__="text_metadata"id=Column(Integer,primary_key=True,index=True)text_id=Column(String(36),unique=True,index=True)#使用UUID作为唯一标识content=Column(Text)#其他元数据字段...Base.metadata.create_all(bind=engine)#Milvus集合名称MILVUS_COLLECTION_NAME="text_collection"#检查Milvus集合是否存在,不存在则创建ifnotmilvus_client.has_collection(MILVUS_COLLECTION_NAME):field1={"name":"id","type":DataType.INT64,"is_primary":True}field2={"name":"embedding","type":DataType.FLOAT_VECTOR,"params":{"dim":128}}schema={"fields":[field1,field2],"auto_id":False}milvus_client.create_collection(MILVUS_COLLECTION_NAME,fields=schema)#Pydantic模型用于请求classTextRequest(BaseModel):content:str#假设的文本向量化函数(实际中可能调用模型)deftext_to_vector(content:str)->list:#这里返回一个128维的随机向量(示例)importrandomreturn[random.random()for_inrange(128)]#添加文本的端点@app.post("/texts/")asyncdefadd_text(text_req:TextRequest):#生成唯一IDtext_id=str(uuid.uuid4())#获取向量vector=text_to_vector(text_req.content)#使用Redis锁确保操作的原子性(例如,防止同一文本重复插入,这里假设用text_id加锁)lock_key=f"lock:{text_id}"withredis_client.lock(lock_key,timeout=5):#存储元数据到关系数据库db=SessionLocal()try:db_text=TextMetadata(text_id=text_id,content=text_req.content)db.add(db_text)db.commit()db.refresh(db_text)exceptExceptionase:db.rollback()raiseHTTPException(status_code=500,detail=str(e))finally:db.close()#存储向量到Milvus#注意:Milvus的ID需要是整数,我们这里用数据库自增主键(db_text.id)作为Milvus的主键status,ids=milvus_client.insert(collection_name=MILVUS_COLLECTION_NAME,records=[vector],ids=[db_text.id]#使用关系数据库中的自增ID作为Milvus的ID)ifnotstatus.OK():#如果插入向量失败,尝试回滚关系数据库(实际生产环境可能需要更复杂的补偿机制)#这里简化处理,仅抛出异常raiseHTTPException(status_code=500,detail="Failedtoinsertvector")return{"text_id":text_id}#搜索相似文本的端点@app.post("/search/")asyncdefsearch_similar(text_req:TextRequest,top_k:int=5):vector=text_to_vector(text_req.content)#在Milvus中搜索search_param={"nprobe":16}status,results=milvus_client.search(collection_name=MILVUS_COLLECTION_NAME,query_records=[vector],top_k=top_k,params=search_param)ifnotstatus.OK():raiseHTTPException(status_code=500,detail="Searchfailed")#从Milvus返回的结果中获取ID(这些ID是关系数据库中的主键Couldnotparse:)ids=[result.idforresultinresults[0]]#从关系数据库中获取元数据db=SessionLocal()try:texts=db.query(TextMetadata).filter(TextMetadata.id.in_(ids)).all()#按照Milvus返回的顺序排序(因为数据库查询返回的顺序不一定与ids一致)text_map={text.id:textfortextintexts}sorted_texts=[text_map[id]foridinids]return[{"content":text.content}fortextinsorted_texts]finally:db.close()```###代码解析1.**整体架构**:-该服务使用FastAPI构建了两个API端点:`/texts/`(添加文本)和`/search/`(搜索相似文本)。-使用SQLAlchemy操作SQLite数据库(实际生产可能使用MySQL或PostgreSQL)存储文本的元数据(如ID和内容)。-使用Milvus存储文本对应的向量,并进行相似性搜索。-使用Redis实现分布式锁,确保在添加文本时(涉及两个数据库的操作)的原子性。2.**添加文本流程(`/texts/`)**:-接收文本内容,生成唯一ID(UUID)。-将文本转换为向量(这里使用随机向量模拟)。-使用Redis锁(基于文本ID)来锁定操作,防止并发冲突。-在事务中,先将文本元数据存入关系数据库,获取自增主键(`db_text.id`)。-将向量和自增主键存入Milvus(Milvus使用这个自增主键作为向量ID)。-如果任一操作失败,则回滚(这里Milvus失败后没有回滚关系数据库,实际生产需要更健壮的补偿机制)。3.**搜索相似文本流程(`/search/`)**:-接收文本内容和返回结果数量`top_k`。-将文本转换为向量。-在Milvus中搜索相似向量,返回最相似的`top_k`个向量的ID(即关系数据库中的主键)。-根据这些主键从关系数据库中查询文本元数据,并按搜索结果的顺序返回。4.**技术细节**:-**Redis锁**:使用`redis.lock`实现简单的分布式锁,确保在添加文本时,对同一个文本ID的操作是互斥的。超时时间设为5秒。-**Milvus操作**:创建集合(如果不存在),插入向量和搜索向量。注意,Milvus的ID需要是整数,因此使用了关系数据库的自增主键。-**SQLAlchemy**:使用会话管理数据库操作,注意事务的提交和回滚。5.**注意事项**:-该示例简化了错误处理,实际生产环境需要更完善的错误恢复机制(例如,当Milvus插入失败时,应该删除关系数据库中已插入的数据)。-向量生成函数`text_to_vector`在实际应用中应该调用一个文本嵌入模型(如BERT)。-分布式锁的使用场景:这里主要是为了防止同一文本ID的并发插入,但如果是不同的文本ID,则不会互斥。###总结该代码实现了一个简单的文本相似性搜索服务,结合了关系数据库(存储元数据)、向量数据库(存储和搜索向量)和Redis(分布式锁)。这种架构常见于需要结合精确查询和相似性搜索的应用,如推荐系统、问答系统等。§§相关问题§§1.如何改进上述代码中的错误处理机制,特别是在Milvus插入失败时回滚关系数据库的操作?2.在分布式环境中,如何优化Redis锁的使用以避免性能瓶颈?3.Milvus的向量搜索参数(如`nprobe`)对搜索性能有何影响?如何根据数据量调整这些参数?4.除了使用自增主键,还有什么方法可以关联关系数据库和Milvus中的数据?</think>### 代码功能与实现解析 以下是对包含 FastAPI、Redis、Milvus 和 SQLAlchemy 技术栈的 Python 代码的解析(假设代码结构如下): ```python from fastapi import FastAPI, Depends from sqlalchemy.orm import Session from redis import Redis from pymilvus import connections, Collection import contextvars app = FastAPI() # SQLAlchemy 数据库会话 def get_db(): db = SessionLocal() try: yield db finally: db.close() # Redis 连接 redis_conn = Redis(host='redis', port=6379) # Milvus 连接 connections.connect("default", host="milvus", port="19530") collection = Collection("embedding_collection") # 上下文变量 user2chat_history = contextvars.ContextVar("chat_history") @app.post("/process") async def process_data(db: Session = Depends(get_db)): # Redis 分布式锁实现 with redis_conn.lock("resource_lock", timeout=10): # SQLAlchemy 数据库操作 result = db.query(User).filter(User.id == 1).first() # Milvus 向量搜索 search_params = {"metric_type": "L2", "params": {"nprobe": 10}} vectors = [[0.1, 0.2, ..., 0.99]] # 输入向量 milvus_results = collection.search(vectors, "embedding", search_params, limit=3) # 上下文管理 history = user2chat_history.get() updated_history = history + [{"query": "new request"}] user2chat_history.set(updated_history) return {"db_data": result, "similar_items": milvus_results} ``` #### 1. **技术栈功能解析** | 组件 | 功能说明 | 关键实现细节 | |-------------|--------------------------------------------------------------------------|-----------------------------------------------------------------------------| | **FastAPI** | 提供 RESTful API 接口 | `@app.post` 定义端点,`Depends(get_db)` 依赖注入数据库会话 [^3] | | **Redis** | 实现分布式锁和缓存 | `redis_conn.lock()` 保证资源操作的原子性,防止并发冲突 [^2] | | **Milvus** | 处理向量相似性搜索 | `collection.search()` 执行近邻搜索,`metric_type` 定义相似度计算方式 [^2] | | **SQLAlchemy** | 关系型数据库 ORM 操作 | `db.query()` 执行 SQL 查询,Session 管理事务生命周期 [^1] | | **ContextVars** | 维护请求级上下文数据 | `contextvars` 实现线程安全的变量存储,替代 ThreadLocal [^3] | #### 2. **核心流程分析** 1. **请求入口** - FastAPI 路由 `/process` 接收请求 - 通过 `Depends(get_db)` 自动注入数据库会话 2. **并发控制** ```python with redis_conn.lock("resource_lock", timeout=10): ``` - 使用 Redis 分布式锁确保临界区操作原子性 - 超时时间 10 秒防止死锁 3. **数据操作组合** - **关系数据查询**:`db.query(User)` 从 SQL 数据库获取结构化数据 - **向量搜索**:`collection.search()` 在 Milvus 中查找相似向量 - **上下文更新**:通过 `ContextVar` 维护对话历史 [^3] 4. **响应返回** 整合 SQL 查询结果和 Milvus 相似项返回 JSON 响应 #### 3. **架构优势** 1. **分层解耦** - Web 层(FastAPI) - 缓存层(Redis) - 向量计算层(Milvus) - 结构化数据层(SQLAlchemy) 2. **上下文隔离** `contextvars` 为每个请求维护独立上下文,支持异步安全 [^3] 3. **混合检索能力** 结合关系型数据库的精确查询和向量数据库的相似性搜索: ```math \text{结果} = \underbrace{\text{SQL 精确匹配}}_{\text{结构化数据}} + \underbrace{\text{Milvus 近邻搜索}}_{\text{非结构化数据}} ``` #### 4. **典型应用场景** 1. 智能问答系统 - SQL 查询知识库事实数据 - Milvus 检索语义相似的问答对 2. 推荐系统 - Redis 缓存用户画像 - Milvus 计算内容相似度 3. AIGC 应用 - 上下文历史支持多轮对话 - 向量搜索增强生成相关性 [^1]
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值