一, Eureka 的高可用性
Eureka 下面的服务实例默认每隔 30 秒会发送一个 HTTP 心跳给 Eureka, 来告诉 Eureka 服务还活着, 每个服务实例每隔 30 秒也会通过 HTTP 请求向 Eureka 获取服务列表, 这就相当于一个服务实例一分钟会与 Eureka 进行四次请求, 当服务实例多了以后, 就要考虑 Eureka 的压力, 如果我们有 1000 个服务实例, 一分钟就会有 4000 次请求, 平均每秒 70 次请求, 不过 Eureka 内部是通过内存建立一个 HashMap 来维护服务实例列表的, 并且还做了读写分离, 所以保证多个实例的心跳是没有问题的, 要注意的是保证 Eureka 的高可用, 生产环境中如果 Eureka 挂掉, 相当于所有实例之间都没办法联系了, 我们可以在多台机器上部署 Eureka(尽量不要同时在一台机器上部署, 因为出问题时, 一般整个机器的资源都不能正常使用了), 可以部署三个 Eureka 实例, 然后将每个服务实例同时注册到三台 Eureka 上面, 这样即使某个 Eureka 挂掉了, 也不会影响整个系统的运行.
配置的方式也很简单, 部署好多台 Eureka 实例后, 只需要将每个服务实例分别注册到每个 Eureka 上面即可
- eureka:
- client:
- serviceUrl:
- defaultZone: http://eureka1:80/eureka/, http://eureka2:80/eureka/
二, 服务熔断和服务降级
微服务之间的调用两种情况, 网关与服务之间的调用, 服务与服务之间的调用, 当某个服务的响应时间过长, 调用链就会等待, 当请求量多了, 就会引起雪崩, 所以就需要用到服务熔断组件 hystrix, 当调用超时时直接返回, 并且设置服务降级策略, 当发生熔断时的补救措施, 比如监控告警, 记录 SQL 日志后续进行数据恢复等
1, 服务降级配置
当出现服务熔断时, 我们需要配置服务熔断的处理策略, 服务降级有两种情况, 网关层面做降级和服务之间做降级
(1) 网关层面降级: 只需要重写 ZuulFallbackProvider 的方法, 即可定制返回值
- @Component
- public class GatewayFallback implements ZuulFallbackProvider
- {
- @Override
- public String getRoute()
- {
- // 这里配置服务降级是针对哪个服务实例的, 可以填写服务 id, 如果返回 null 则是针对所有服务
- return null;
- }
- @Override
- public ClientHttpResponse fallbackResponse()
- {
- // 服务熔断后, 返回的内容
- return new ClientHttpResponse()
- {
- @Override
- public InputStream getBody() throws IOException
- {
- JSONObject result = new JSONObject();
- result.put("error_code", -1);
- result.put("error_info", "网络繁忙");
- return new ByteArrayInputStream(result.toString().getBytes("UTF-8"));
- }
- @Override
- public HttpHeaders getHeaders()
- {
- // 返回 JSON 格式的数据
- HttpHeaders headers = new HttpHeaders();
- headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
- return headers;
- }
- @Override
- public HttpStatus getStatusCode() throws IOException
- {
- // 返回的 HTTP 错误码
- return HttpStatus.OK;
- }
- @Override
- public int getRawStatusCode() throws IOException
- {
- return HttpStatus.OK.value();
- }
- @Override
- public String getStatusText() throws IOException
- {
- return HttpStatus.OK.getReasonPhrase();
- }
- @Override
- public void close()
- {
- // 进行一些自定义的处理, 比如监控告警
- }
- };
- }
- }
(2) 服务之间降级: 服务之间的调用一般是使用 Feign 组件, 我们需要为 Feign 接口声明的每个方法编写处理的逻辑, 通过注解的 fallback 属性来指定服务降级的实现类
- @FeignClient(value = "clientService", fallback = ClientServiceFallback.class)
- public interface ClientService
- {
- @RequestMapping(method = RequestMethod.POST, value = "/test", produces = MediaType.APPLICATION_JSON_VALUE)
- String queryClientById(@RequestParam("id") String id);
- }
- public class ClientServiceFallback implements ClientService
- {
- @Override
- public String queryClientById(String id)
- {
- // 进行一些自定义的处理
- return null;
- }
- }
2, 服务熔断配置
服务熔断的参数配置非常重要, 合理的参数配置才能更好地利用好机器资源, 既不会浪费, 也能合理对服务进行熔断防止雪崩
(1) 熔断超时时间设置: 这个时间一定要根据情况合理选择, 不能太高也不能太低, 如果设置太高, 当服务出现问题时, 每个线程都要等待很久, 所有线程卡死就会导致用户根本无法正常使用, 如果太小, 出现网络波动就会影响服务质量, 合理的设置一般是比如你的接口处理时间是 200ms, 那你可以设置 300ms, 比正常的响应时间大一点点, 防止网络波动出现熔断
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds: 300
(2)Hystrix 线程池大小设置: 首先评估你的服务压力, 比如你的服务每秒需要处理 100 个请求, 每个请求的处理时间是 200ms, 相当于 1 个线程 1 秒可以处理 5 个请求, 100/5=20, 可以算出 20 个线程就可以处理请求, 我们设置就可以设置 25 个线程, 多给 5 个线程用来留些后路, 防止一些特点时间点有大量的请求
hystrix.threadpool.default.coreSize: 25
三, 最后
应对高并发, 最重要还是先要保证业务逻辑的处理速度, 才能从根本上优化, 比如进行 SQL 查询时, 尽量避免多表关联, SQL 语句越简单越好, 数据表加索引, 不要使用外键, 外键会在一定程度上影响性能, 且不容易维护, 我个人建议通过增加其他表的 id 字段来维护表之间的关系
来源: https://www.cnblogs.com/orange911/p/10696835.html