通过 Python+Nacos实现微服务,细解微服务架构
shigen坚持更新文章的博客写手,擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。记录成长,分享认知,留住感动。
个人IP:shigen
背景
一直以来的想法比较多,然后就用Python编写各种代码脚本。很多的脚本都是通过Python的Flask框架实现,如[file-server],然后部署到云服务器。但是这样只提供一个端口就可以通过http访问,无异于在互联网上裸奔。而且这样的服务有很多个,一直在想如何实现一个统一认证然后就可以访问这么多的服务。在Java领域最常见的设计就是使用微服务架构,把每个服务拆分出来,然后通过网关统一拦截、验证、分发流量。蹭了一张架构图(发现飞书的模板已经很好了):

那我的Python服务为什么不能设计成微服务架构呢,当然,还没听说过谁家的Python服务是微服务架构的,姑且一试。
代码实现
考虑到大家的技术栈就是Java,以下的python代码将省略部分细节。
有了之前python flask如何注册到nacos踩坑的经验,这次明显顺利的多了。现在本地搭建nacos环境,并支持http访问,推荐docker-compose的方式搭建:shigen/spring-cloud-platform
因为我的Nacos版本是2.0+的,官方的nacos-sdk-python是这样描述的:
Supported Python version:
Python 2.7 Python 3.6 Python 3.7
Supported Nacos version
Nacos 0.8.0 ~ 1.3.2
于是就使用的是官方的API:Open API 指南
我的服务模块是这样细分的:
microservices-demo/
├── nacos/
├── api-gateway/
│ └── app.py
├── user-service/
│ └── app.py
├── auth-service/
│ └── app.py
└── document-service/└── app.py
也就是分成了四个模块:网关、用户中心、鉴权中心、文档中心。接下来就是服务的注册和调用。我们以最简单的auth-service为例:
NACOS_URL = os.getenv("NACOS_URL", "http://localhost:8848/nacos/v1/ns/instance")
SERVICE_NAME = "auth-service"
SERVICE_IP = socket.gethostbyname(socket.gethostname())
SERVICE_PORT = 5002
NAMESPACE = "python"# 发送到Nacos服务注册接口
def register_service():payload = {"serviceName": SERVICE_NAME,"ip": SERVICE_IP,"port": SERVICE_PORT,"namespaceId": NAMESPACE,}response = requests.post(f"{NACOS_URL}", params=payload)# 每5秒发送一次心跳
def send_heartbeat():while True:payload = {"serviceName": SERVICE_NAME,"ip": SERVICE_IP,"port": SERVICE_PORT,"namespaceId": NAMESPACE,}response = requests.put(f"{NACOS_URL}/beat", params=payload)time.sleep(5)# 密码验证,获得token
@app.route('/auth', methods=['POST'])
def authenticate():pass# 验证token
@app.route('/verify', methods=['POST'])
def verify_token():pass# 服务启动类
if __name__ == '__main__':register_service()heartbeat_thread = threading.Thread(target=send_heartbeat)heartbeat_thread.daemon = Trueheartbeat_thread.start()app.run(port=SERVICE_PORT)
不用尝试读懂代码,很简单:在服务启动的时候注册到nacos,完了就是定时的向nacos发送心跳。@app.route(‘/auth’, methods=[‘POST’])表示提供一个POST请求方式的/auth接口,然后启动服务:

服务启动成功之后,可以看到控制台打印的日志信息。同时提供http访问接口。测试的方式如下:
curl --location 'http://127.0.0.1:5002/auth' \
--header 'Content-Type: application/json' \
--data '{"username": "user","password": "pass"
}'
其他的几个服务也如法炮制。最终Nacos服务注册表如下:

