SpringCloud筆記三:服務消費者ribbon和feign和註冊中心高可用
文章目錄
常用的服務間調用方式
- RPC調用方式
遠程過程調用,像調用本地服務一樣調用服務器的服務。
支持同步,異步調用。
客戶端和服務端之間建立TCP連接,可以一次建立一個,也可以多個調用複用一次連接。
也就是說,建立連接後,每次調用就用這個連接,不需要再次連接了,因爲每次建立連接都會消耗資源的。(三次握手)
適合千萬級別的用戶。
Rpc數據包小,使用谷歌開源protobuf
開發成本高,編碼,序列化問題,丟包,分包。
- Rest(http)
http請求,支持各種協議和功能。
開發方便成本低。
http數據包大
微服務調用之ribbon實戰,訂單調用商品服務
- 開發步驟
1、創建order_service項目
2、開發僞下單接口
3、使用ribbon
啓動類增加註解,這個是ribbon的負載均衡策略
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
4、根據名稱進行調用商品,獲取商品詳情。
- ribbon介紹
類似於HttpClient,urlConnection
- 核心代碼
@Service
public class PorductOrderServiceImpl implements ProductOrderService {
@Autowired
private RestTemplate restTemplate;
@Override
public ProductOrder save(int userId, int productId) {
Object obj = restTemplate.getForObject("http://product-service/api/v1/product/find?id=" + productId, Object.class);
System.out.println(obj);
//獲取商品詳情
ProductOrder productOrder=new ProductOrder();
productOrder.setCreateTime(new Date());
productOrder.setUserId(userId);
productOrder.setTradeNo(UUID.randomUUID().toString());
return productOrder;
}
}
- 核心配置
server:
port: 8781
#服務的名稱
spring:
application:
name: order-service
#指定註冊中心地址
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
Ribbon負載均衡源碼分析
- 引入rbbion的負載均衡器的第二種方式
通過注入:LoadBalancerClient,和在啓動類裏面添加Bean一樣。
@Service
public class PorductOrderServiceImpl implements ProductOrderService {
/*@Autowired
private RestTemplate restTemplate;*/
@Autowired
private LoadBalancerClient loadBalancerClient;
@Override
public ProductOrder save(int userId, int productId) {
//Map<String,Object> productMap = restTemplate.getForObject("http://product-service/api/v1/product/find?id=" + productId, Map.class);
//獲取商品詳情
ServiceInstance instance = loadBalancerClient.choose("product-service");
String url=String.format("http://%s:%s/api/v1/product/find?id="+productId,instance.getHost(),instance.getPort());
RestTemplate restTemplate=new RestTemplate();
Map<String,Object> productMap1 =restTemplate.getForObject(url,Map.class);
ProductOrder productOrder=new ProductOrder();
productOrder.setCreateTime(new Date());
productOrder.setUserId(userId);
productOrder.setTradeNo(UUID.randomUUID().toString());
productOrder.setProductName(productMap.get("name").toString());
productOrder.setPrice(Integer.parseInt(productMap.get("price").toString()));
return productOrder;
}
}
- 源碼分析ribbon的負載均衡類
ctrl+shift+N搜索LoadBalancerClient,查看chose()方法,通過源碼得知裏面的負載均衡策略。
調用負載均衡步驟
1、首先從註冊中心獲取provider的列表 2、通過一定的策略選擇其中一個節點。
3、再返回restTemplete調用。
調整ribbon的負載均衡策略
- 在yml文件裏面進行配置
ribbon默認的負載均衡策略是:輪流進行,下面修改成隨機的。
#要調用的服務名
product-service:
ribbon:
#找到IRule的實現類,並將該實現類的權限名copy過來。
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
- 策略配置
1、如果每個機器配置一樣,則建議不修改策略。(推薦)
2、如果部分機器配置強,則可以改爲 WeightedResponseTimeRule
微服務調用方式feign
- feign
Feign:僞RPC客戶端(本質還是http)
- 使用步驟
1、加入依賴,注意新舊版本
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2、啓動類添加@EnableFeignClients註解
3、增加接口並@FeignClient(name=“所調用服務的註冊名字”)
@FeignClient(name = "product-service")
public interface ProductClient {
@GetMapping("api/v1/product/find")
String findById(@RequestParam(value = "id") int id);
}
4、實現類調用,將響應的json轉成JsonNode,然後從裏面取值。
@Service
public class PorductOrderServiceImpl implements ProductOrderService {
/*@Autowired
private RestTemplate restTemplate;*/
/* @Autowired
private LoadBalancerClient loadBalancerClient;*/
@Autowired
private ProductClient productClient;
@Override
public ProductOrder save(int userId, int productId) {
//Map<String,Object> productMap = restTemplate.getForObject("http://product-service/api/v1/product/find?id=" + productId, Map.class);
//獲取商品詳情
/* ServiceInstance instance = loadBalancerClient.choose("product-service");
String url=String.format("http://%s:%s/api/v1/product/find?id="+productId,instance.getHost(),instance.getPort());
RestTemplate restTemplate=new RestTemplate();
Map<String,Object> productMap1 =restTemplate.getForObject(url,Map.class);*/
String response = productClient.findById(productId);
JsonNode jsonNode = JsonUtils.str2JsonNode(response);
ProductOrder productOrder=new ProductOrder();
productOrder.setCreateTime(new Date());
productOrder.setUserId(userId);
productOrder.setTradeNo(UUID.randomUUID().toString());
/*productOrder.setProductName(productMap.get("name").toString());
productOrder.setPrice(Integer.parseInt(productMap.get("price").toString()));*/
productOrder.setProductName(jsonNode.get("name").toString());
productOrder.setPrice(Integer.parseInt(jsonNode.get("price").toString()));
return productOrder;
}
}
5、json轉JsonNode
public class JsonUtils {
private static final ObjectMapper objectMapper=new ObjectMapper();
public static JsonNode str2JsonNode(String str) {
try {
return objectMapper.readTree(str);
} catch (JsonProcessingException e) {
return null;
}
}
}
Feign源碼解讀以及Feign和Ribbon的選擇
- 設置當前線程睡眠
TimeUnit.SECONDS.sleep(10);//該方法會讓當前線程睡眠10s,睡眠會放棄cpu,但是不會放棄鎖對象。wait()會讓出cpu和鎖對象。該API還可以設置分鐘。
- 超時配置
默認options readtimeout是60,但是由於Hystrix默認是1s超時.下面是超時配置
#修改feign請求的超時時間
feign:
client:
config:
default:
connectTimeout: 2000
readTimeout: 2000
- Feign內部的負載均衡策略其實使用的是ribbon
- 儘量使用Feign,因爲Feign解耦性更強。