死信队列监听补充
最近在做Spring cloud项目,在以前的demo中体验过Feign,整个cloud组件太多,暂时没时间整理,java并发编程系列估计还要1-2章吧,demo不是很好找,结合最近的见闻整理一下最近的问题。
最近高频词:SpringCloud,Arthas,Spring Alibaba Nacos,Thymleaf复选框回显问题
Springcloud我看下加一下我的笔记连接,Arthas我自己写过一篇,但是太皮毛了,针对实际项目的排错和好多命令并没有试过,下面一一推荐下公众号,另外就是Spring Alibaba Nacos,这个也推一下小马哥的链接,另外描述下Thymleaf的复选框回显问题。
Spring cloud
随着微服务的流行,cloud现在用的越来越多,很多组件由于种种原因出现了停更,现在不描述太多的问题,说一下最近遇到的错,和Ribbon的负载均衡算法。
1.Feign:服务端面向接口式的客户端负载均衡组件
用法在笔记里有,先看下常见报错
org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘requestMappingHandlerMapping’ defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping. Cannot map ‘xxx’ method
public xxx
to {[xxx]}: There is already ‘xxx’ bean method
关键词
Ambiguous mapping. Cannot map ‘xxx’ method
这类报错一定是在声明Feign接口时,请求的RequestMapping地址存在重复
例如两个Feign接口,应用了同一个@GetMapping(value = “payment/get/{id}”)地址
@Component
@FeignClient(value = “CLOUD-PAYMENT-SERVICE”)
public interface FeignClientService {
/**
* 根据id查询
*
* @param id
* @return
*/
@GetMapping(value = “payment/get/{id}”)
CommonResult getPaymentById(@PathVariable(“id”) Long id);
/**
* 模拟feign超时
*
* @return
*/
@GetMapping(value = "/payment/feign/timeout")
String paymentFeignTimeout();
}
2.Ribbon负载均衡算法
Ribbon负载均衡客户端 Consumer Load Balancer
官网:https://github.com/Netflix/ribbon/wiki/Getting-Started
未来替换SpringCloud loadBalancer
Nginx是服务器负载均衡 集中式 客户端请求交由Nginx处理
Ribbon本地负载均衡 进程内
负载均衡算法:轮询,随机,权重等
eureka包含了Ribbon
点击eureka pom依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> ↓ <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-archaius</artifactId> <version>2.2.1.RELEASE</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> <version>2.2.1.RELEASE</version> <scope>compile</scope> </dependency>图片
看一下Ribbon的核心组件IRule源码
/**
- Interface that defines a “Rule” for a LoadBalancer. A Rule can be thought of
- as a Strategy for loadbalacing. Well known loadbalancing strategies include
- Round Robin, Response Time based etc.
- 为LoadBalancer定义“规则”的接口。可以想出一个规则
*作为负载平衡策略。众所周知的负载平衡策略包括
*轮询、响应时间等 - @author stonse
/
public interface IRule{
/
* choose one alive server from lb.allServers or
* lb.upServers according to key
*
* @return choosen Server object. NULL is returned if none
* server is available
*/
public Server choose(Object key);
public void setLoadBalancer(ILoadBalancer lb);
public ILoadBalancer getLoadBalancer();
}
看下其实现
图片
源码
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
/**
- The most well known and basic load balancing strategy, i.e. Round Robin Rule.
- @author stonse
- @author Nikos Michalakis nikos@netflix.com
*/
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() {
nextServerCyclicCounter = new AtomicInteger(0);
}
public RoundRobinRule(ILoadBalancer lb) {
this();
setLoadBalancer(lb);
}
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
log.warn("no load balancer");
return null;
}
Server server = null;
int count = 0;
while (server == null && count++ < 10) {
//选择活着的机器
List<Server> reachableServers = lb.getReachableServers();
List<Server> allServers = lb.getAllServers();
int upCount = reachableServers.size();
int serverCount = allServers.size();
if ((upCount == 0) || (serverCount == 0)) {
log.warn("No up servers available from load balancer: " + lb);
return null;
}
servercount=集群总数
int nextServerIndex = incrementAndGetModulo(serverCount);
//获取服务下标 get(1)
server = allServers.get(nextServerIndex);
if (server == null) {
/* Transient. */
Thread.yield();
continue;
}
if (server.isAlive() && (server.isReadyToServe())) {
return (server);
}
// Next.
server = null;
}
if (count >= 10) {
log.warn("No available alive servers after 10 tries from load balancer: "
+ lb);
}
return server;
}
/**
* Inspired by the implementation of {@link AtomicInteger#incrementAndGet()}.
*
* @param modulo The modulo to bound the value of the counter.
* @return The next value.
*/
private int incrementAndGetModulo(int modulo) {
for (;;) {
int current = nextServerCyclicCounter.get();
int next = (current + 1) % modulo;
//CAS
if (nextServerCyclicCounter.compareAndSet(current, next))
return next;
}
}
@Override
public Server choose(Object key) {
return choose(getLoadBalancer(), key);
}
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
}
}
原理是第几次请求%服务集群数量=实际服务下标,返回其服务
源码利用AtomicInteger +CAS算法实现
手写随机算法
定义获取服务器方法接口
public interface LoadBalancer {
/**
* 获取存活的服务实例列表
*
* @param serviceInstances
* @return
*/
ServiceInstance instances(List<ServiceInstance> serviceInstances);
}
利用AtomicInteger+cas实现
@Component
public class MyLB implements LoadBalancer {
private AtomicInteger atomicInteger = new AtomicInteger(0);
public final int getAndIncrement() {
int current;
int next;
do {
current = this.atomicInteger.get();
// 超过最大值,为0,重新计数
next = current >= Integer.MAX_VALUE ? 0 : current + 1;
// 自旋锁
} while (!atomicInteger.compareAndSet(current, next));
System.out.println("****第几次访问,次数next:" + next);
return next;
}
/**
* 负载均衡算法:rest接口第几次请求数%服务器集群总数量=实际调用服务器位置下标,每次服务重启动后rest接口计数从1开始.
*
* @param serviceInstances
* @return
*/
@Override
public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
int index = getAndIncrement() % serviceInstances.size();
return serviceInstances.get(index);
}
}
Controller调用
/**
* 路由规则: 轮询
* http://localhost/consumer/payment/payment/lb
*
* @return
*/
@GetMapping(value = “/consumer/payment/lb”)
public String getPaymentLB() {
List<ServiceInstance> instances = discoveryClient.getInstances(“CLOUD-PAYMENT-SERVICE”);
if (instances == null || instances.size() <= 0) {
return null;
}
ServiceInstance serviceInstance = loadBalancer.instances(instances);
URI uri = serviceInstance.getUri();
return restTemplate.getForObject(uri + “/payment/lb”, String.class);
}
Arthas
Arthas针对线上排错,定位线上BUG有很多命令操作,自己写的那篇入门太过简单,推荐文章
阿里问题定位神器 Arthas 的骚操作,定位线上BUG,超给力!
Spring Alibaba Nacos
Springcloud config 服务配置的替换
推荐视频https://www.bilibili.com/video/av32191103?p=1
Thymleaf复选框回显问题
这个问题我在以前文章提到过,只不过没现在了解的那么透彻我转载了CSDN一篇5万+访问量的文章,现在结合代码说明下
首先后台放入想要复选的值集合
public class MethodService {
public boolean contains(String id,List<Proof> proofs,ModelMap map){
List<String> ids = new ArrayList<>();
for(Proof p: proofs){
ids.add(p.getId());
}
map.put("list",ids);
return (ids.contains(id));
}
}
前台取值首先取到list,在判断是否包含当前value值如果包含返回true,页面回显选中
<label class="checkbox-inline i-checks" th:each="data : ${list}"> <input th:attr="checked=${methodService.contains(data.id,proofsList)?true:false}" type="checkbox" name="proofs[]" th:value="${data.id}" id="inlineCheckbox1" /> </lable> 附带Spring Cloud笔记链接https://note.youdao.com/ynoteshare1/index.html?id=b5cd0830c14f59287ee8a053174c60df&type=note
我不想在未来的日子里
独自哭着无法往前
歌曲《我还年轻 我还年轻》
- 点赞
- 收藏
- 关注作者
评论(0)