在网关这一块可能稍微有一点区别,复习前面提到的网关的作用:流量的拦截和转发、认证拦截、负载均衡…这里我的网关服务设计如下:
NACOS_URL = os.getenv("NACOS_URL", "http://localhost:8848/nacos/v1/ns/instance")
NAMESPACE = "python"def get_service_url(service_name):try:response = requests.get(f"{NACOS_URL}/list?serviceName={service_name}&namespaceId={NAMESPACE}")data = response.json()if data and data['hosts']:service = data['hosts'][0]# return f"http://{service['ip']}:{service['port']}"# 这里是本机调用测试return f"http://localhost:{service['port']}"except Exception as e:print(f"Error getting service URL: {e}")return None@app.route('/<service_name>/<path:path>', methods=['GET', 'POST', 'PUT', 'DELETE'])
def proxy(service_name, path):service_url = get_service_url(service_name)if not service_url:return jsonify({"error": "Service not found"}), 404# 认证逻辑if service_name != "auth-service":token = request.headers.get("Authorization")if not token:return jsonify({"error": "Missing token"}), 401auth_url = get_service_url("auth-service")if not auth_url:return jsonify({"error": "Auth service not found"}), 500verify_response = requests.post(f"{auth_url}/verify", json={"token": token})if verify_response.status_code != 200:return jsonify({"error": "Invalid token"}), 401url = f"{service_url}/{path}"response = requests.request(method=request.method,url=url,headers={key: value for key,value in request.headers if key != 'Host'},data=request.get_data(),cookies=request.cookies,allow_redirects=False)return (response.content, response.status_code, response.headers.items())if __name__ == '__main__':app.run(port=8080)
这里其实就是请求来了之后,从nacos上拉取服务列表。这个服务列表就是服务名称和对应的服务所在机器的IP(service-name和对应的IP集合)。然后选取对应服务所在的机器之一作为目标机器(这里选用的是第一台机器),从请求头中获得token,进行验证和调用。token校验失败则打给认证服务,重新进行登录验证。为此,我还对比了一下Spring Cloud + Nacos的设计:

