springCloud-LoadBalancer负载均衡微服务负载均衡器LoadBalancer

这篇具有很好参考价值的文章主要介绍了springCloud-LoadBalancer负载均衡微服务负载均衡器LoadBalancer。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

2020年前SpringCloud是采用Ribbon作为负载均衡实现,但是在2020后采用了LoadBalancer替代

LoadBalancer默认提供了两种负载均衡策略(只能通过配置类来修改负载均衡策略)

1.RandomLoadBalancer-随机分配策略
2.RoundRobinLoadBalancer-轮询分配策略(默认)

添加一个自定义的负载均衡策略CustomLoadBalancerConfiguration 配置类,可以直接复制官网

package com.test.order.config;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.RandomLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;

//无需添加@Component
public class CustomLoadBalancerConfiguration {

    @Bean
    ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(Environment environment,
                                                            LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new RandomLoadBalancer(loadBalancerClientFactory
                .getLazyProvider(name, ServiceInstanceListSupplier.class),
                name);
    }
}

注意如果负载均衡策略配置类使用spring注解@ComponentScan或者@Configuration,就要注意如果被SpringBootApplication的ComponentScan扫描到(默认扫描SpringBootApplication目录下的全部包),就会变成全局的负载均衡策略,如果需要局部负载均衡最好不用注解,或者设置不被默认的ComponentScan扫描到

在启动类配置那个微服务使用那种负载均衡策略(如果有Ribbon负载均衡需要在yml负载均衡去掉,一般在2020版本后无需配置去掉,因为默认没有Ribbon)

@SpringBootApplication
//@LoadBalancerClients(defaultConfiguration={CustomLoadBalancerConfiguration.class})
//value的值表示需要负载均衡的微服务,调用指定的负载均衡策略
//@LoadBalancerClient(value = "stock-nacos",configuration = {CustomLoadBalancerConfiguration.class})
//@LoadBalancerClients({@LoadBalancerClient(value = "stock-nacos", configuration = {CustomLoadBalancerConfiguration.class}),@LoadBalancerClient(value = "stock-nacos2", configuration = {CustomLoadBalancerConfiguration2.class})})
@LoadBalancerClients({@LoadBalancerClient(value = "stock-nacos", configuration = {CustomLoadBalancerConfiguration.class})})
public class OrderLoadbalancerApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderLoadbalancerApplication.class, args);
    }

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        RestTemplate restTemplate = builder.build();
        return restTemplate;
    }
}

pom.xml配置(因为spring-cloud-starter-alibaba-nacos-discovery依赖中的spring-cloud-starter-loadbalancer的true,所以不会继承,需要收到继承),如下

springcloud loadbalancer配置,spring cloud,负载均衡,微服务文章来源地址https://www.toymoban.com/news/detail-852180.html

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
    </dependencies>

父pom.xml配置

    <dependencyManagement>
        <!--Spring Cloud alibaba的版本管理,通过dependency完成继承-->
        <dependencies>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2021.0.4.0</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>2021.0.4</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

遇到问题,点击spring-cloud-dependencies进不去查看pom文件,就是下载的pom有问题,可以都删除掉org.springframework.cloud目录下的文件,再重新刷新下载

Loadbalancer实现自定义负载均衡

定义负载均衡方式的枚举

public enum LoadBalancerTypeEnum {

    /**
     * 开发环境,获取自己的服务
     */
    DEV,

    /**
     * 网关,根据请求地址获取对应的服务
     */
    GATEWAY,

    /**
     * 轮循
     */
    ROUND_ROBIN,

    /**
     * 随机
     */
    RANDOM;

}

添加配置类,默认使用轮训方式

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * 负载均衡配置项
 */
@Data
@ConfigurationProperties(prefix = "spring.cloud.loadbalancer")
public class LoadBalanceProperties {

    private LoadBalancerTypeEnum type = LoadBalancerTypeEnum.ROUND_ROBIN;

}

