当前位置: 首页 > 科技观察

SpringCloud微服务实践

时间:2023-03-16 15:43:26 科技观察

背景随着微服务的流行,基于Spring生态系统的SpringCloud越来越受到关注。SpringCloud专注于提供良好的开箱即用的典型用例和可扩展性覆盖机制。特性分布式/版本化配置服务注册和发现路由服务-到-服务调用负载均衡断路器Springcloud由两个基本模块组成,springcloudcontext和springcloudcommons。springcloudcontext即springcloud应用上下文,包括bootstrapcontext(加载bootstrap配置)、配置加密、配置刷新作用域(RefreshScope)、控制端点(/env/reset、/refresh、/restart等)功能。Springcloudcommons为服务注册发现、负载均衡、断路器等模式提供了通用的抽象层,为具体的现实提供统一的抽象。在实际应用过程中,我们使用springcloudconsul作为服务注册和发现组件,springcloudconfig作为分布式/版本化配置管理,springcloudbus作为消息总线刷新分布式应用配置,springbootadmin作为统一应用监控后台springcloudNetflixfeign作为rest服务调用客户端springcloudNetflixzuul作为路由和过滤网关springcloudconsulConsul是一个使用Go开发的开源服务发现和健康检查工具。Consul还提供K/V存储。使用Consul集群可以很方便的搭建一个高可用的微服务基础设施。Consul还包括一个webui来查看每个服务的状态。在线consul地址:http://consul.nidianwo.com/如下截图:因为consul内置了服务注册发现功能,所以springcloudconsul代码实现起来比较简单。它使用ConsulServiceRegistry进行服务注册操作,使用ConsulDiscoveryClient获取所有服务或up服务,使用ConsulClient请求consul集群内部运行。使用过程中出现问题。当一个服务向多台机器注册时,有时注册的服务会被覆盖。查看源码发现consul应用会在监听应用servlet容器初始化事件后自动注册。注册使用ConsulAutoRegistration对象。里面会有一个NewService对象,通过NewService对象的id可以判断服务的唯一性,NewService的id默认是ApplicationContext对象的id,即应用名加端口加profile,所以同一个应用的id是一样的,所以注册会被覆盖。如果你发现问题,让我们解决问题。添加配置bean覆盖ConsulAutoRegistration对象,id设置为ApplicationContext的id加上机器的ip,保证多台机器的id唯一。@Bean@PrimarypublicConsulAutoRegistrationconsulRegistration(ConsulDiscoveryPropertiesproperties,ApplicationContextapplicationContext,ServletContextservletContext,HeartbeatPropertiesheartbeatProperties){properties.setInstanceId(applicationContext.getId()+"-"+DigestUtils.sha1Hex(properties.getIpAddress()));returnConsul,AutoRegistrationproperties,registration.heartbeatProperties);}ConsulDiscoveryProperties是consul服务发现的配置类。需要注意一些配置,比如preferIpAddress默认为false,即服务的地址默认是通过host注册和校验的,但是当环境不支持host访问时就会出现问题。比如我们线上的阿里云环境,有些机器是不支持主机访问的,所以需要配置preferIpAddress=true。springcloudconfigSpringCloudConfig提供了分布式系统中服务端和客户端的扩展配置。支持不同环境(开发、测试、生产)的配置。Git作为默认的配置后端,支持配置环境的版本标注。springcloudconfig的结构图如下:springcloudconfig包括4个部分a)git配置仓库,存放各个应用环境的配置b)configserver通过@EnableConfigServer提供一个基于资源的HTTP接口来开启配置服务器应用#gitconfigspring.cloud.config。server.git.uri=http://60.191.68.43:19090/config/{application}-config.gitspring.cloud.config.server.git.username=xxxspring.cloud.config.server.git.password=xxxspring。cloud.config.server.git.force-pull=true(这个配置可以在配置仓库冲突的时候强制拉取,不会获取不到最新的配置)上面配置git仓库地址上面配置git仓库地址Configserver以rest的形式提供配置资源,如下图:c)configclient,通过配置的url或者服务发现拉取configserver来配置Configserver开启服务发现后,configclient可以找到configserver通过服务发现我们的config客户端使用consul服务发现找到configserver来拉取配置。默认情况下,ConsulDiscoveryClient获取服务时,根据服务id获取所有服务节点,即获取down服务,导致配置拉取失败。查看consul服务发现的配置类ConsulDiscoveryProperties。发现可以通过配置将默认的queryPassing=false改为true,返回所有健康检查通过的服务。d)springcloudbus分布式应用配置更新通知springcloudbus支持rabbitmq和kafka,因为公司部署了kafka,所以使用kafka作为springcloudbus的消息组件。配置如下:#springcloudbuskafkaspring.cloud.bus.enabled=truespring.cloud.bus.trace.enabled=falsespring.cloud.stream.kafka.binder.zk-nodes=192.168.11.30:2181,192.168.11.33:2181,192.168。11.35:2181spring.cloud.stream.kafka.binder.brokers=192.168.11.30:9092,192.168.11.33:9092,192.168.11.35:9092结构如下:此时SpringCloudBus的配置更新步骤为如下:提交代码,使用gitwebhook触发post请求到bus/refresh。服务器接收请求并将其发送到SpringCloudBus。SpringCloud总线接收消息并通知其他客户端。其他客户端收到通知,请求服务器为所有客户端获取***配置。获取最新配置springbootadminspringbootadmin是springboot应用的监控管理服务,通过服务发现拉取服务列表,通过ApplicationRegistry注册到内部映射或者使用Hazelcast分布式存储。通过扩展zuul的RouteLocator,路由请求到各个应用的springbootactuator端点,返回各个应用的各种指标数据,通过angularjs展示。地址:http://middleware.nidianwo.com/界面如下:可以通过界面。界面如下:通过日志的实时监控,方便观察应用启动状态和实时请求日志,方便调试。springcloudnetfixfeignspringcloudnetflix包含了很多非常有用的微服务组件,如服务发现(Eureka)、断路器(Hystrix)、智能路由(Zuul)和客户端负载均衡(Ribbon)、声明式服务调用客户端(feign)的使用假装很简单。应用主类添加注解@EnableFeignClients(basePackages="com.dianwoba.open.express.service"),并添加服务调用接口类:@FeignClient(name="heimdall",url="${express.open.url}",configuration=RemoteConfiguration.class)publicinterfaceRemoteExpressService{//@Headers({"Content-Type:application/x-www-form-urlencoded","Accept:application/x-www-form-urlencoded"})@RequestMapping(method=RequestMethod.POST,value="/express/api/v1/addModifySite")@ResponseBodyApiResponseaddModifySite(SiteDTOsiteDTO);}Feign内部使用了几个组件来封装请求、调用它们和分析响应。Contract实现上述接口方法的注解解析和请求的封装,Encoder实现上述接口方法的参数解析和请求的组装,Feign.Builder实现核心类feign对象的构建器,Decoder实现响应解析并生成返回对象,Logger实现Logging方法。这些接口有默认实现。默认实现是通过配置类配置的。默认实现为:DecoderfeignDecoder:ResponseEntityDecoder(这是对SpringDecoder的封装)EncoderfeignEncoder:SpringEncoderLoggerfeignLogger:Slf4jLoggerContractfeignContract:SpringMvcContractFeign.BuilderfeignBuilder:HystrixFeign.Builder程序实现过程如下:首先通过@EnableFeignCleints的注解EnableFeignCleint实现接口Feign的规则,并添加@FeignCleint注释。程序启动后,会扫描包,扫描所有@FeignCleint注解的类,并将这些信息注入到ioc容器中。当调用接口的方法时,通过jdk的代理生成具体的RequestTemplate。RequestTemplate生成Request请求,交给Client处理。Client可以是HttpUrlConnection、HttpClient或Okhttp***Client被封装到LoadBalanceClient类中。类和Ribbon的结合实现了负载均衡。springcloudnetfixzuulZuul作为微服务网关,具有动态路由和过滤链功能。基于zuul可以实现:Authentication&认证数据统计服务路由辅助单点压测限流静态响应Zuul通过ZuulhanderMapping实现SrpingMVC的AbstractUrlHandlerMapping,通过RouteLocator获取Route列表,将路由对应的fullPath映射到ZuulController,ZuulController继承了ServletWrappingController,会将相应的请求代理给ZuulServlet,而ZuulServlet是zuul过滤器链的入口。过滤器链分为三种,分别是pre,route,post对应请求执行前的操作,执行请求路由,执行请求返回。可以定制各种过滤器以满足特定要求。使用起来非常简单。在Springboot启动类中添加注解@EnableZuulProxy,开启zuul代理功能。配置zuul.routes.express.path=/express/**zuul.routes.express.serviceId=express-open-apizuul.routes.express.stripPrefix=false请求的不同路径会路由到不同的服务。一些经验认为springcloud微服务组件的使用还是比较简单方便的。通常可以通过在启动类中添加starter依赖、开启switch配置、开启注解等方式使用。在使用过程中可能会遇到一些小问题,但是springboot和springcloud社区都非常支持。活跃,版本迭代很快,问题应该是比较容易解决的,也可以通过解决问题的方式看源码学习相关的设计思路。