Nacos的API实现的是springframework.cloud.client.discovery的接口,意味着统一的标准:
package com.alibaba.cloud.nacos.discovery;public class NacosDiscoveryClient implements DiscoveryClient {private static final Logger log = LoggerFactory.getLogger(NacosDiscoveryClient.class);/*** Nacos Discovery Client Description.*/public static final String DESCRIPTION = "Spring Cloud Nacos Discovery Client";private NacosServiceDiscovery serviceDiscovery;public NacosDiscoveryClient(NacosServiceDiscovery nacosServiceDiscovery) {this.serviceDiscovery = nacosServiceDiscovery;}@Overridepublic String description() {return DESCRIPTION;}@Overridepublic List<ServiceInstance> getInstances(String serviceId) {try {return serviceDiscovery.getInstances(serviceId);}catch (Exception e) {throw new RuntimeException("Can not get hosts from nacos server. serviceId: " + serviceId, e);}}@Overridepublic List<String> getServices() {try {return serviceDiscovery.getServices();}catch (Exception e) {log.error("get service name from nacos server fail,", e);return Collections.emptyList();}}}
其中的serviceName和serviceId其实是同一概念,意味着我们可以通过服务名获得全部的部署服务的实例信息,实现自定义的负载均衡调用。这里的原理和我直接从Nacos的API中获得服务列表,默认选取第一台机器进行调用的设计如出一辙。
对于以上的Python代码段,可能文字描述有不详细或者不当之处,借助魔法进行进一步的完善:
这段代码实现了一个反向代理服务器,其主要功能是根据服务名称将请求转发到不同的服务,并在转发前进行认证。具体功能如下:
- 服务发现:代码通过访问 NACOS(一个服务发现和配置管理平台)来获取目标服务的 URL。NACOS 提供了服务注册和发现的功能,代码中通过 get_service_url(service_name) 函数实现这一功能。
- 请求转发:当接收到一个请求时,根据 URL 中的 service_name 和 path,代码会将请求转发到相应的目标服务。转发时,保留了原始请求的 HTTP 方法、头信息、数据和 cookies。
- 认证检查:对于非 auth-service 的请求,代码会检查请求头中是否包含 Authorization token。如果没有 token 或 token 无效,则会返回错误响应。具体步骤如下:
- 检查请求头中是否包含 Authorization token。
- 如果没有 token,返回 401 错误(未授权)。
- 如果有 token,向认证服务(auth-service)发送请求,验证 token 的有效性。
- 如果 token 无效,返回 401 错误。
- 错误处理:代码包含了基本的错误处理逻辑,例如当服务 URL 无法获取或认证服务不可用时,返回相应的错误响应。
通过这些功能,该反向代理服务器能够在微服务架构中充当中间层,路由请求并提供统一的认证机制。
这样下来,我们调用服务只需要直接走网关了,其它的服务端口也不用放行,极大程度上保证了数据的安全。此时,我们需要这样调用服务:
登录
curl --location 'http://127.0.0.1:8080/auth-service/auth' \
--header 'Content-Type: application/json' \
--data '{
"username": "user",
"password": "pass"
}'
服务调用
curl --location 'http://127.0.0.1:8080/document-service/documents' \
--header 'Authorization: xxx'
总结
之前微服务的开发中,可能我们借助Spring Cloud部分组件、Nacos,在项目中加上依赖配置,稍微改一下配置文件,服务就可以正常的调用了。其中依赖的SDK如何的工作,可能只是停留在理论上,缺少实操。这次的这个案例很好的展示Python+Nacos如何实现微服务,并从中细解微服务结构和服务之间的调用原理。是不是觉得Nacos其实也不过如此哈,没什么牛掰、独特之处,其实都是草台班子。
与shigen一起,每天不一样!
相关文章:
通过 Python+Nacos实现微服务,细解微服务架构
shigen坚持更新文章的博客写手,擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。记录成长,分享认知,留住感动。 个人IP:shigen 背景 一直以来的想法比较多,然后就用Python编写各种代码脚本。很多…...
如何使用new和delete操作符进行动态内存分配和释放?
在C中,new 和 delete 操作符用于在堆(heap)上动态地分配和释放内存。这是管理内存的一种重要方式,特别是在需要创建可变数量或生命周期与程序执行流程不一致的对象时。 使用 new 进行动态内存分配 当你使用 new 操作符时&#x…...
【SCAU数据挖掘】数据挖掘期末总复习题库选择题及解析
1.将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?( C ) A.频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 解析:数据预处理是数据分析和数据挖掘的重要步骤之一,包括数据清洗、集成、变换、规约(如维度规约、数值规约)等。这…...
顶顶通呼叫中心中间件-限制最大通话时间(mod_cti基于FreeSWITCH)
顶顶通呼叫中心中间件-限制最大通话时间(mod_cti基于FreeSWITCH) 一、最大通话时间 1、配置拨号方案 1、点击拨号方案 ->2、在框中输入通话最大时长->3、点击添加->4、根据图中配置->5、勾选continue。修改拨号方案需要等待一分钟即可生效 action"sched…...
深度学习:使用argparse 模块
在深度学习中,结合 Bash 脚本和 argparse 模块,可以实现高效的任务自动化和参数管理。Bash 脚本可以用来调度任务和管理环境,而 argparse 模块可以用来解析命令行参数,控制深度学习模型的训练和评估过程。 1.argparse 模块 argp…...
unity text根据文本内容自动设置高度
我们经常会遇到需要根据文字数量动态修改文本框高度的需求,我们可以使用文本的行数*每行的高度来计算文本框的高度,伪代码如下: int oneLineHight 50;// 每行的像素高度 private void ResetTextHight(string str) {//设置文字内容ShowText.…...
ARM 汇编 C语言 for循环
在使用 Keil 编译基于 STM32F103 的 C 语言程序时,生成的汇编代码会有一些不同。STM32F103 是基于 ARM Cortex-M3 内核的微控制器,因为汇编语言是 ARM 汇编,而不是 x86 汇编。 示例 C 代码 假设我们有如下的简单 C 语言 for 循环代码&#x…...
java:【@ComponentScan】和【@SpringBootApplication】扫包范围的冲突
# 代码结构如下: 注意【com.chz.myBean.branch】和【com.chz.myBean.main】这两个包是没有生重叠的。 主程序【MyBeanTest1、MyBeanTest2、MyBeanTest3】这两个类是在包【com.chz.myBean.main】下 # 示例代码 【pom.xml】 <dependency><groupId>org.…...
本学期嵌入式期末考试的综合项目,我是这么出题的
时间过得真快,临近期末,又到了老师出卷的时候。作为《嵌入式开发及应用》这门课的主讲教师,今年给学生出的题目有一点点难度,最后的综合项目要求如下所示,各位学生朋友和教师同行可以评论一下难度如何,单片…...
CSS概述
CSS是一种样式表语言,用于为HTML文档控制外观,定义布局。例如, CSS涉及字体、颜色、边距、高度、宽度、背景图像、高级定位等方面 。 ● 可将页面的内容与表现形式分离,页面内容存放在HTML文档中,而用 于定义表现形式…...
Tensorflow-GPU工具包了解和详细安装方法
目录 基础知识信息了解 显卡算力 CUDA兼容 Tensorflow gpu安装 CUDA/cuDNN匹配和下载 查看Conda driver的版本 下载CUDA工具包 查看对应cuDNN版本 下载cuDNN加速库 CUDA/cuDNN安装 CUDA安装方法 cuDNN加速库安装 配置CUDA/cuDNN环境变量 配置环境变量 核验是否安…...
【python】OpenCV GUI——Trackbar(14.2)
学习来自 OpenCV基础(12)OpenCV GUI中的鼠标和滑动条 文章目录 GUI 滑条介绍cv2.createTrackbar 介绍牛刀小试 GUI 滑条介绍 GUI滑动条是一种直观且快速的调节控件,主要用于改变一个数值或相对值。以下是关于GUI滑动条的详细介绍:…...
Qt自定义日志输出
Qt自定义日志输出 简略版: #include <QApplication> #include <QDebug> #include <QDateTime> #include <QFileInfo> // 将日志类型转换为字符串 QString typeToString(QtMsgType type) {switch (type) {case QtDebugMsg: return "D…...
[C++] vector list 等容器的迭代器失效问题
标题:[C] 容器的迭代器失效问题 水墨不写bug 正文开始: 什么是迭代器? 迭代器是STL提供的六大组件之一,它允许我们访问容器(如vector、list、set等)中的元素,同时提供一个遍历容器的方法。然而…...
Java——变量作用域和生命周期
一、作用域 1、作用域简介 在Java中,作用域(Scope)指的是变量、方法和类在代码中的可见性和生命周期。理解作用域有助于编写更清晰、更高效的代码。 2、作用域 块作用域(Block Scope): 块作用域是指在…...
WPF界面设计
1、使用C#-WPF实现抽屉效果-炫酷漂亮的侧边栏导航菜单-SplitViewMD主题重绘原生控件的美观效果-提供源码Demo下载 码源地址:https://download.csdn.net/download/Prince999999/89424685 2、使用C#-WPF实现抽屉效果-菜单导航功能实现,常规的管理系统应该…...
【C#】使用JavaScriptSerializer序列化对象
在C#开发语言编程中,通常使用系统内置的JavaScriptSerializer类来序列化对象,以便将其转换为JSON格式的文本存储与后台服务通信, 在这里将为大家详细介绍一下这个过程。 文章目录 反序列化序列化忽略属性 假设处理的数据中有一个对象类, 如下 public cl…...
HTML静态网页成品作业(HTML+CSS)—— 明星吴磊介绍网页(5个页面)
🎉不定期分享源码,关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 🏷️本套采用HTMLCSS,未使用Javacsript代码,共有5个页面。 二、作品演示 三、代…...
EasyRecovery2024数据恢复神器#电脑必备良品
EasyRecovery数据恢复软件,让你的数据重见天日! 大家好!今天我要给大家种草一个非常实用的软件——EasyRecovery数据恢复软件!你是不是也曾经遇到过不小心删除了重要的文件,或者电脑突然崩溃导致数据丢失的尴尬情况呢&…...
前端HTML相关知识
1.什么是HTML HTML 指的是超文本标记语言 ( HyperText Markup Language )。 超文本:是指页面内可以包含图片、链接、声音,视频等内容 标记:标签(通过标记符号来告诉浏览器网页内容该如何显示) 浏览器根据不同的HTML标签,解析成我们看到的网页 2.HTML的特点 HTML不…...
从怀疑到真香!2026我日常办公离不开的这款在线文字转换器太好用了
刚入职那半年我踩过太多坑:一周三次新人培训,怕漏记知识点全程录音,下课手动整理1小时录音要熬3小时,知识点散得根本没法复习;部门周会做完记录,散会就要我出整理好的纪要,赶工赶得饭都吃不上&a…...
PostgreSQL CASE语句深度解析:性能、类型与NULL安全实战指南
1. 为什么你必须真正吃透 PostgreSQL 的 CASE 语句——它远不止是 SQL 里的“if-else”翻译器在 PostgreSQL 实战中,我见过太多人把CASE当成一个语法糖:写几个WHEN...THEN,加个ELSE,再套个END,就以为搞定了。结果呢&am…...
Shiro RememberMe反序列化漏洞深度解析与实战利用
1. 这个漏洞不是“老古董”,而是理解Java安全边界的活教材很多人看到CVE-2016-4437,第一反应是“Shiro都淘汰了,还讲这个干啥?”——我去年在给一家做政企内部系统的客户做渗透复测时,就遇到过一个上线三年的审批平台&…...
ARM PMU外部接口与性能监控寄存器详解
1. ARM性能监控寄存器外部接口深度解析性能监控单元(PMU)是现代处理器架构中用于硬件性能分析的核心模块,它通过一组可编程计数器实时捕获处理器微架构层面的各类事件。在ARMv8/v9架构中,PMU不仅可以通过系统寄存器访问,还提供了标准化的外部…...
炉石传说自动对战助手:5分钟上手,彻底解放双手的终极指南
炉石传说自动对战助手:5分钟上手,彻底解放双手的终极指南 【免费下载链接】Hearthstone-Script Hearthstone script(炉石传说脚本) 项目地址: https://gitcode.com/gh_mirrors/he/Hearthstone-Script 还在为每天重复的炉石…...
METSO A413248自动化系统
METSO A413248 自动化系统模块产品特点: 品牌归属:芬兰METSO(美卓)工业自动化系统原装备件。 产品类型:工业级自动化控制模块/接口模块。 核心功能:用于控制信号处理、数据采集及系统集成。 系统兼容&am…...
37家金融客户紧急启用的DeepSeek扫描辅助加固包(含未公开API调用密钥策略)
更多请点击: https://kaifayun.com 第一章:DeepSeek漏洞扫描辅助的背景与战略价值 近年来,大模型在安全领域的应用正从辅助问答向深度协同防御演进。DeepSeek系列模型凭借其开源、高推理精度及强代码理解能力,成为构建智能化漏洞…...
告别数据饥荒:用PyTorch手把手实现原型网络(Prototypical Networks)做电影评论情感分类
告别数据饥荒:用PyTorch手把手实现原型网络做电影评论情感分类 在自然语言处理领域,情感分析一直是热门研究方向,但现实中的开发者常面临一个尴尬困境:标注数据太少。传统深度学习方法动辄需要成千上万的标注样本,而实…...
别被忽悠了!2026亲测靠谱的AI论文网站|避坑精选版
2026 年学术写作工具已高度分化,千笔AI与ThouPen为全流程首选,豆包、DeepSeek 为专项强手;避坑关键:拒绝假文献、严控 AIGC 率、优先国内适配、免费试用先行。 一、TOP3 全流程首选(亲测不踩雷) 1. 千笔AI&…...
告别混乱绑定!在UE5 GAS中优雅管理技能输入(基于GameplayTag)
告别混乱绑定!在UE5 GAS中优雅管理技能输入(基于GameplayTag)当你的UE5 RPG项目发展到中期,技能数量从十几个膨胀到几十个时,最痛苦的莫过于发现InputAction绑定已经变成一团乱麻。每次新增技能都要修改输入绑定逻辑&a…...