在自定义的类中,我们实现了四种负载均衡策略

    1、getRoundRobinInstance方法是直接复制的RoundRobinLoadBalancer类中的实现;

    2、getRandomInstance方法参考org.springframework.cloud.loadbalancer.core.RandomLoadBalancer类中的实现;

    3、getDevelopmentInstance方法是返回所有服务中和当前机器ip一致的服务,如果没有,则轮训返回;

    4、getGatewayDevelopmentInstance方法是返回所有服务中和网关请求头中ip一致的服务。
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.TypeReference;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.utils.ip.IpUtils;
import com.ruoyi.common.loadbalance.config.LoadBalancerTypeEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.DefaultRequest;
import org.springframework.cloud.client.loadbalancer.DefaultResponse;
import org.springframework.cloud.client.loadbalancer.EmptyResponse;
import org.springframework.cloud.client.loadbalancer.Request;
import org.springframework.cloud.client.loadbalancer.RequestData;
import org.springframework.cloud.client.loadbalancer.RequestDataContext;
import org.springframework.cloud.client.loadbalancer.Response;
import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
import org.springframework.cloud.loadbalancer.core.SelectedInstanceCallback;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.http.HttpHeaders;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 自定义 SpringCloud 负载均衡算法
 * 负载均衡算法的默认实现是 {@link org.springframework.cloud.loadbalancer.core.RoundRobinLoadBalancer}
 *
 */
@Slf4j
public class CustomSpringCloudLoadBalancer implements ReactorServiceInstanceLoadBalancer {

    private final String serviceId;
    private final AtomicInteger position;
    private final LoadBalancerTypeEnum type;
    private final ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;

    public CustomSpringCloudLoadBalancer(String serviceId,
                                         LoadBalancerTypeEnum type,
                                         ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider) {
        this(serviceId, new Random().nextInt(1000), type, serviceInstanceListSupplierProvider);
    }

    public CustomSpringCloudLoadBalancer(String serviceId,
                                         int seedPosition,
                                         LoadBalancerTypeEnum type,
                                         ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider) {
        this.serviceId = serviceId;
        this.position = new AtomicInteger(seedPosition);
        this.type = type;
        this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
    }

