- 1.1 消息队列
-
1.2 搜索引擎
-
1.2.1 es 的分布式架构原理能说一下么(es 是如何实现分布式的啊)?
-
1.2.2 es 写入数据的工作原理是什么啊?es 查询数据的工作原理是什么啊?底层的 lucene 介绍一下呗?倒排索引了解吗?
-
1.2.3 es 在数据量很大的情况下(数十亿级别)如何提高查询效率啊?
-
1.2.4 es 生产集群的部署架构是什么?每个索引的数据量大概有多少?每个索引大概有多少个分片?
-
1.3.1 在项目中缓存是如何使用的?缓存如果使用不当会造成什么后果?
-
1.3.2 Redis 和 Memcached 有什么区别?Redis 的线程模型是什么?为什么单线程的 Redis 比多线程的 Memcached 效率要高得多?
-
1.3.3 Redis 都有哪些数据类型?分别在哪些场景下使用比较合适?
-
1.3.4 Redis 的过期策略都有哪些?手写一下 LRU 代码实现?
-
1.3.5 如何保证 Redis 高并发、高可用?Redis 的主从复制原理能介绍一下么?Redis 的哨兵原理能介绍一下么?
-
1.3.6 Redis 的持久化有哪几种方式?不同的持久化机制都有什么优缺点?持久化机制具体底层是如何实现的?
-
1.3.7 Redis 集群模式的工作原理能说一下么?在集群模式下,Redis 的 key 是如何寻址的?分布式寻址都有哪些算法?了解一致性 hash 算法吗?如何动态增加和删除一个节点?
-
1.3.8 了解什么是 redis 的雪崩、穿透和击穿?Redis 崩溃之后会怎么样?系统该如何应对这种情况?如何处理 Redis 的穿透?
-
1.3.9 如何保证缓存与数据库的双写一致性?
-
1.3.10 Redis 的并发竞争问题是什么?如何解决这个问题?了解 Redis 事务的 CAS 方案吗?
-
1.3.11 生产环境中的 Redis 是怎么部署的?
-
1.4.1 为什么要分库分表(设计高并发系统的时候,数据库层面该如何设计)?用过哪些分库分表中间件?不同的分库分表中间件都有什么优点和缺点?你们具体是如何对数据库如何进行垂直拆分或水平拆分的?
-
1.4.2 现在有一个未分库分表的系统,未来要分库分表,如何设计才可以让系统从未分库分表动态切换到分库分表上?
-
1.4.3 如何设计可以动态扩容缩容的分库分表方案?
-
1.4.4 分库分表之后,id 主键如何处理?
-
1.5.1 如何实现 MySQL 的读写分离?MySQL 主从复制原理是啥?如何解决 MySQL 主从同步的延时问题?
-
1.6.1 如何设计一个高并发系统?
-
1.2.1 es 的分布式架构原理能说一下么(es 是如何实现分布式的啊)?
-
2.1 面试连环炮
-
2.2.1 为什么要进行系统拆分?如何进行系统拆分?拆分后不用 Dubbo 可以吗?
-
2.3.1 说一下 Dubbo 的工作原理?注册中心挂了可以继续通信吗?
-
2.3.2 Dubbo 支持哪些序列化协议?说一下 Hessian 的数据结构?PB 知道吗?为什么 PB 的效率是最高的?
-
2.3.3 Dubbo 负载均衡策略和集群容错策略都有哪些?动态代理策略呢?
-
2.3.4 Dubbo 的 spi 思想是什么?
-
2.3.5 如何基于 Dubbo 进行服务治理、服务降级、失败重试以及超时重试?
-
2.3.6 分布式服务接口的幂等性如何设计(比如不能重复扣款)?
-
2.3.7 分布式服务接口请求的顺序性如何保证?
-
2.3.8 如何自己设计一个类似 Dubbo 的 RPC 框架?
-
2.4.1 Zookeeper 都有哪些应用场景?
-
2.4.2 使用 Redis 如何设计分布式锁?使用 Zookeeper 来设计分布式锁可以吗?以上两种分布式锁的实现方式哪种效率比较高?
-
2.5.1 分布式事务了解吗?你们如何解决分布式事务问题的?TCC 如果出现网络连不通怎么办?XA 的一致性如何保证?
-
2.6.1 集群部署时的分布式 Session 如何实现?
-
3.1.1 Hystrix 介绍
-
3.1.2 电商网站详情页系统架构
-
3.1.3 Hystrix 线程池技术实现资源隔离
-
3.1.4 Hystrix 信号量机制实现资源隔离
-
3.1.5 Hystrix 隔离策略细粒度控制
-
3.1.6 深入 Hystrix 执行时内部原理
-
3.1.7 基于 request cache 请求缓存技术优化批量商品数据查询接口
-
3.1.8 基于本地缓存的 fallback 降级机制
-
3.1.9 深入 Hystrix 断路器执行原理
-
3.1.10 深入 Hystrix 线程池隔离与接口限流
-
3.1.11 基于 timeout 机制为服务接口调用超时提供安全保护
-
2.2.1 为什么要进行系统拆分?如何进行系统拆分?拆分后不用 Dubbo 可以吗?
-
4.1 关于微服务架构的描述
基于 timeout 机制为服务接口调用超时提供安全保护
一般来说,在调用依赖服务的接口的时候,比较常见的一个问题就是超时。超时是在一个复杂的分布式系统中,导致系统不稳定,或者系统抖动。出现大量超时,线程资源会被 hang 死,从而导致吞吐量大幅度下降,甚至服务崩溃。
你去调用各种各样的依赖服务,特别是在大公司,你甚至都不认识开发一个服务的人,你都不知道那个人的技术水平怎么样,对那个人根本不了解。
Peter Steiner 说过,"On the Internet, nobody knows you're a dog",也就是说在互联网的另外一头,你都不知道甚至坐着一条狗。
像特别复杂的分布式系统,特别是在大公司里,多个团队、大型协作,你可能都不知道服务是谁的,很可能说开发服务的那个哥儿们甚至是一个实习生。依赖服务的接口性能可能很不稳定,有时候 2ms,有时候 200ms,甚至 2s,都有可能。
如果你不对各种依赖服务接口的调用做超时控制,来给你的服务提供安全保护措施,那么很可能你的服务就被各种垃圾的依赖服务的性能给拖死了。大量的接口调用很慢,大量的线程被卡死。如果你做了资源的隔离,那么也就是线程池的线程被卡死,但其实我们可以做超时控制,没必要让它们全卡死。
TimeoutMilliseconds
在 Hystrix 中,我们可以手动设置 timeout 时长,如果一个 command 运行时间超过了设定的时长,那么就被认为是 timeout,然后 Hystrix command 标识为 timeout,同时执行 fallback 降级逻辑。
TimeoutMilliseconds
默认值是 1000,也就是 1000ms。
HystrixCommandProperties.Setter()
..withExecutionTimeoutInMilliseconds(int)
copy
TimeoutEnabled
这个参数用于控制是否要打开 timeout 机制,默认值是 true。
HystrixCommandProperties.Setter()
.withExecutionTimeoutEnabled(boolean)
copy
实例 Demo
我们在 command 中,将超时时间设置为 500ms,然后在 run() 方法中,设置休眠时间 1s,这样一个请求过来,直接休眠 1s,结果就会因为超时而执行降级逻辑。
public class GetProductInfoCommand extends HystrixCommand<ProductInfo> {
private Long productId;
private static final HystrixCommandKey KEY = HystrixCommandKey.Factory.asKey("GetProductInfoCommand");
public GetProductInfoCommand(Long productId) {
super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ProductInfoService"))
.andCommandKey(KEY)
.andThreadPoolPropertiesDefaults(HystrixThreadPoolProperties.Setter()
.withCoreSize(8)
.withMaxQueueSize(10)
.withQueueSizeRejectionThreshold(8))
.andCommandPropertiesDefaults(HystrixCommandProperties.Setter()
.withCircuitBreakerEnabled(true)
.withCircuitBreakerRequestVolumeThreshold(20)
.withCircuitBreakerErrorThresholdPercentage(40)
.withCircuitBreakerSleepWindowInMilliseconds(3000)
// 设置是否打开超时,默认是true
.withExecutionTimeoutEnabled(true)
// 设置超时时间,默认1000(ms)
.withExecutionTimeoutInMilliseconds(500)
.withFallbackIsolationSemaphoreMaxConcurrentRequests(30)));
this.productId = productId;
}
@Override
protected ProductInfo run() throws Exception {
System.out.println("调用接口查询商品数据,productId=" + productId);
// 休眠1s
TimeUtils.sleep(1);
String url = "http://localhost:8081/getProductInfo?productId=" + productId;
String response = HttpClientUtils.sendGetRequest(url);
System.out.println(response);
return JSONObject.parseObject(response, ProductInfo.class);
}
@Override
protected ProductInfo getFallback() {
ProductInfo productInfo = new ProductInfo();
productInfo.setName("降级商品");
return productInfo;
}
}
copy
在测试类中,我们直接发起请求。
@SpringBootTest
@RunWith(SpringRunner.class)
public class TimeoutTest {
@Test
public void testTimeout() {
HttpClientUtils.sendGetRequest("http://localhost:8080/getProductInfo?productId=1");
}
}
copy
结果中可以看到,打印出了降级商品相关信息。
ProductInfo(id=null, name=降级商品, price=null, pictureList=null, specification=null, service=null, color=null, size=null, shopId=null, modifiedTime=null, cityId=null, cityName=null, brandId=null, brandName=null)
{"id": 1, "name": "iphone7手机", "price": 5599, "pictureList":"a.jpg,b.jpg", "specification": "iphone7的规格", "service": "iphone7的售后服务", "color": "红色,白色,黑色", "size": "5.5", "shopId": 1, "modifiedTime": "2017-01-01 12:00:00", "cityId": 1, "brandId": 1}
copy