Eureka
微服务的注册中心。
服务端
1.添加依赖
1 2 3 4
| <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
|
2.应用启动入口标注@EnableEurekaServer
1 2 3 4 5 6 7 8 9
| @EnableEurekaServer @SpringBootApplication public class EurekaServerDemoApplication {
public static void main(String[] args) { SpringApplication.run(EurekaServerDemoApplication.class, args); }
}
|
3.在 application.yml 中配置相关信息
1 2 3 4 5 6 7 8 9
| server: port: 80 spring: application: name: eurekaServer eureka: client: service-url: defaultZone: http://localhost/eureka
|
客户端
1.添加依赖(若是依赖管理中没有客户端的版本,则需要像下面这样手动添加,版本最好跟服务端保持一致)
1 2 3 4 5
| <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <version>2.2.6.RELEASE</version> </dependency>
|
2.在 application.yml 中配置相关信息
修改端口和应用名称,eureka的服务端地址保持不变。
远程调用
服务的远程调用包含两个客户端:调用服务的是消费者,被调用服务的是提供者。一个客户端可用同时是消费者和提供者。
远程调用服务可使用 RestTemplate 类的实例的 getObject 方法。
比如,我写一个工具类。将构建 RestTemplate 实体的工厂函数注册为 bean。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package cn.kahvia.imageservice.utils;
import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate;
@Component public class RestTemplateUtil {
@Bean public static RestTemplate getRestTemplate(){ return new RestTemplate(); } }
|
然后在有需要的地方自动装配一个 RestTemplate 对象,调用它的各种请求方法就行了。post示例如下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| package cn.kahvia.imageservice.controller; import cn.kahvia.imageservice.pojo.UploadResult; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.FileSystemResource; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest; import java.io.*;
@RestController @RequestMapping("/image") public class ImageController { @Autowired RestTemplate restTemplate; @PostMapping("/upload") public void uploadImg(MultipartFile file, HttpServletRequest request){ String path=request.getServletContext().getRealPath("");
File temp=new File(path,file.getOriginalFilename()); try { InputStream inputStream=file.getInputStream(); FileOutputStream fileOutputStream=new FileOutputStream(temp); BufferedOutputStream bufferedOutputStream=new BufferedOutputStream(fileOutputStream); int n=0; byte b[] = new byte[1024]; while ((n=inputStream.read(b))!=-1) { bufferedOutputStream.write(b); } bufferedOutputStream.flush(); bufferedOutputStream.close(); inputStream.close(); } catch (IOException e) { throw new RuntimeException(e); }
MultiValueMap<String,Object> map= new LinkedMultiValueMap<>(); FileSystemResource fileSystemResource=new FileSystemResource(temp); map.add("image",fileSystemResource);
HttpHeaders headers = new HttpHeaders(); headers.add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"); headers.add("Content-Type","multipart/form-data");
HttpEntity<MultiValueMap<String, Object>> entity=new HttpEntity<>( map,headers); UploadResult uploadResult= restTemplate.postForObject("https://xxxxxx/api/upload",entity,UploadResult.class); temp.delete(); System.out.println(uploadResult.toString()); }
}
|
负载均衡
为 RestTemplate 的工厂函数添加 @LoadBalanced注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| package cn.kahvia.imageservice.utils;
import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate;
@Component public class RestTemplateUtil { @LoadBalanced @Bean public static RestTemplate getRestTemplate(){ return new RestTemplate(); } }
|
原理:远程调用其它服务端的接口时,发出的请求会被拦截,然后根据请求的地址获取主机名(如果是eureka服务获取到的就是服务名),获取到服务名后再去eureka注册中心中取得对应服务名的所有服务端地址,根据负载均衡轮询或者随机的规则选取一个合适的地址,替换请求的地址中的服务名后,再放行,从而实现负载均衡。
负载均衡的策略
- RoundRobinRule:简单的轮询。Ribbon默认策略。
- ZoneAvoidanceRule:以区域为基础,进行服务器的选择。使用Zone进行分类。
- RandomRule:随机。
- RetryRule:重连。
- AvailabilityFilteringRule,BestAvailableRule,WeightedResponseTimeRule等
全局策略
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Component public class RestTemplateUtil { @LoadBalanced @Bean public static RestTemplate getRestTemplate(){ return new RestTemplate(); }
@Bean public static IRule setBalanceRule(){ return new BestAvailableRule(); } }
|
局部策略
1 2 3
| UserService: ribbon: NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
|
Ribbon修改饥饿加载
Ribbon默认是懒加载,也就是说,Ribbon提供的负载均衡的服务 LoadBalancerClient 并不会随着服务端启动而启动。第一次请求远程调用时,会初始化负载均衡服务,所以第一次会比较慢。
如果想要让负载均衡服务随着服务端启动而启动,就需要设置饥饿加载。在 application.yml 文件中配置饥饿加载。
1 2 3 4
| ribbon: eager-load: enabled: true clients: UserService
|