注册一个服务注册中心 是一个管理微服务的地方 重点是@EnableEurekaServer
可利用端口号8761登入界面 和hadoop/mongodb/redis的管理中心相似
@EnableEurekaServer
@SpringBootApplication
public class EurekaserverApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaserverApplication.class, args);
}
}
创建一个服务提供者,当client向server注册时,它会提供一些元数据:端口号,url等,如果超时会被删除
@SpringBootApplication
@EnableEurekaClient
@RestController
public class ServiceHiApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceHiApplication.class, args);
}
@Value("${server.port}")
String port;
@RequestMapping("/hi")
public String home(@RequestParam String name) {
return "hi "+name+",i am from port:" +port;
}
}
client的命名 类名 Service+名+Application
在配置中的名字是真正使用时的名字(如在Feing时调用的微服务名),application.name=service-名
ribbon是一个负载均衡客户端,可以很好的控制htt和tcp的一些行为。
@SpringBootApplication
@EnableDiscoveryClient
public class ServiceRibbonApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceRibbonApplication.class, args);
}
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}@LoadBalanced可以完成负载均衡
RestTemplate对象更是强大,它可以访问一个uri并且得到访问后返回的数据(http信息),它是spring对REST的封装。
REST/RestTemplate https://blog.csdn.net/itguangit/article/details/80198895
https://blog.csdn.net/itguangit/article/details/78825505
Feign是一个web请求的工具,可以将请求指定到具体的服务上去
Feign更轻量级的httpclient可以绑定参数访问uri
一般用于远程调用,在feign写好调用微服务的名字,就可以在任意一处调用该微服务中的方法了
对Feign的配置,不写就默认
@Configuration
public class FeignConfig {
@Bean
public Retryer feignRetryer() {
return new Retryer.Default(100, SECONDS.toMillis(1), 5);
}
}
指定微服务名称,和服务的方法
@FeignClient(value = "service-hi",configuration = FeignConfig.class)
public interface SchedualServiceHi {
@RequestMapping(value = "/hi",method = RequestMethod.GET)
String sayHiFromClientOne(@RequestParam(value = "name") String name);
}
在其他控制器中调用该微服务的方法
@RestController
public class HiController {
@Autowired
SchedualServiceHi schedualServiceHi;
@RequestMapping(value = "/hi",method = RequestMethod.GET)
public String sayHi(@RequestParam String name){
return schedualServiceHi.sayHiFromClientOne(name);
}
}
向服务发送请求的过程中,有些情况需要对请求的内容进行处理。例如服务端发布的服务接收的是JSON格式参数,而客户端使用的是对象,这种情况就可以使用编码器,将对象转换为JSON字符串。
如果接口方法要求是json
public interface PersonClient {
@RequestLine("POST /person/create")
@Headers("Content-Type: application/json")
String createPerson(Person person);
@Data
class Person {
Integer id;
String name;
Integer age;
String message;
}
}
那么调用该微服务方法时,先得到该类,再传参
public class EncoderTest {
public static void main(String[] args) {
// 获取服务接口
PersonClient personClient = Feign.builder()
.encoder(new GsonEncoder())
.target(PersonClient.class, "http://localhost:8080/");
// 创建参数的实例
Person person = new Person();
person.id = 1;
person.name = "Angus";
person.age = 30;
String response = personClient.createPerson(person);
System.out.println(response);
}
}
编码器是对请求的内容进行处理,解码器则会对服务响应的内容进行处理,例如解析响应的JSON或者XML字符串,转换为我们所需要的对象,在代码中通过以下的代码片断设置解码器:
使用.decoder()进行设置,并且在接口处@Headers要设置
Hystrix:防止某个服务不可用殃及到所偶服务不可用
资源隔离模式:1.线程池隔离模式,用多个线程池,高流量时处理不完的数据可存在线程池中慢慢处理
2.信号隔离,严格计数当前线程,当高流量时线程超过预定值直接不处理
设置
https://www.cnblogs.com/gaoyanqing/p/7470085.html
public class CommandUsingSemaphoreIsolation extends HystrixCommand<String> {
private final int id;
private long start,end ;
public CommandUsingSemaphoreIsolation(int id) {
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
// since we're doing an in-memory cache lookup we choose SEMAPHORE isolation
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE) //设置使用信号量隔离策略
.withExecutionIsolationSemaphoreMaxConcurrentRequests(3) //设置信号量隔离时的最大并发请求数
.withFallbackIsolationSemaphoreMaxConcurrentRequests(5) //设置fallback的最大并发数
.withExecutionTimeoutInMilliseconds(300))); //设置超时时间
this.id = id;
this.start = System.currentTimeMillis();
}
@Override
protected String run() throws InterruptedException {
// a real implementation would retrieve data from in memory data structure
TimeUnit.MILLISECONDS.sleep(id*30);
System.out.println("running normal, id="+id);
return "ValueFromHashMap_" + id;
}
@Override
protected String getFallback(){
System.out.println(" fallback, id="+id);
return "fallback:"+id;
}
}
线程池隔离中,发起请求的线程和真实执行的线程不是同一个线程,使用信号量隔离时,它们是同一个线程
降级方案:fallback:当失败时我们会用候选方案:降级方案
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@EnableHystrix //在微服务中允许使用
public class ServiceRibbonApplication {
public static void main(String[] args) {
SpringApplication.run( ServiceRibbonApplication.class, args );
}
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
@Service
public class HelloService {
@Autowired
RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "hiError") //注解表示开启
public String hiService(String name) {
return restTemplate.getForObject("http://SERVICE-HI/hi?name="+name,String.class);
}
public String hiError(String name) {
return "hi,"+name+",sorry,error!";
}
}
Feign中使用断路器
@FeignClient(value = "service-hi",fallback = SchedualServiceHiHystric.class)
public interface SchedualServiceHi {
@RequestMapping(value = "/hi",method = RequestMethod.GET)
String sayHiFromClientOne(@RequestParam(value = "name") String name);
}
@Component
public class SchedualServiceHiHystric implements SchedualServiceHi {
@Override
public String sayHiFromClientOne(String name) {
return "sorry "+name;
}
}
熔断器机制:https://www.cnblogs.com/small-k/p/8149227.html
请求合并:将多次请求变为一次,减少io的消耗,增加平均延迟
1、必须继承HystrixCollapser类,
2、实现以下方法:
getRequestArgument: 返回请求参数对象
createCommand : 返回BatchCommand
mapResponseToRequests:实现Response和Request的映射
3、创建对应的BatchCommand类:批量请求的具体实现
http://blog.didispace.com/spring-cloud-hystrix-request-collapse
网关zuul:官方文档http://cloud.spring.io/spring-cloud-static/Dalston.SR2/#_router_and_filter_zuul
是一个路由和负载均衡器。它可以通过映射来完成服务器的访问,类似于php框架的路由器
@SpringBootApplication
@EnableZuulProxy // 启动路由
publicclass ZuulApplication {
publicstaticvoid main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
}
它可以用过yml文件来书写规则
zuul:
routes:
ignoredServices: '' //需要忽略的微服务
ignoredPatterns: //admin/* //需要忽略的地址
users:
//下面是参数
path: /myusers/** //外来访问的地址,只要是这个格式就命中
users: /myusers/** //users是微服务名 后面跟自定义路由
url: https://downstream //命中就进入该网站
serviceId: users_service //指定转发给哪个微服务
更多用法参照 http://blog.51cto.com/1754966750/1958422
路由熔断 指定熔断某个服务
如果微服务下线了,针对每个微服务,都需要回复一个中文提示,而不是报异常
@Component
public class ConsumerFallbackProvider implements ZuulFallbackProvider {
@Override
public String getRoute() {
// 表明是为哪个微服务提供回退
return "tcloud-user-consumer";
}
@Overrid
public ClientHttpResponse fallbackResponse() {
return new ClientHttpResponse() {
@Override
public HttpStatus getStatusCode() throws IOException {
// fallback时的状态码
return HttpStatus.OK;
}
@Override
public int getRawStatusCode() throws IOException {
// 数字类型的状态码,本例返回的其实就是200,详见HttpStatus
return this.getStatusCode().value();
}
@Override
public String getStatusText() throws IOException {
// 状态文本,本例返回的其实就是OK,详见HttpStatus
return this.getStatusCode().getReasonPhrase();
}
@Override
public void close() {
}
@Override
public InputStream getBody() throws IOException {
// 响应体
return new ByteArrayInputStream("tcloud-user-consumer微服务不可用,请稍后再试。".getBytes());
}
@Override
public HttpHeaders getHeaders() {
// headers设定
HttpHeaders headers = new HttpHeaders();
MediaType mt = new MediaType("application","json", Charset.forName("UTF-8"));
headers.setContentType(mt);
return headers;
}
};}}
网友评论