
2024好事发生
今日推荐:CSS 思考『CSS in JS』 or 『JS in CSS』 ?
文章链接:https://cloud.tencent.com/developer/article/2180464
这是个很好的命题,但作者写得稀烂。不过不妨碍我输出个人观点,首先国内响应式需求其实很低,其次私有化和外包化场景极多,这类样式实现方案更加的贴近实际的项目 less mixins 搭配 css vars 这种模式。推荐给各位同学
随着微服务架构的广泛应用,服务的动态管理和监控变得尤为重要。在微服务架构中,服务的上下线是一个常见的操作,如何实时感知这些变化,确保系统的稳定性和可靠性,成为了一个关键技术挑战。本文将深入探讨微服务上下线动态感知的实现方式,从技术基础、场景案例、解决思路和底层原理等多个维度进行阐述,并分别使用Java和Python进行演示介绍。
某业务系统采用Spring Boot和Spring Cloud框架,服务发布流程中经常遇到以下问题:
在云原生环境下,某客户在生产环境中使用Spring Cloud应用时,发现发布过程中出现了大量错误,如ServiceUnavailable。分析后发现,问题的根源在于某些消费者未能及时收到提供者的下线通知,导致请求仍然被发送到已下线的服务实例。
针对上述场景,我们需要实现微服务的优雅上下线,确保服务在上下线过程中不会中断现有请求,并能及时通知调用方更新服务列表。以下是解决这些问题的关键思路:
/offline接口,用于接收主动注销的通知。在K8s的Prestop钩子中触发该接口,实现服务提前注销。服务注册与发现是微服务架构中实现服务动态感知的基础。常见的服务注册中心有Eureka、Consul、Nacos等。
当一个新的微服务实例启动时,它会向服务注册中心注册自己的信息,包括服务名称、IP地址、端口号等。这些信息将被存储在注册中心的目录中,供其他服务查询。
其他服务实例通过查询注册中心,可以获取到目标服务的地址信息,从而实现服务的调用。注册中心通常提供RESTful API或客户端库,方便服务实例进行查询。
已注册的服务实例会定期向注册中心发送心跳包,以表明自己仍然存活。如果注册中心在一定时间内未收到某个服务实例的心跳包,将认为该实例已经下线,并将其从注册列表中移除。
当服务注册中心感知到服务的上下线变化时,会通过事件通知机制及时通知订阅了该服务的其他微服务实例。这样,订阅者可以实时更新自己的本地缓存或服务列表,确保服务调用的准确性。
GracefulServiceRegistration组件,负责触发预热逻辑和服务注册。WarmUp接口用于定义预热逻辑,业务方可以实现该接口并注册到Spring容器中。GracefulServiceRegistration组件取消注册,并标记服务为下线状态。InvokePlugin插件检查服务状态,如果服务处于下线中,则直接返回下线标记。/offline接口用于接收主动注销的通知。curl http://localhost:20001/offline触发主动注销。Zookeeper作为一种分布式协调服务,也可以用于实现微服务的动态感知。通过Zookeeper的watch机制,可以实时监控服务节点的变化。
Spring Cloud提供了对Eureka的集成支持,使得在Spring Boot应用中实现服务注册与发现变得非常简单。
pom.xml文件中引入Spring Cloud Starter Netflix Eureka Client依赖。application.yml或application.properties文件中配置Eureka客户端的相关属性,如服务名称、Eureka服务器地址等。@EnableEurekaClient注解,启用Eureka客户端功能。在Kubernetes中,可以使用Prestop钩子在容器停止之前执行一些清理或通知操作。这对于实现微服务的无损下线非常有用。
/offline接口或向注册中心发送取消注册请求来实现。以下是一个使用Java和Spring Cloud Eureka实现微服务上下线动态感知的示例。
xml复制代码
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>yaml复制代码
spring:
application:
name: demo-service
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
lease-renewal-interval-in-seconds: 5 # 心跳间隔时间
lease-expiration-duration-in-seconds: 15 # 服务失效时间java复制代码
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class DemoServiceApplication {
public static void main(String[] args) {
SpringApplication.run(DemoServiceApplication.class, args);
}
}java复制代码
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class DemoController {
@GetMapping("/hello")
public String hello() {
return "Hello from Demo Service!";
}
}如果没有现成的Eureka服务器,可以创建一个Spring Boot项目并配置Eureka服务器。
yaml复制代码
server:
port: 8761
eureka:
client:
register-with-eureka: false
fetch-registry: false
spring:
application:
name: eureka-server在启动类上添加@EnableEurekaServer注解:
java复制代码
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}启动Eureka服务器和DemoServiceApplication,访问Eureka控制台(通常是http://localhost:8761),应该能够看到demo-service已经注册成功。访问http://localhost:<port>/hello(<port>是demo-service的端口),应该能够看到返回的“Hello from Demo Service!”。
现在,当你启动或停止demo-service实例时,Eureka服务器会实时地感知到这一变化,并更新其注册列表。其他微服务可以通过Eureka服务器查询最新的服务地址信息,从而实现动态的服务发现和调用。
以下是一个使用Python和Consul实现微服务上下线动态感知的示例。
首先,需要安装python-consul库:
bash复制代码
pip install python-consulpython复制代码
import consul
import time
import random
# 连接到Consul代理
c = consul.Consul(host='127.0.0.1', port=8500)
# 注册服务
def register_service(name, port):
c.agent.service.register(name, service_id=f"{name}_{port}", address='127.0.0.1', port=port, check={
'ttl': '10s'
})
# 模拟服务运行
def run_service(name, port):
register_service(name, port)
try:
while True:
print(f"{name} is running on port {port}")
time.sleep(random.randint(1, 10))
except KeyboardInterrupt:
deregister_service(name, port)
# 注销服务
def deregister_service(name, port):
c.agent.service.deregister(f"{name}_{port}")
if __name__ == "__main__":
service_name = "demo-service"
service_port = 8080
run_service(service_name, service_port)python复制代码
import consul
import requests
# 连接到Consul代理
c = consul.Consul(host='127.0.0.1', port=8500)
# 发现服务
def discover_services(service_name):
index, services = c.catalog.service(service_name)
return [(service['Address'], service['ServicePort']) for service in services]
# 调用服务
def call_service(service_name):
services = discover_services(service_name)
if not services:
print(f"No available instances of {service_name}")
return
address, port = random.choice(services)
url = f"http://{address}:{port}/hello"
response = requests.get(url)
print(f"Called {url}, response: {response.text}")
if __name__ == "__main__":
service_name = "demo-service"
call_service(service_name)在上面的示例中,我们首先注册了一个名为demo-service的服务,并模拟了其运行过程。然后,我们编写了一个发现服务的函数discover_services,用于查询Consul中的服务实例。最后,我们编写了一个调用服务的函数call_service,它随机选择一个可用的服务实例并发送HTTP GET请求。
微服务上下线动态感知是微服务架构中一个非常重要的功能,它确保了系统的可用性和负载均衡。通过服务注册与发现机制、心跳机制、事件通知机制以及优雅上下线策略的实现,我们可以有效地感知和处理服务的上下线变化。同时,结合Zookeeper、Spring Cloud与Eureka、Consul等技术和工具,我们可以更加灵活地构建和管理微服务系统。在未来的发展中,随着技术的不断进步和应用场景的不断拓展,微服务上下线动态感知的实现方式也将更加多样化和智能化。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。