    @Override
    public Mono<Response<ServiceInstance>> choose(Request request) {
        ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);
        return supplier.get(request).next().map(serviceInstances -> processInstanceResponse(request, supplier, serviceInstances));
    }

    private Response<ServiceInstance> processInstanceResponse(Request request,
                                                              ServiceInstanceListSupplier supplier,
                                                              List<ServiceInstance> serviceInstances) {
        Response<ServiceInstance> serviceInstanceResponse = getInstanceResponse(request, serviceInstances);
        if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) {
            ((SelectedInstanceCallback) supplier).selectedServiceInstance(serviceInstanceResponse.getServer());
        }
        return serviceInstanceResponse;
    }

    private Response<ServiceInstance> getInstanceResponse(Request request, List<ServiceInstance> instances) {
        if (instances.isEmpty()) {
            if (log.isWarnEnabled()) {
                log.warn("No servers available for service: " + serviceId);
            }
            return new EmptyResponse();
        }

        if (Objects.equals(type, LoadBalancerTypeEnum.ROUND_ROBIN)){
            return this.getRoundRobinInstance(instances);
        }else if (Objects.equals(type, LoadBalancerTypeEnum.RANDOM)){
            return this.getRandomInstance(instances);
        }else if (Objects.equals(type, LoadBalancerTypeEnum.DEV)){
            return this.getDevelopmentInstance(instances);
        }else if (Objects.equals(type, LoadBalancerTypeEnum.GATEWAY)){
            return this.getGatewayDevelopmentInstance(request, instances);
        }
        return this.getRoundRobinInstance(instances);
    }

    /**
     * 获取网关本机实例
     *
     * @param instances 实例
     * @return {@link Response }<{@link ServiceInstance }>
     * @author : lwq
     * @date : 2022-12-15 14:22:13
     */
    private Response<ServiceInstance> getGatewayDevelopmentInstance(Request request, List<ServiceInstance> instances) {

        //把request转为默认的DefaultRequest,从request中拿到请求的ip信息,再选择ip一样的微服务
        DefaultRequest<RequestDataContext> defaultRequest = Convert.convert(new TypeReference<DefaultRequest<RequestDataContext>>() {}, request);
        RequestDataContext context = defaultRequest.getContext();
        RequestData clientRequest = context.getClientRequest();
        HttpHeaders headers = clientRequest.getHeaders();
        String requestIp = IpUtils.getIpAddressFromHttpHeaders(headers);
        log.debug("客户端请求gateway的ip:{}", requestIp);

        //先取得和本地ip一样的服务,如果没有则按默认来取
        for (ServiceInstance instance : instances) {
            String currentServiceId = instance.getServiceId();
            String host = instance.getHost();
            log.debug("注册服务:{},ip:{}", currentServiceId, host);
            if (StringUtils.isNotEmpty(host) && StringUtils.equals(requestIp, host)) {
                return new DefaultResponse(instance);
            }
        }
        return getRoundRobinInstance(instances);
    }


    /**
     * 获取本机实例
     *
     * @param instances 实例
     * @return {@link Response }<{@link ServiceInstance }>
     * @author : lwq
     * @date : 2022-12-15 14:22:13
     */
    private Response<ServiceInstance> getDevelopmentInstance(List<ServiceInstance> instances) {
        //获取本机ip
        String hostIp = IpUtils.getHostIp();
        log.debug("本机Ip:{}", hostIp);

        //先取得和本地ip一样的服务,如果没有则按默认来取
        for (ServiceInstance instance : instances) {
            String currentServiceId = instance.getServiceId();
            String host = instance.getHost();
            log.debug("注册服务:{},ip:{}", currentServiceId, host);
            if (StringUtils.isNotEmpty(host) && StringUtils.equals(hostIp, host)) {
                return new DefaultResponse(instance);
            }
        }
        return getRoundRobinInstance(instances);
    }

    /**
     * 使用随机算法
     * 参考{link {@link org.springframework.cloud.loadbalancer.core.RandomLoadBalancer}}
     *
     * @param instances 实例
     * @return {@link Response }<{@link ServiceInstance }>
     * @author : lwq
     * @date : 2022-12-15 13:32:11
     */
    private Response<ServiceInstance> getRandomInstance(List<ServiceInstance> instances) {
        int index = ThreadLocalRandom.current().nextInt(instances.size());
        ServiceInstance instance = instances.get(index);
        return new DefaultResponse(instance);
    }

    /**
     * 使用RoundRobin机制获取节点
     *
     * @param instances 实例
     * @return {@link Response }<{@link ServiceInstance }>
     * @author : lwq
     * @date : 2022-12-15 13:28:31
     */
    private Response<ServiceInstance> getRoundRobinInstance(List<ServiceInstance> instances) {
        // 每一次计数器都自动+1,实现轮询的效果
        int pos = this.position.incrementAndGet() & Integer.MAX_VALUE;
        ServiceInstance instance = instances.get(pos % instances.size());
        return new DefaultResponse(instance);
    }

}

其中的工具类如下

import java.net.InetAddress;
import java.net.URL;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Objects;
import javax.servlet.http.HttpServletRequest;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.URLUtil;
import org.springframework.http.HttpHeaders;

/**
 * 获取IP方法
 */
public class IpUtils{

    /**
     * 获取IP地址
     *
     * @return 本地IP地址
     */
    public static String getHostIp(){
        try{
            return InetAddress.getLocalHost().getHostAddress();
        }catch (UnknownHostException e){
        }
        return "127.0.0.1";
    }

