找回密码
 会员注册
查看: 30|回复: 0

通过Python+Nacos实现微服务,细解微服务架构

[复制链接]

2万

主题

0

回帖

6万

积分

超级版主

积分
63679
发表于 2024-9-13 14:57:22 | 显示全部楼层 |阅读模式
shigen坚持更新文章的博客写手,擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。记录成长,分享认知,留住感动。个人IP:shigen背景一直以来的想法比较多,然后就用Python编写各种代码脚本。很多的脚本都是通过Python的Flask框架实现,如[file-server],然后部署到云服务器。但是这样只提供一个端口就可以通过http访问,无异于在互联网上裸奔。而且这样的服务有很多个,一直在想如何实现一个统一认证然后就可以访问这么多的服务。在Java领域最常见的设计就是使用微服务架构,把每个服务拆分出来,然后通过网关统一拦截、验证、分发流量。蹭了一张架构图(发现飞书的模板已经很好了):那我的Python服务为什么不能设计成微服务架构呢,当然,还没听说过谁家的Python服务是微服务架构的,姑且一试。代码实现考虑到大家的技术栈就是Java,以下的python代码将省略部分细节。有了之前pythonflask如何注册到nacos踩坑的经验,这次明显顺利的多了。现在本地搭建nacos环境,并支持http访问,推荐docker-compose的方式搭建:shigen/spring-cloud-platform因为我的Nacos版本是2.0+的,官方的nacos-sdk-python是这样描述的:SupportedPythonversion:Python2.7Python3.6Python3.7SupportedNacosversionNacos0.8.0~1.3.2于是就使用的是官方的API:OpenAPI指南我的服务模块是这样细分的:microservices-demo/├──nacos/├──api-gateway/│└──app.py├──user-service/│└──app.py├──auth-service/│└──app.py└──document-service/└──app.py12345678910也就是分成了四个模块:网关、用户中心、鉴权中心、文档中心。接下来就是服务的注册和调用。我们以最简单的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=5002NAMESPACE="python"#发送到Nacos服务注册接口defregister_service():payload={"serviceName":SERVICE_NAME,"ip":SERVICE_IP,"port":SERVICE_PORT,"namespaceId":NAMESPACE,}response=requests.post(f"{NACOS_URL}",params=payload)#每5秒发送一次心跳defsend_heartbeat():whileTrue: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'])defauthenticate():pass#验证token@app.route('/verify',methods=['POST'])defverify_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)12345678910111213141516171819202122232425262728293031323334353637383940414243444546不用尝试读懂代码,很简单:在服务启动的时候注册到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"}'123456其他的几个服务也如法炮制。最终Nacos服务注册表如下:在网关这一块可能稍微有一点区别,复习前面提到的网关的作用:流量的拦截和转发、认证拦截、负载均衡…这里我的网关服务设计如下:NACOS_URL=os.getenv("NACOS_URL","http://localhost:8848/nacos/v1/ns/instance")NAMESPACE="python"defget_service_url(service_name):try:response=requests.get(f"{NACOS_URL}/list?serviceName={service_name}&namespaceId={NAMESPACE}")data=response.json()ifdataanddata['hosts']:service=data['hosts'][0]#returnf"http://{service['ip']}:{service['port']}"#这里是本机调用测试returnf"http://localhost:{service['port']}"exceptExceptionase:print(f"ErrorgettingserviceURL:{e}")returnNone@app.route('// ',methods=['GET','POST','PUT','DELETE'])defproxy(service_name,path):service_url=get_service_url(service_name)ifnotservice_url:returnjsonify({"error":"Servicenotfound"}),404#认证逻辑ifservice_name!="auth-service":token=request.headers.get("Authorization")ifnottoken:returnjsonify({"error":"Missingtoken"}),401auth_url=get_service_url("auth-service")ifnotauth_url:returnjsonify({"error":"Authservicenotfound"}),500verify_response=requests.post(f"{auth_url}/verify",json={"token":token})ifverify_response.status_code!=200:returnjsonify({"error":"Invalidtoken"}),401url=f"{service_url}/{path}"response=requests.request(method=request.method,url=url,headers={key:valueforkey,valueinrequest.headersifkey!='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)123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657这里其实就是请求来了之后,从nacos上拉取服务列表。这个服务列表就是服务名称和对应的服务所在机器的IP(service-name和对应的IP集合)。然后选取对应服务所在的机器之一作为目标机器(这里选用的是第一台机器),从请求头中获得token,进行验证和调用。token校验失败则打给认证服务,重新进行登录验证。为此,我还对比了一下SpringCloud+Nacos的设计:Nacos的API实现的是springframework.cloud.client.discovery的接口,意味着统一的标准:packagecom.alibaba.cloud.nacos.discovery;publicclassNacosDiscoveryClientimplementsDiscoveryClient{privatestaticfinalLoggerlog=LoggerFactory.getLogger(NacosDiscoveryClient.class);/***NacosDiscoveryClientDescription.*/publicstaticfinalStringDESCRIPTION="SpringCloudNacosDiscoveryClient";privateNacosServiceDiscoveryserviceDiscovery;publicNacosDiscoveryClient(NacosServiceDiscoverynacosServiceDiscovery){this.serviceDiscovery=nacosServiceDiscovery;}@OverridepublicStringdescription(){returnDESCRIPTION;}@OverridepublicListgetInstances(StringserviceId){try{returnserviceDiscovery.getInstances(serviceId);}catch(Exceptione){thrownewRuntimeException("Cannotgethostsfromnacosserver.serviceId:"+serviceId,e);}}@OverridepublicListgetServices(){try{returnserviceDiscovery.getServices();}catch(Exceptione){log.error("getservicenamefromnacosserverfail,",e);returnCollections.emptyList();}}}123456789101112131415161718192021222324252627282930313233343536373839404142434445其中的serviceName和serviceId其实是同一概念,意味着我们可以通过服务名获得全部的部署服务的实例信息,实现自定义的负载均衡调用。这里的原理和我直接从Nacos的API中获得服务列表,默认选取第一台机器进行调用的设计如出一辙。对于以上的Python代码段,可能文字描述有不详细或者不当之处,借助魔法进行进一步的完善:这段代码实现了一个反向代理服务器,其主要功能是根据服务名称将请求转发到不同的服务,并在转发前进行认证。具体功能如下:服务发现:代码通过访问NACOS(一个服务发现和配置管理平台)来获取目标服务的URL。NACOS提供了服务注册和发现的功能,代码中通过get_service_url(service_name)函数实现这一功能。请求转发:当接收到一个请求时,根据URL中的service_name和path,代码会将请求转发到相应的目标服务。转发时,保留了原始请求的HTTP方法、头信息、数据和cookies。认证检查:对于非auth-service的请求,代码会检查请求头中是否包含Authorizationtoken。如果没有token或token无效,则会返回错误响应。具体步骤如下:检查请求头中是否包含Authorizationtoken。如果没有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"}'123456服务调用curl--location'http://127.0.0.1:8080/document-service/documents'\--header'Authorization:xxx'12总结之前微服务的开发中,可能我们借助SpringCloud部分组件、Nacos,在项目中加上依赖配置,稍微改一下配置文件,服务就可以正常的调用了。其中依赖的SDK如何的工作,可能只是停留在理论上,缺少实操。这次的这个案例很好的展示Python+Nacos如何实现微服务,并从中细解微服务结构和服务之间的调用原理。是不是觉得Nacos其实也不过如此哈,没什么牛掰、独特之处,其实都是草台班子。与shigen一起,每天不一样!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2024-12-25 13:12 , Processed in 0.478385 second(s), 26 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表