Python 官方文档:入门教程 => 点击学习
目录一、简介1. 是什么2. 负载均衡2.1 集中式LB2.2 进程内LB二、实验1. RestTemplate1.1 加入到ioc容器1.2 RestTemplate 远程调用1.
Ribbon集成在spring-cloud-starter-netflix-eureka-client中,可以参考eureka的使用。在此基础上简单修改一下,就可以完成服务调用及负载均衡
首先,将其加入到IOC容器中。@LoadBalanced表示开启负载均衡。
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
@Slf4j
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
RestTemplate restTemplate; // 在ioc容器中获取
@Value("${payment.url}")
String paymentUrl; // 远程调用的URL,保存在配置文件中,解耦
@GetMapping("/payment/get/{id}")
public CommonResult<Payment> getPaymentById(@PathVariable("id") Long id) {
CommonResult<Payment> result = restTemplate.getForObject(paymentUrl + "/payment/get/" + id, CommonResult.class); // get方法调用,并且返回封装成 CommonResult 类型
log.info("Order 查询 Payment,id:" + id);
return result;
}
}
也可以使用getForEntity()方法,获取整个响应,自己在响应中获取想要的内容。
@GetMapping("/payment/getEntity/{id}")
public CommonResult<Payment> getPaymentEntityById(@PathVariable("id") Long id) {
ResponseEntity<CommonResult> entity = restTemplate.getForEntity(paymentUrl + "/payment/get/" + id, CommonResult.class);
log.info("获取到的信息是:" + entity.toString());
log.info("获取到的StatusCode是:" + entity.getStatusCode());
log.info("获取到的StatusCodeValue是:" + entity.getStatusCodeValue());
log.info("获取到的Headers是:" + entity.getHeaders());
if (entity.getStatusCode().is2xxSuccessful()) {
log.info("查询成功:" + id);
return entity.getBody();
} else {
log.info("查询失败:" + id);
return new CommonResult<>(CommonResult.FailURE, "查询失败");
}
}
如果使用post方法,就将get改成post就好了。
url,可以写具体的地址,表示直接调用该地址;也可以写在eureka的服务名,首先在eureka中获取该服务的所有地址,再通过LB选择一个。
payment:
url: "http://CLOUD-PAYMENT-SERVICE"
上面通过@LoadBalanced开启了负载均衡。默认使用轮询算法,也可以修改成其他算法。
Class | 算法 |
---|---|
com.netflix.loadbalancer.RoundRobinRule | 轮询,默认算法 |
com.netflix.loadbalancer.RandomRule | 随机算法,通过产生随机数选择服务器 |
com.netflix.loadbalancer.RetryRule | 先按照RoundRobinRule的策略获取服务,如果获取服务失败则在指定时间内会进行重试,获取可用的服务 |
WeightedResponseTimeRule | 对RoundRobinRule的扩展,响应速度越快的实例选择权重越大,越容易被选择 |
BestAvailableRule | 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务 |
AvailabilityFilteringRule | 先过滤掉故障实例,再选择并发较小的实例 |
ZoneAvoidanceRule | 默认规则,复合判断server所在区域的性能和server的可用性选择服务器 |
如果想让该算法只针对某个服务,则不能将其放在ComponentScan够得到的地方,否则会修改所有服务的负载均衡算法。因此,最好在外面再新建一个package,用来放这个LB
@Configuration
public class MyRule {
@Bean
public IRule rule() {
return new RandomRule();
}
}
在主启动类上,标识一下服务与算法直接的映射关系
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE", configuration = MyRule.class)
public class OrderApplication80 {
public static void main(String[] args) {
SpringApplication.run(OrderApplication80.class, args);
}
}
如果嫌这种方法麻烦,也可以使用配置文件的方法
CLOUD-PAYMENT-SERVICE: # 服务名称
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 算法选择
以默认的RoundRobinRule作为阅读的源码,其他的源码基本上很类似,只是修改的选择服务器的代码。
public interface IRule {
Server choose(Object var1); // 选择服务器,最重要的方法
void setLoadBalancer(ILoadBalancer var1);
ILoadBalancer getLoadBalancer();
}
基本没什么作用,只是将公共的部分提取了出来进行实现。
public abstract class AbstractLoadBalancerRule implements IRule, IClientConfigAware {
private ILoadBalancer lb; // ILoadBalancer接口,主要的功能就是获取当前服务器的状态、数量等,为负载均衡算法提供计算的参数
public AbstractLoadBalancerRule() {
}
public void setLoadBalancer(ILoadBalancer lb) {
this.lb = lb;
}
public ILoadBalancer getLoadBalancer() {
return this.lb;
}
}
简单来说,就是通过一个计数器,实现了轮询
public class RoundRobinRule extends AbstractLoadBalancerRule {
private AtomicInteger nextServerCyclicCounter; // 原子类,用来保存一个计数,记录现在轮询到哪了
private static final boolean AVAILABLE_ONLY_SERVERS = true;
private static final boolean ALL_SERVERS = false;
private static Logger log = LoggerFactory.getLogger(RoundRobinRule.class);
public RoundRobinRule() {
this.nextServerCyclicCounter = new AtomicInteger(0); // 初始化
}
public RoundRobinRule(ILoadBalancer lb) { // 设置LoadBalancer
this();
this.setLoadBalancer(lb);
}
public Server choose(ILoadBalancer lb, Object key) { // 最重要的方法,选择服务器并返回
// 下面贴出来
}
private int incrementAndGetModulo(int modulo) { // 对计数器进行修改,并返回一个选择值,是轮询算法的实现
// 下面贴出来
}
public Server choose(Object key) { // 接口的方法,在该类中调用了另一个方法实现
return this.choose(this.getLoadBalancer(), key);
}
public void initWithNiwsConfig(IClientConfig clientConfig) {}
}
简单来说,该方法就是根据目前的状态,选择一个服务器返回。
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) { // 如果没有LoadBalancer,那就不白费功夫了
log.warn("no load balancer");
return null;
} else {
Server server = null;
int count = 0;
while(true) {
if (server == null && count++ < 10) { // 尝试十次,如果还找不到server就放弃了
List<Server> reachableServers = lb.getReachableServers(); // 通过LB获取目前所有可获取的服务器
List<Server> allServers = lb.getAllServers(); // 获取实际上的所有服务器
int upCount = reachableServers.size(); // 获取目前可获得的服务器数量
int serverCount = allServers.size(); // 所有服务器的数量,这是取余的除数
if (upCount != 0 && serverCount != 0) { // 如果目前有服务器且服务器可用
int nextServerIndex = this.incrementAndGetModulo(serverCount); // 最关键的选择算法,将目前的的服务器数量放进去,返回一个选择的号码
server = (Server)allServers.get(nextServerIndex); // 根据下标将服务器取出来
if (server == null) { // 如果取出来为空,表示目前不可用,则进入下一个循环
Thread.yield();
} else {
if (server.isAlive() && server.isReadyToServe()) { // 如果该服务器活着且可以被使用,则直接将其返回
return server;
}
server = null;
}
continue;
}
log.warn("No up servers available from load balancer: " + lb);
return null;
}
if (count >= 10) {
log.warn("No available alive servers after 10 tries from load balancer: " + lb);
}
return server;
}
}
}
简单来说,就是将目前的计数器+1取余,获取一个下标,并返回。为了避免高并发的危险,采用CAS的方法进行设置。
private int incrementAndGetModulo(int modulo) {
int current;
int next;
do {
current = this.nextServerCyclicCounter.get(); // 获取当前值
next = (current + 1) % modulo; // +1取余
} while(!this.nextServerCyclicCounter.compareAndSet(current, next)); // CAS,如果成功就返回,失败就再来
return next;
}
以上就是Spring Cloud调用Ribbon的步骤的详细内容,更多关于Spring Cloud调用Ribbon的资料请关注编程网其它相关文章!
--结束END--
本文标题: Spring Cloud调用Ribbon的步骤
本文链接: https://lsjlt.com/news/126686.html(转载时请注明来源链接)
有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
2024-03-01
2024-03-01
2024-03-01
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
2024-02-29
回答
回答
回答
回答
回答
回答
回答
回答
回答
回答
0