    /**
     * 获取客户端IP
     *
     * @param httpHeaders 请求头
     * @return IP地址
     */
    public static String getIpAddressFromHttpHeaders(HttpHeaders httpHeaders){
        if (httpHeaders == null){
            return "unknown";
        }
        //前端请求自定义请求头,转发到哪个服务
        List<String> ipList = httpHeaders.get("forward-to");
        String ip = CollectionUtil.get(ipList, 0);
        //请求自带的请求头
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
            ipList = httpHeaders.get("x-forwarded-for");
            ip = CollectionUtil.get(ipList, 0);
        }
        //从referer获取请求的ip地址
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
            //从referer中获取请求的ip地址
            List<String> refererList = httpHeaders.get("referer");
            String referer = CollectionUtil.get(refererList, 0);
            URL url = URLUtil.url(referer);
            if (Objects.nonNull(url)){
                ip = url.getHost();
            }else {
                ip = "unknown";
            }
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
            ipList = httpHeaders.get("Proxy-Client-IP");
            ip = CollectionUtil.get(ipList, 0);
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
            ipList = httpHeaders.get("X-Forwarded-For");
            ip = CollectionUtil.get(ipList, 0);
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
            ipList = httpHeaders.get("WL-Proxy-Client-IP");
            ip = CollectionUtil.get(ipList, 0);
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){
            ipList = httpHeaders.get("X-Real-IP");
            ip = CollectionUtil.get(ipList, 0);
        }
        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : getMultistageReverseProxyIp(ip);
    }
}

配置负载均衡策略

import com.ruoyi.common.loadbalance.core.CustomSpringCloudLoadBalancer;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

/**
 * 自定义负载均衡客户端配置
 *
 */
@SuppressWarnings("all")
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(LoadBalanceProperties.class)
public class CustomLoadBalanceClientConfiguration {

    @Bean
    @ConditionalOnBean(LoadBalancerClientFactory.class)
    public ReactorLoadBalancer<ServiceInstance> customLoadBalancer(LoadBalanceProperties loadBalanceProperties,
                                                                   Environment environment,
                                                                   LoadBalancerClientFactory loadBalancerClientFactory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new CustomSpringCloudLoadBalancer(name, loadBalanceProperties.getType(),
                loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class));
    }

}

使用LoadBalancerClients注解加载一下配置

@SpringBootApplication
@EnableFeignClients
//全局
//@LoadBalancerClients(defaultConfiguration = CustomLoadBalanceClientConfiguration.class)
//指定
@LoadBalancerClients({@LoadBalancerClient(value = "stock-nacos", configuration = {CustomLoadBalanceClientConfiguration .class})})
public class OrderOpenFeignApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderOpenFeignApplication.class, args);
    }
}

在配置文件配置

 #调用自己本地开发环境的微服务
 spring.cloud.loadbalancer.type=dev
 #在网关中配置如下即可实现调用固定某个服务
 spring.cloud.loadbalancer.type=gateway

版本链接对应

到了这里,关于springCloud-LoadBalancer负载均衡微服务负载均衡器LoadBalancer的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • SpringCloud - 新版淘汰 Ribbon,在 OpenFeign 中整合 LoadBalancer 负载均衡

    目录 一、LoadBalancer 负载均衡 1.1、前言 1.2、LoadBalancer 负载均衡底层实现原理 二、整合 OpenFeign + LoadBalancer 2.1、所需依赖 2.2、具体实现  2.3、自定义负载均衡策略 在 2020 年以前的 SpringCloud 采用 Ribbon 作为负载均衡,但是 2020 年之后,SpringCloud 吧 Ribbon 移除了,而是使用自己编

    2024年02月03日
    浏览(46)
  • SpringCloud Alibaba集成 Gateway(自定义负载均衡器)、Nacos(配置中心、注册中心)、Loadbalancer

    路由(route):路由是网关最基础的部分,路由信息由一个ID,一个目的URL、一组断言工厂和一 组Filter组成。如果断言为真,则说明请求URL和配置的路由匹配。 断言(Predicate):Java8中的断言函数,Spring Cloud Gateway中的断言函数输入类型是 Spring5.0框架中的ServerWebExchange。Sprin

    2024年04月12日
    浏览(48)
  • 微服务之LoadBalancer负载均衡服务调用

    LB,既负载均衡(Load Balancer),是高并发、高可用系统必不可少的关键组件,其目标是尽力将网络流量平均分发到多个服务器上,以提高系统整体的响应速度和可用性。 负载均衡的主要作用 高并发 :负载均衡通过算法调整负载,尽力均匀的分配应用集群中的各结点的工作量。

    2024年04月15日
    浏览(50)
  • Spring Cloud Alibaba全家桶(三)——微服务负载均衡器Ribbon与LoadBalancer

    本文为 微服务负载均衡器Ribbon与LoadBalancer 相关知识,下边将对 什么是Ribbon (包括: 客户端的负载均衡 、 服务端的负载均衡 、 常见负载均衡算法 ), Nacos使用Ribbon , Ribbon内核原理 (包括: Ribbon原理 , Ribbon负载均衡策略 , 饥饿加载 ), Spring Cloud LoadBalancer (包括:

    2024年02月02日
    浏览(33)
  • 负载均衡 LoadBalancer

    负载均衡 负载均衡一般分为 服务端负载均衡 和 客户端负载均衡 服务端负载均衡: 指在服务器端进行负载均衡的策略。在这种策略下,负载均衡器位于服务器端(如 Nginx),当客户端发起服务调用时,根据服务器的负载情况,将请求分发到不同的服务器上,以实现请求的均

    2024年01月17日
    浏览(52)
  • springcloud Ribbon负载均衡服务调用

    地址:https://github.com/13thm/study_springcloud/tree/main/days6_Ribbon Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端 负载均衡的工具。 简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法和服务调用。Ribbon客户端组件提供一系列完善的配置项如连接超时

    2024年01月20日
    浏览(41)
  • 客户端负载均衡策略:loadBalancer,ribbon

    客户端负载均衡是指在分布式系统中,客户端通过某种策略将请求分发到多个服务提供者实例上,以达到负载均衡和提高系统的可用性和性能。 在 Java 生态系统中,Ribbon 是一个常用的客户端负载均衡框架,它是 Netflix 开源的一部分,被广泛应用于 Spring Cloud 中。Ribbon 提供了

    2024年02月08日
    浏览(40)
  • 【微服务 SpringCloud】实用篇 · Ribbon负载均衡

    微服务(4) 在前面,我们添加了@LoadBalanced注解,即可实现负载均衡功能,这是什么原理、什么策略呢? SpringCloud底层其实是利用了一个名为 Ribbon 的组件 ,来实现负载均衡功能的。 那么我们发出的请求明明是http://userservice/user/1,怎么变成了http://localhost:8081的呢? 为什么我

    2024年02月08日
    浏览(41)
  • Spring Cloud LoadBalancer 负载均衡策略与缓存机制

    目录 1. 什么是 LoadBalancer ? 2. 负载均衡策略的分类 2.1 常见的负载均衡策略 3. 为什么要学习 Spring Cloud Balancer ? 4. Spring Cloud LoadBalancer 内置的两种负载均衡策略 4.1 轮询负载均衡策略(默认的) 4.2 随机负载均衡策略 4.2.1 创建随机负载均衡策略  4.2.2 设置随机负载均衡策略

    2024年01月21日
    浏览(48)
  • MetalLB:本地Kubernetes集群的LoadBalancer负载均衡利器

    在本地集群进行测试时,我们常常面临一个棘手的问题:Service Type不支持LoadBalancer,而我们只能选择使用NodePort作为替代。这种情况下,我们通常会配置Service为NodePort,并使用externalIPs将流量导入Kubernetes环境。然而,这些解决方案都存在明显的缺陷,使得在私有环境部署Kube

    2024年02月03日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包