diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..952cbbf1c --- /dev/null +++ b/.prettierrc @@ -0,0 +1,10 @@ +{ + "tabWidth": 4, + "useTabs": false, + "semi": true, + "singleQuote": true, + "trailingComma": "all", + "bracketSpacing": true, + "jsxBracketSameLine": false, + "arrowParens": "avoid" +} \ No newline at end of file diff --git a/README.md b/README.md index 4d11f1543..5603a3e08 100644 --- a/README.md +++ b/README.md @@ -8,64 +8,64 @@ [![doocs](https://img.shields.io/badge/org-join%20us-42b883?style=flat-square&logo=homeassistantcommunitystore&logoColor=ffffff)](https://doocs.github.io/#/?id=how-to-join) [![discord-chat](https://img.shields.io/discord/901805669529825301.svg?logo=discord&color=42b883&style=flat-square&logoColor=ffffff)](https://discord.gg/qUFwPPEYEy) -本项目大部分内容来自中华石杉,版权归作者所有,内容涵盖[高并发](#高并发架构)、[分布式](#分布式系统)、[高可用](#高可用架构)、[微服务](#微服务架构)、[海量数据处理](#海量数据处理)等领域知识。我们对这部分知识做了一个系统的整理,方便学习查阅。 +本项目大部分内容来自中华石杉,版权归作者所有,内容涵盖[高并发](#高并发架构)、[分布式](#分布式系统)、[高可用](#高可用架构)、[微服务](#微服务架构)、[海量数据处理](#海量数据处理)等领域知识。我们对这部分知识做了一个系统的整理,方便读者们学习查阅。 我们也在全力更新算法项目!如果你在准备笔面试算法,或者想进一步提升 coding 能力,欢迎 Star 关注 [doocs/leetcode](https://github.com/doocs/leetcode) 学习本项目之前,先来看看 [Discussions 讨论区](https://github.com/doocs/advanced-java/discussions/9)的技术面试官是怎么说的吧。本项目欢迎各位开发者朋友到 Discussions 讨论区分享自己的一些想法和实践经验。也不妨 Star 关注 [doocs/advanced-java](https://github.com/doocs/advanced-java),随时追踪项目最新动态。 -- Gitee Pages: https://doocs.gitee.io/advanced-java -- GitHub Pages: https://doocs.github.io/advanced-java +- Gitee Pages: https://doocs.gitee.io/advanced-java +- GitHub Pages: https://doocs.github.io/advanced-java ## 高并发架构 ### [消息队列](/docs/high-concurrency/mq-interview.md) -- [为什么使用消息队列?消息队列有什么优点和缺点?Kafka、ActiveMQ、RabbitMQ、RocketMQ 都有什么优点和缺点?](/docs/high-concurrency/why-mq.md) -- [如何保证消息队列的高可用?](/docs/high-concurrency/how-to-ensure-high-availability-of-message-queues.md) -- [如何保证消息不被重复消费?(如何保证消息消费的幂等性)](/docs/high-concurrency/how-to-ensure-that-messages-are-not-repeatedly-consumed.md) -- [如何保证消息的可靠性传输?(如何处理消息丢失的问题)](/docs/high-concurrency/how-to-ensure-the-reliable-transmission-of-messages.md) -- [如何保证消息的顺序性?](/docs/high-concurrency/how-to-ensure-the-order-of-messages.md) -- [如何解决消息队列的延时以及过期失效问题?消息队列满了以后该怎么处理?有几百万消息持续积压几小时,说说怎么解决?](/docs/high-concurrency/mq-time-delay-and-expired-failure.md) -- [如果让你写一个消息队列,该如何进行架构设计啊?说一下你的思路。](/docs/high-concurrency/mq-design.md) +- [为什么使用消息队列?消息队列有什么优点和缺点?Kafka、ActiveMQ、RabbitMQ、RocketMQ 都有什么优点和缺点?](/docs/high-concurrency/why-mq.md) +- [如何保证消息队列的高可用?](/docs/high-concurrency/how-to-ensure-high-availability-of-message-queues.md) +- [如何保证消息不被重复消费?(如何保证消息消费的幂等性)](/docs/high-concurrency/how-to-ensure-that-messages-are-not-repeatedly-consumed.md) +- [如何保证消息的可靠性传输?(如何处理消息丢失的问题)](/docs/high-concurrency/how-to-ensure-the-reliable-transmission-of-messages.md) +- [如何保证消息的顺序性?](/docs/high-concurrency/how-to-ensure-the-order-of-messages.md) +- [如何解决消息队列的延时以及过期失效问题?消息队列满了以后该怎么处理?有几百万消息持续积压几小时,说说怎么解决?](/docs/high-concurrency/mq-time-delay-and-expired-failure.md) +- [如果让你写一个消息队列,该如何进行架构设计啊?说一下你的思路。](/docs/high-concurrency/mq-design.md) ### [搜索引擎](/docs/high-concurrency/es-introduction.md) -- [ES 的分布式架构原理能说一下么(ES 是如何实现分布式的啊)?](/docs/high-concurrency/es-architecture.md) -- [ES 写入数据的工作原理是什么啊?ES 查询数据的工作原理是什么啊?底层的 Lucene 介绍一下呗?倒排索引了解吗?](/docs/high-concurrency/es-write-query-search.md) -- [ES 在数据量很大的情况下(数十亿级别)如何提高查询效率啊?](/docs/high-concurrency/es-optimizing-query-performance.md) -- [ES 生产集群的部署架构是什么?每个索引的数据量大概有多少?每个索引大概有多少个分片?](/docs/high-concurrency/es-production-cluster.md) +- [ES 的分布式架构原理能说一下么(ES 是如何实现分布式的啊)?](/docs/high-concurrency/es-architecture.md) +- [ES 写入数据的工作原理是什么啊?ES 查询数据的工作原理是什么啊?底层的 Lucene 介绍一下呗?倒排索引了解吗?](/docs/high-concurrency/es-write-query-search.md) +- [ES 在数据量很大的情况下(数十亿级别)如何提高查询效率啊?](/docs/high-concurrency/es-optimizing-query-performance.md) +- [ES 生产集群的部署架构是什么?每个索引的数据量大概有多少?每个索引大概有多少个分片?](/docs/high-concurrency/es-production-cluster.md) ### 缓存 -- [在项目中缓存是如何使用的?缓存如果使用不当会造成什么后果?](/docs/high-concurrency/why-cache.md) -- [Redis 和 Memcached 有什么区别?Redis 的线程模型是什么?为什么单线程的 Redis 比多线程的 Memcached 效率要高得多?](/docs/high-concurrency/redis-single-thread-model.md) -- [Redis 都有哪些数据类型?分别在哪些场景下使用比较合适?](/docs/high-concurrency/redis-data-types.md) -- [Redis 的过期策略都有哪些?手写一下 LRU 代码实现?](/docs/high-concurrency/redis-expiration-policies-and-lru.md) -- [如何保证 Redis 高并发、高可用?Redis 的主从复制原理能介绍一下么?Redis 的哨兵原理能介绍一下么?](/docs/high-concurrency/how-to-ensure-high-concurrency-and-high-availability-of-redis.md) -- [Redis 主从架构是怎样的?](/docs/high-concurrency/redis-master-slave.md) -- [Redis 的持久化有哪几种方式?不同的持久化机制都有什么优缺点?持久化机制具体底层是如何实现的?](/docs/high-concurrency/redis-persistence.md) -- [Redis 集群模式的工作原理能说一下么?在集群模式下,Redis 的 key 是如何寻址的?分布式寻址都有哪些算法?了解一致性 hash 算法吗?如何动态增加和删除一个节点?](/docs/high-concurrency/redis-cluster.md) -- [了解什么是 Redis 的雪崩、穿透和击穿?Redis 崩溃之后会怎么样?系统该如何应对这种情况?如何处理 Redis 的穿透?](/docs/high-concurrency/redis-caching-avalanche-and-caching-penetration.md) -- [如何保证缓存与数据库的双写一致性?](/docs/high-concurrency/redis-consistence.md) -- [Redis 的并发竞争问题是什么?如何解决这个问题?了解 Redis 事务的 CAS 方案吗?](/docs/high-concurrency/redis-cas.md) -- [生产环境中的 Redis 是怎么部署的?](/docs/high-concurrency/redis-production-environment.md) -- [有了解过 Redis rehash 的过程吗?](/docs/high-concurrency/redis-rehash.md) +- [在项目中缓存是如何使用的?缓存如果使用不当会造成什么后果?](/docs/high-concurrency/why-cache.md) +- [Redis 和 Memcached 有什么区别?Redis 的线程模型是什么?为什么单线程的 Redis 比多线程的 Memcached 效率要高得多?](/docs/high-concurrency/redis-single-thread-model.md) +- [Redis 都有哪些数据类型?分别在哪些场景下使用比较合适?](/docs/high-concurrency/redis-data-types.md) +- [Redis 的过期策略都有哪些?手写一下 LRU 代码实现?](/docs/high-concurrency/redis-expiration-policies-and-lru.md) +- [如何保证 Redis 高并发、高可用?Redis 的主从复制原理能介绍一下么?Redis 的哨兵原理能介绍一下么?](/docs/high-concurrency/how-to-ensure-high-concurrency-and-high-availability-of-redis.md) +- [Redis 主从架构是怎样的?](/docs/high-concurrency/redis-master-slave.md) +- [Redis 的持久化有哪几种方式?不同的持久化机制都有什么优缺点?持久化机制具体底层是如何实现的?](/docs/high-concurrency/redis-persistence.md) +- [Redis 集群模式的工作原理能说一下么?在集群模式下,Redis 的 key 是如何寻址的?分布式寻址都有哪些算法?了解一致性 hash 算法吗?如何动态增加和删除一个节点?](/docs/high-concurrency/redis-cluster.md) +- [了解什么是 Redis 的雪崩、穿透和击穿?Redis 崩溃之后会怎么样?系统该如何应对这种情况?如何处理 Redis 的穿透?](/docs/high-concurrency/redis-caching-avalanche-and-caching-penetration.md) +- [如何保证缓存与数据库的双写一致性?](/docs/high-concurrency/redis-consistence.md) +- [Redis 的并发竞争问题是什么?如何解决这个问题?了解 Redis 事务的 CAS 方案吗?](/docs/high-concurrency/redis-cas.md) +- [生产环境中的 Redis 是怎么部署的?](/docs/high-concurrency/redis-production-environment.md) +- [有了解过 Redis rehash 的过程吗?](/docs/high-concurrency/redis-rehash.md) ### 分库分表 -- [为什么要分库分表(设计高并发系统的时候,数据库层面该如何设计)?用过哪些分库分表中间件?不同的分库分表中间件都有什么优点和缺点?你们具体是如何对数据库如何进行垂直拆分或水平拆分的?](/docs/high-concurrency/database-shard.md) -- [现在有一个未分库分表的系统,未来要分库分表,如何设计才可以让系统从未分库分表动态切换到分库分表上?](/docs/high-concurrency/database-shard-method.md) -- [如何设计可以动态扩容缩容的分库分表方案?](/docs/high-concurrency/database-shard-dynamic-expand.md) -- [分库分表之后,id 主键如何处理?](/docs/high-concurrency/database-shard-global-id-generate.md) +- [为什么要分库分表(设计高并发系统的时候,数据库层面该如何设计)?用过哪些分库分表中间件?不同的分库分表中间件都有什么优点和缺点?你们具体是如何对数据库如何进行垂直拆分或水平拆分的?](/docs/high-concurrency/database-shard.md) +- [现在有一个未分库分表的系统,未来要分库分表,如何设计才可以让系统从未分库分表动态切换到分库分表上?](/docs/high-concurrency/database-shard-method.md) +- [如何设计可以动态扩容缩容的分库分表方案?](/docs/high-concurrency/database-shard-dynamic-expand.md) +- [分库分表之后,id 主键如何处理?](/docs/high-concurrency/database-shard-global-id-generate.md) ### 读写分离 -- [如何实现 MySQL 的读写分离?MySQL 主从复制原理是啥?如何解决 MySQL 主从同步的延时问题?](/docs/high-concurrency/mysql-read-write-separation.md) +- [如何实现 MySQL 的读写分离?MySQL 主从复制原理是啥?如何解决 MySQL 主从同步的延时问题?](/docs/high-concurrency/mysql-read-write-separation.md) ### 高并发系统 -- [如何设计一个高并发系统?](/docs/high-concurrency/high-concurrency-design.md) +- [如何设计一个高并发系统?](/docs/high-concurrency/high-concurrency-design.md) ## 分布式系统 @@ -73,106 +73,106 @@ ### 系统拆分 -- [为什么要进行系统拆分?如何进行系统拆分?拆分后不用 Dubbo 可以吗?](/docs/distributed-system/why-dubbo.md) +- [为什么要进行系统拆分?如何进行系统拆分?拆分后不用 Dubbo 可以吗?](/docs/distributed-system/why-dubbo.md) ### 分布式服务框架 -- [说一下 Dubbo 的工作原理?注册中心挂了可以继续通信吗?](/docs/distributed-system/dubbo-operating-principle.md) -- [Dubbo 支持哪些序列化协议?说一下 Hessian 的数据结构?PB 知道吗?为什么 PB 的效率是最高的?](/docs/distributed-system/dubbo-serialization-protocol.md) -- [Dubbo 负载均衡策略和集群容错策略都有哪些?动态代理策略呢?](/docs/distributed-system/dubbo-load-balancing.md) -- [Dubbo 的 spi 思想是什么?](/docs/distributed-system/dubbo-spi.md) -- [如何基于 Dubbo 进行服务治理、服务降级、失败重试以及超时重试?](/docs/distributed-system/dubbo-service-management.md) -- [分布式服务接口的幂等性如何设计(比如不能重复扣款)?](/docs/distributed-system/distributed-system-idempotency.md) -- [分布式服务接口请求的顺序性如何保证?](/docs/distributed-system/distributed-system-request-sequence.md) -- [如何自己设计一个类似 Dubbo 的 RPC 框架?](/docs/distributed-system/dubbo-rpc-design.md) -- [CAP 定理的 P 是什么?](/docs/distributed-system/distributed-system-cap.md) +- [说一下 Dubbo 的工作原理?注册中心挂了可以继续通信吗?](/docs/distributed-system/dubbo-operating-principle.md) +- [Dubbo 支持哪些序列化协议?说一下 Hessian 的数据结构?PB 知道吗?为什么 PB 的效率是最高的?](/docs/distributed-system/dubbo-serialization-protocol.md) +- [Dubbo 负载均衡策略和集群容错策略都有哪些?动态代理策略呢?](/docs/distributed-system/dubbo-load-balancing.md) +- [Dubbo 的 spi 思想是什么?](/docs/distributed-system/dubbo-spi.md) +- [如何基于 Dubbo 进行服务治理、服务降级、失败重试以及超时重试?](/docs/distributed-system/dubbo-service-management.md) +- [分布式服务接口的幂等性如何设计(比如不能重复扣款)?](/docs/distributed-system/distributed-system-idempotency.md) +- [分布式服务接口请求的顺序性如何保证?](/docs/distributed-system/distributed-system-request-sequence.md) +- [如何自己设计一个类似 Dubbo 的 RPC 框架?](/docs/distributed-system/dubbo-rpc-design.md) +- [CAP 定理的 P 是什么?](/docs/distributed-system/distributed-system-cap.md) ### 分布式锁 -- [Zookeeper 都有哪些应用场景?](/docs/distributed-system/zookeeper-application-scenarios.md) -- [使用 Redis 如何设计分布式锁?使用 Zookeeper 来设计分布式锁可以吗?以上两种分布式锁的实现方式哪种效率比较高?](/docs/distributed-system/distributed-lock-redis-vs-zookeeper.md) +- [Zookeeper 都有哪些应用场景?](/docs/distributed-system/zookeeper-application-scenarios.md) +- [使用 Redis 如何设计分布式锁?使用 Zookeeper 来设计分布式锁可以吗?以上两种分布式锁的实现方式哪种效率比较高?](/docs/distributed-system/distributed-lock-redis-vs-zookeeper.md) ### 分布式事务 -- [分布式事务了解吗?你们如何解决分布式事务问题的?TCC 如果出现网络连不通怎么办?XA 的一致性如何保证?](/docs/distributed-system/distributed-transaction.md) +- [分布式事务了解吗?你们如何解决分布式事务问题的?TCC 如果出现网络连不通怎么办?XA 的一致性如何保证?](/docs/distributed-system/distributed-transaction.md) ### 分布式会话 -- [集群部署时的分布式 Session 如何实现?](/docs/distributed-system/distributed-session.md) +- [集群部署时的分布式 Session 如何实现?](/docs/distributed-system/distributed-session.md) ## 高可用架构 -- [Hystrix 介绍](/docs/high-availability/hystrix-introduction.md) -- [电商网站详情页系统架构](/docs/high-availability/e-commerce-website-detail-page-architecture.md) -- [Hystrix 线程池技术实现资源隔离](/docs/high-availability/hystrix-thread-pool-isolation.md) -- [Hystrix 信号量机制实现资源隔离](/docs/high-availability/hystrix-semphore-isolation.md) -- [Hystrix 隔离策略细粒度控制](/docs/high-availability/hystrix-execution-isolation.md) -- [深入 Hystrix 执行时内部原理](/docs/high-availability/hystrix-process.md) -- [基于 request cache 请求缓存技术优化批量商品数据查询接口](/docs/high-availability/hystrix-request-cache.md) -- [基于本地缓存的 fallback 降级机制](/docs/high-availability/hystrix-fallback.md) -- [深入 Hystrix 断路器执行原理](/docs/high-availability/hystrix-circuit-breaker.md) -- [深入 Hystrix 线程池隔离与接口限流](/docs/high-availability/hystrix-thread-pool-current-limiting.md) -- [基于 timeout 机制为服务接口调用超时提供安全保护](/docs/high-availability/hystrix-timeout.md) +- [Hystrix 介绍](/docs/high-availability/hystrix-introduction.md) +- [电商网站详情页系统架构](/docs/high-availability/e-commerce-website-detail-page-architecture.md) +- [Hystrix 线程池技术实现资源隔离](/docs/high-availability/hystrix-thread-pool-isolation.md) +- [Hystrix 信号量机制实现资源隔离](/docs/high-availability/hystrix-semphore-isolation.md) +- [Hystrix 隔离策略细粒度控制](/docs/high-availability/hystrix-execution-isolation.md) +- [深入 Hystrix 执行时内部原理](/docs/high-availability/hystrix-process.md) +- [基于 request cache 请求缓存技术优化批量商品数据查询接口](/docs/high-availability/hystrix-request-cache.md) +- [基于本地缓存的 fallback 降级机制](/docs/high-availability/hystrix-fallback.md) +- [深入 Hystrix 断路器执行原理](/docs/high-availability/hystrix-circuit-breaker.md) +- [深入 Hystrix 线程池隔离与接口限流](/docs/high-availability/hystrix-thread-pool-current-limiting.md) +- [基于 timeout 机制为服务接口调用超时提供安全保护](/docs/high-availability/hystrix-timeout.md) ### 高可用系统 -- 如何设计一个高可用系统? +- 如何设计一个高可用系统? ### 限流 -- [如何限流?在工作中是怎么做的?说一下具体的实现?](/docs/high-concurrency/how-to-limit-current.md) +- [如何限流?在工作中是怎么做的?说一下具体的实现?](/docs/high-concurrency/how-to-limit-current.md) ### 熔断 -- 如何进行熔断? -- 熔断框架都有哪些?具体实现原理知道吗? -- [熔断框架如何做技术选型?选用 Sentinel 还是 Hystrix?](/docs/high-availability/sentinel-vs-hystrix.md) +- 如何进行熔断? +- 熔断框架都有哪些?具体实现原理知道吗? +- [熔断框架如何做技术选型?选用 Sentinel 还是 Hystrix?](/docs/high-availability/sentinel-vs-hystrix.md) ### 降级 -- 如何进行降级? +- 如何进行降级? ## 微服务架构 -- [微服务架构整个章节内容属额外新增,后续抽空更新,也欢迎读者们参与补充完善](https://github.com/doocs/advanced-java) -- [关于微服务架构的描述](/docs/micro-services/microservices-introduction.md) -- [从单体式架构迁移到微服务架构](/docs/micro-services/migrating-from-a-monolithic-architecture-to-a-microservices-architecture.md) -- [微服务的事件驱动数据管理](/docs/micro-services/event-driven-data-management-for-microservices.md) -- [选择微服务部署策略](/docs/micro-services/choose-microservice-deployment-strategy.md) -- [微服务架构的优势与不足](/docs/micro-services/advantages-and-disadvantages-of-microservice.md) +- [微服务架构整个章节内容属额外新增,后续抽空更新,也欢迎读者们参与补充完善](https://github.com/doocs/advanced-java) +- [关于微服务架构的描述](/docs/micro-services/microservices-introduction.md) +- [从单体式架构迁移到微服务架构](/docs/micro-services/migrating-from-a-monolithic-architecture-to-a-microservices-architecture.md) +- [微服务的事件驱动数据管理](/docs/micro-services/event-driven-data-management-for-microservices.md) +- [选择微服务部署策略](/docs/micro-services/choose-microservice-deployment-strategy.md) +- [微服务架构的优势与不足](/docs/micro-services/advantages-and-disadvantages-of-microservice.md) ### Spring Cloud 微服务架构 -- [什么是微服务?微服务之间是如何独立通讯的?](/docs/micro-services/what's-microservice-how-to-communicate.md) -- Spring Cloud 和 Dubbo 有哪些区别? -- Spring Boot 和 Spring Cloud,谈谈你对它们的理解? -- 什么是服务熔断?什么是服务降级? -- 微服务的优缺点分别是什么?说一下你在项目开发中碰到的坑? -- [你所知道的微服务技术栈都有哪些?](/docs/micro-services/micro-services-technology-stack.md) -- [微服务治理策略](/docs/micro-services/micro-service-governance.md) -- Eureka 和 Zookeeper 都可以提供服务注册与发现的功能,它们有什么区别? -- [谈谈服务发现组件 Eureka 的主要调用过程?](/docs/micro-services/how-eureka-enable-service-discovery-and-service-registration.md) -- ...... +- [什么是微服务?微服务之间是如何独立通讯的?](/docs/micro-services/what's-microservice-how-to-communicate.md) +- Spring Cloud 和 Dubbo 有哪些区别? +- Spring Boot 和 Spring Cloud,谈谈你对它们的理解? +- 什么是服务熔断?什么是服务降级? +- 微服务的优缺点分别是什么?说一下你在项目开发中碰到的坑? +- [你所知道的微服务技术栈都有哪些?](/docs/micro-services/micro-services-technology-stack.md) +- [微服务治理策略](/docs/micro-services/micro-service-governance.md) +- Eureka 和 Zookeeper 都可以提供服务注册与发现的功能,它们有什么区别? +- [谈谈服务发现组件 Eureka 的主要调用过程?](/docs/micro-services/how-eureka-enable-service-discovery-and-service-registration.md) +- ...... ## 海量数据处理 -- [如何从大量的 URL 中找出相同的 URL?](/docs/big-data/find-common-urls.md) -- [如何从大量数据中找出高频词?](/docs/big-data/find-top-100-words.md) -- [如何找出某一天访问百度网站最多的 IP?](/docs/big-data/find-top-1-ip.md) -- [如何在大量的数据中找出不重复的整数?](/docs/big-data/find-no-repeat-number.md) -- [如何在大量的数据中判断一个数是否存在?](/docs/big-data/find-a-number-if-exists.md) -- [如何查询最热门的查询串?](/docs/big-data/find-hotest-query-string.md) -- [如何统计不同电话号码的个数?](/docs/big-data/count-different-phone-numbers.md) -- [如何从 5 亿个数中找出中位数?](/docs/big-data/find-mid-value-in-500-millions.md) -- [如何按照 query 的频度排序?](/docs/big-data/sort-the-query-strings-by-counts.md) -- [如何找出排名前 500 的数?](/docs/big-data/find-rank-top-500-numbers.md) -- [讲讲大数据中 TopK 问题的常用套路?](/docs/big-data/topk-problems-and-solutions.md) +- [如何从大量的 URL 中找出相同的 URL?](/docs/big-data/find-common-urls.md) +- [如何从大量数据中找出高频词?](/docs/big-data/find-top-100-words.md) +- [如何找出某一天访问百度网站最多的 IP?](/docs/big-data/find-top-1-ip.md) +- [如何在大量的数据中找出不重复的整数?](/docs/big-data/find-no-repeat-number.md) +- [如何在大量的数据中判断一个数是否存在?](/docs/big-data/find-a-number-if-exists.md) +- [如何查询最热门的查询串?](/docs/big-data/find-hotest-query-string.md) +- [如何统计不同电话号码的个数?](/docs/big-data/count-different-phone-numbers.md) +- [如何从 5 亿个数中找出中位数?](/docs/big-data/find-mid-value-in-500-millions.md) +- [如何按照 query 的频度排序?](/docs/big-data/sort-the-query-strings-by-counts.md) +- [如何找出排名前 500 的数?](/docs/big-data/find-rank-top-500-numbers.md) +- [讲讲大数据中 TopK 问题的常用套路?](/docs/big-data/topk-problems-and-solutions.md) ## Stars 趋势 Stargazers over time -注:本趋势图由 [actions-starcharts](https://github.com/MaoLongLong/actions-starcharts) 自动定时刷新。 +注:本趋势图由 [actions-starcharts](https://github.com/MaoLongLong/actions-starcharts) 自动定时刷新,作者 [@MaoLongLong](https://github.com/maolonglong) --- diff --git a/docs/big-data/README.md b/docs/big-data/README.md index a5adaa90b..a1e1cb2b0 100644 --- a/docs/big-data/README.md +++ b/docs/big-data/README.md @@ -1,15 +1,15 @@ # 海量数据处理 -- [如何从大量的 URL 中找出相同的 URL?](/docs/big-data/find-common-urls.md) -- [如何从大量数据中找出高频词?](/docs/big-data/find-top-100-words.md) -- [如何找出某一天访问百度网站最多的 IP?](/docs/big-data/find-top-1-ip.md) -- [如何在大量的数据中找出不重复的整数?](/docs/big-data/find-no-repeat-number.md) -- [如何在大量的数据中判断一个数是否存在?](/docs/big-data/find-a-number-if-exists.md) -- [如何查询最热门的查询串?](/docs/big-data/find-hotest-query-string.md) -- [如何统计不同电话号码的个数?](/docs/big-data/count-different-phone-numbers.md) -- [如何从 5 亿个数中找出中位数?](/docs/big-data/find-mid-value-in-500-millions.md) -- [如何按照 query 的频度排序?](/docs/big-data/sort-the-query-strings-by-counts.md) -- [如何找出排名前 500 的数?](/docs/big-data/find-rank-top-500-numbers.md) +- [如何从大量的 URL 中找出相同的 URL?](/docs/big-data/find-common-urls.md) +- [如何从大量数据中找出高频词?](/docs/big-data/find-top-100-words.md) +- [如何找出某一天访问百度网站最多的 IP?](/docs/big-data/find-top-1-ip.md) +- [如何在大量的数据中找出不重复的整数?](/docs/big-data/find-no-repeat-number.md) +- [如何在大量的数据中判断一个数是否存在?](/docs/big-data/find-a-number-if-exists.md) +- [如何查询最热门的查询串?](/docs/big-data/find-hotest-query-string.md) +- [如何统计不同电话号码的个数?](/docs/big-data/count-different-phone-numbers.md) +- [如何从 5 亿个数中找出中位数?](/docs/big-data/find-mid-value-in-500-millions.md) +- [如何按照 query 的频度排序?](/docs/big-data/sort-the-query-strings-by-counts.md) +- [如何找出排名前 500 的数?](/docs/big-data/find-rank-top-500-numbers.md) --- diff --git a/docs/big-data/find-no-repeat-number.md b/docs/big-data/find-no-repeat-number.md index cb91e4332..0c3599b22 100644 --- a/docs/big-data/find-no-repeat-number.md +++ b/docs/big-data/find-no-repeat-number.md @@ -48,9 +48,9 @@ for i in range(8): **那么对于这道题**,我们用 2 个 bit 来表示各个数字的状态: -- 00 表示这个数字没出现过; -- 01 表示这个数字出现过一次(即为题目所找的不重复整数); -- 10 表示这个数字出现了多次。 +- 00 表示这个数字没出现过; +- 01 表示这个数字出现过一次(即为题目所找的不重复整数); +- 10 表示这个数字出现了多次。 那么这 232 个整数,总共所需内存为 232\*2b=1GB。因此,当可用内存超过 1GB 时,可以采用位图法。假设内存满足位图法需求,进行下面的操作: diff --git a/docs/big-data/sort-the-query-strings-by-counts.md b/docs/big-data/sort-the-query-strings-by-counts.md index 842fb3a19..f15db3a3a 100644 --- a/docs/big-data/sort-the-query-strings-by-counts.md +++ b/docs/big-data/sort-the-query-strings-by-counts.md @@ -20,5 +20,5 @@ ### 方法总结 -- 内存若够,直接读入进行排序; -- 内存不够,先划分为小文件,小文件排好序后,整理使用外排序进行归并。 +- 内存若够,直接读入进行排序; +- 内存不够,先划分为小文件,小文件排好序后,整理使用外排序进行归并。 diff --git a/docs/distributed-system/README.md b/docs/distributed-system/README.md index 34dff7ea2..cd1a79348 100644 --- a/docs/distributed-system/README.md +++ b/docs/distributed-system/README.md @@ -4,32 +4,32 @@ ## 系统拆分 -- [为什么要进行系统拆分?如何进行系统拆分?拆分后不用 Dubbo 可以吗?](/docs/distributed-system/why-dubbo.md) +- [为什么要进行系统拆分?如何进行系统拆分?拆分后不用 Dubbo 可以吗?](/docs/distributed-system/why-dubbo.md) ## 分布式服务框架 -- [说一下 Dubbo 的工作原理?注册中心挂了可以继续通信吗?](/docs/distributed-system/dubbo-operating-principle.md) -- [Dubbo 支持哪些序列化协议?说一下 Hessian 的数据结构?PB 知道吗?为什么 PB 的效率是最高的?](/docs/distributed-system/dubbo-serialization-protocol.md) -- [Dubbo 负载均衡策略和集群容错策略都有哪些?动态代理策略呢?](/docs/distributed-system/dubbo-load-balancing.md) -- [Dubbo 的 SPI 思想是什么?](/docs/distributed-system/dubbo-spi.md) -- [如何基于 Dubbo 进行服务治理、服务降级、失败重试以及超时重试?](/docs/distributed-system/dubbo-service-management.md) -- [分布式服务接口的幂等性如何设计(比如不能重复扣款)?](/docs/distributed-system/distributed-system-idempotency.md) -- [分布式服务接口请求的顺序性如何保证?](/docs/distributed-system/distributed-system-request-sequence.md) -- [如何自己设计一个类似 Dubbo 的 RPC 框架?](/docs/distributed-system/dubbo-rpc-design.md) -- [CAP 定理的 P 是什么](/docs/distributed-system/distributed-system-cap.md) +- [说一下 Dubbo 的工作原理?注册中心挂了可以继续通信吗?](/docs/distributed-system/dubbo-operating-principle.md) +- [Dubbo 支持哪些序列化协议?说一下 Hessian 的数据结构?PB 知道吗?为什么 PB 的效率是最高的?](/docs/distributed-system/dubbo-serialization-protocol.md) +- [Dubbo 负载均衡策略和集群容错策略都有哪些?动态代理策略呢?](/docs/distributed-system/dubbo-load-balancing.md) +- [Dubbo 的 SPI 思想是什么?](/docs/distributed-system/dubbo-spi.md) +- [如何基于 Dubbo 进行服务治理、服务降级、失败重试以及超时重试?](/docs/distributed-system/dubbo-service-management.md) +- [分布式服务接口的幂等性如何设计(比如不能重复扣款)?](/docs/distributed-system/distributed-system-idempotency.md) +- [分布式服务接口请求的顺序性如何保证?](/docs/distributed-system/distributed-system-request-sequence.md) +- [如何自己设计一个类似 Dubbo 的 RPC 框架?](/docs/distributed-system/dubbo-rpc-design.md) +- [CAP 定理的 P 是什么](/docs/distributed-system/distributed-system-cap.md) ## 分布式锁 -- [Zookeeper 都有哪些应用场景?](/docs/distributed-system/zookeeper-application-scenarios.md) -- [使用 Redis 如何设计分布式锁?使用 Zookeeper 来设计分布式锁可以吗?以上两种分布式锁的实现方式哪种效率比较高?](/docs/distributed-system/distributed-lock-redis-vs-zookeeper.md) +- [Zookeeper 都有哪些应用场景?](/docs/distributed-system/zookeeper-application-scenarios.md) +- [使用 Redis 如何设计分布式锁?使用 Zookeeper 来设计分布式锁可以吗?以上两种分布式锁的实现方式哪种效率比较高?](/docs/distributed-system/distributed-lock-redis-vs-zookeeper.md) ## 分布式事务 -- [分布式事务了解吗?你们如何解决分布式事务问题的?TCC 如果出现网络连不通怎么办?XA 的一致性如何保证?](/docs/distributed-system/distributed-transaction.md) +- [分布式事务了解吗?你们如何解决分布式事务问题的?TCC 如果出现网络连不通怎么办?XA 的一致性如何保证?](/docs/distributed-system/distributed-transaction.md) ## 分布式会话 -- [集群部署时的分布式 Session 如何实现?](/docs/distributed-system/distributed-session.md) +- [集群部署时的分布式 Session 如何实现?](/docs/distributed-system/distributed-session.md) --- diff --git a/docs/distributed-system/distributed-lock-redis-vs-zookeeper.md b/docs/distributed-system/distributed-lock-redis-vs-zookeeper.md index 4679ca366..e3d7f0407 100644 --- a/docs/distributed-system/distributed-lock-redis-vs-zookeeper.md +++ b/docs/distributed-system/distributed-lock-redis-vs-zookeeper.md @@ -14,17 +14,17 @@ 这个分布式锁有 3 个重要的考量点: -- 互斥(只能有一个客户端获取锁) -- 不能死锁 -- 容错(只要大部分 Redis 节点创建了这把锁就可以) +- 互斥(只能有一个客户端获取锁) +- 不能死锁 +- 容错(只要大部分 Redis 节点创建了这把锁就可以) #### Redis 最普通的分布式锁 第一个最普通的实现方式,就是在 Redis 里使用 `SET key value [EX seconds] [PX milliseconds] NX` 创建一个 key,这样就算加锁。其中: -- `NX`:表示只有 `key` 不存在的时候才会设置成功,如果此时 redis 中存在这个 `key`,那么设置失败,返回 `nil`。 -- `EX seconds`:设置 `key` 的过期时间,精确到秒级。意思是 `seconds` 秒后锁自动释放,别人创建的时候如果发现已经有了就不能加锁了。 -- `PX milliseconds`:同样是设置 `key` 的过期时间,精确到毫秒级。 +- `NX`:表示只有 `key` 不存在的时候才会设置成功,如果此时 redis 中存在这个 `key`,那么设置失败,返回 `nil`。 +- `EX seconds`:设置 `key` 的过期时间,精确到秒级。意思是 `seconds` 秒后锁自动释放,别人创建的时候如果发现已经有了就不能加锁了。 +- `PX milliseconds`:同样是设置 `key` 的过期时间,精确到毫秒级。 比如执行以下命令: @@ -332,8 +332,8 @@ public class ZooKeeperDistributedLock implements Watcher { ### redis 分布式锁和 zk 分布式锁的对比 -- redis 分布式锁,其实**需要自己不断去尝试获取锁**,比较消耗性能。 -- zk 分布式锁,获取不到锁,注册个监听器即可,不需要不断主动尝试获取锁,性能开销较小。 +- redis 分布式锁,其实**需要自己不断去尝试获取锁**,比较消耗性能。 +- zk 分布式锁,获取不到锁,注册个监听器即可,不需要不断主动尝试获取锁,性能开销较小。 另外一点就是,如果是 Redis 获取锁的那个客户端 出现 bug 挂了,那么只能等待超时时间之后才能释放锁;而 zk 的话,因为创建的是临时 znode,只要客户端挂了,znode 就没了,此时就自动释放锁。 diff --git a/docs/distributed-system/distributed-system-cap.md b/docs/distributed-system/distributed-system-cap.md index a2ec79fff..33bb333af 100644 --- a/docs/distributed-system/distributed-system-cap.md +++ b/docs/distributed-system/distributed-system-cap.md @@ -8,17 +8,17 @@ 在理论计算机科学中,CAP 定理(CAP theorem),又被称作布鲁尔定理(Brewer's theorem),它指出对于一个分布式计算系统来说,不可能同时满足以下三点: -- 一致性(Consistency) (等同于所有节点访问同一份最新的数据副本) -- 可用性(Availability)(每次请求都能获取到非错的响应——但是不保证获取的数据为最新数据) -- 分区容错性(Partition tolerance)(以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在 C 和 A 之间做出选择。) +- 一致性(Consistency) (等同于所有节点访问同一份最新的数据副本) +- 可用性(Availability)(每次请求都能获取到非错的响应——但是不保证获取的数据为最新数据) +- 分区容错性(Partition tolerance)(以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在 C 和 A 之间做出选择。) ### 分区容错性(Partition tolerance) 理解 CAP 理论的最简单方式是想象两个节点分处分区两侧。允许至少一个节点更新状态会导致数据不一致,即丧失了 C 性质。如果为了保证数据一致性,将分区一侧的节点设置为不可用,那么又丧失了 A 性质。除非两个节点可以互相通信,才能既保证 C 又保证 A,这又会导致丧失 P 性质。 -- P 指的是分区容错性,分区现象产生后需要容错,容错是指在 A 与 C 之间选择。如果分布式系统没有分区现象(没有出现不一致不可用情况) 本身就没有分区 ,既然没有分区则就更没有分区容错性 P。 -- 无论我设计的系统是 AP 还是 CP 系统如果没有出现不一致不可用。 则该系统就处于 CA 状态 -- P 的体现前提是得有分区情况存在 +- P 指的是分区容错性,分区现象产生后需要容错,容错是指在 A 与 C 之间选择。如果分布式系统没有分区现象(没有出现不一致不可用情况) 本身就没有分区 ,既然没有分区则就更没有分区容错性 P。 +- 无论我设计的系统是 AP 还是 CP 系统如果没有出现不一致不可用。 则该系统就处于 CA 状态 +- P 的体现前提是得有分区情况存在 > 文章来源:[维基百科 CAP 定理](https://zh.wikipedia.org/wiki/CAP%E5%AE%9A%E7%90%86) diff --git a/docs/distributed-system/distributed-system-idempotency.md b/docs/distributed-system/distributed-system-idempotency.md index 4d012a586..55199773d 100644 --- a/docs/distributed-system/distributed-system-idempotency.md +++ b/docs/distributed-system/distributed-system-idempotency.md @@ -22,9 +22,9 @@ 其实保证幂等性主要是三点: -- 对于每个请求必须有一个唯一的标识,举个栗子:订单支付请求,肯定得包含订单 id,一个订单 id 最多支付一次,对吧。 -- 每次处理完请求之后,必须有一个记录标识这个请求处理过了。常见的方案是在 mysql 中记录个状态啥的,比如支付之前记录一条这个订单的支付流水。 -- 每次接收请求需要进行判断,判断之前是否处理过。比如说,如果有一个订单已经支付了,就已经有了一条支付流水,那么如果重复发送这个请求,则此时先插入支付流水,orderId 已经存在了,唯一键约束生效,报错插入不进去的。然后你就不用再扣款了。 +- 对于每个请求必须有一个唯一的标识,举个栗子:订单支付请求,肯定得包含订单 id,一个订单 id 最多支付一次,对吧。 +- 每次处理完请求之后,必须有一个记录标识这个请求处理过了。常见的方案是在 mysql 中记录个状态啥的,比如支付之前记录一条这个订单的支付流水。 +- 每次接收请求需要进行判断,判断之前是否处理过。比如说,如果有一个订单已经支付了,就已经有了一条支付流水,那么如果重复发送这个请求,则此时先插入支付流水,orderId 已经存在了,唯一键约束生效,报错插入不进去的。然后你就不用再扣款了。 实际运作过程中,你要结合自己的业务来,比如说利用 Redis,用 orderId 作为唯一键。只有成功插入这个支付流水,才可以执行实际的支付扣款。 diff --git a/docs/distributed-system/distributed-system-interview.md b/docs/distributed-system/distributed-system-interview.md index adec6cd18..dba56dfcf 100644 --- a/docs/distributed-system/distributed-system-interview.md +++ b/docs/distributed-system/distributed-system-interview.md @@ -12,27 +12,27 @@ ### 为什么要进行系统拆分? -- 为什么要进行系统拆分?如何进行系统拆分?拆分后不用 Dubbo 可以吗?Dubbo 和 thrift 有什么区别呢? +- 为什么要进行系统拆分?如何进行系统拆分?拆分后不用 Dubbo 可以吗?Dubbo 和 thrift 有什么区别呢? ### 分布式服务框架 -- 说一下的 Dubbo 的工作原理?注册中心挂了可以继续通信吗? -- Dubbo 支持哪些序列化协议?说一下 Hessian 的数据结构?PB 知道吗?为什么 PB 的效率是最高的? -- Dubbo 负载均衡策略和高可用策略都有哪些?动态代理策略呢? -- Dubbo 的 SPI 思想是什么? -- 如何基于 Dubbo 进行服务治理、服务降级、失败重试以及超时重试? -- 分布式服务接口的幂等性如何设计(比如不能重复扣款)? -- 分布式服务接口请求的顺序性如何保证? -- 如何自己设计一个类似 Dubbo 的 RPC 框架? +- 说一下的 Dubbo 的工作原理?注册中心挂了可以继续通信吗? +- Dubbo 支持哪些序列化协议?说一下 Hessian 的数据结构?PB 知道吗?为什么 PB 的效率是最高的? +- Dubbo 负载均衡策略和高可用策略都有哪些?动态代理策略呢? +- Dubbo 的 SPI 思想是什么? +- 如何基于 Dubbo 进行服务治理、服务降级、失败重试以及超时重试? +- 分布式服务接口的幂等性如何设计(比如不能重复扣款)? +- 分布式服务接口请求的顺序性如何保证? +- 如何自己设计一个类似 Dubbo 的 RPC 框架? ### 分布式锁 -- 使用 Redis 如何设计分布式锁?使用 zk 来设计分布式锁可以吗?这两种分布式锁的实现方式哪种效率比较高? +- 使用 Redis 如何设计分布式锁?使用 zk 来设计分布式锁可以吗?这两种分布式锁的实现方式哪种效率比较高? ### 分布式事务 -- 分布式事务了解吗?你们如何解决分布式事务问题的?TCC 如果出现网络连不通怎么办?XA 的一致性如何保证? +- 分布式事务了解吗?你们如何解决分布式事务问题的?TCC 如果出现网络连不通怎么办?XA 的一致性如何保证? ### 分布式会话 -- 集群部署时的分布式 Session 如何实现? +- 集群部署时的分布式 Session 如何实现? diff --git a/docs/distributed-system/distributed-transaction.md b/docs/distributed-system/distributed-transaction.md index a0702d392..8b2a2b9e4 100644 --- a/docs/distributed-system/distributed-transaction.md +++ b/docs/distributed-system/distributed-transaction.md @@ -12,12 +12,12 @@ 分布式事务的实现主要有以下 6 种方案: -- XA 方案 -- TCC 方案 -- SAGA 方案 -- 本地消息表 -- 可靠消息最终一致性方案 -- 最大努力通知方案 +- XA 方案 +- TCC 方案 +- SAGA 方案 +- 本地消息表 +- 可靠消息最终一致性方案 +- 最大努力通知方案 ### 两阶段提交方案/XA 方案 @@ -37,9 +37,9 @@ TCC 的全称是: `Try` 、 `Confirm` 、 `Cancel` 。 -- Try 阶段:这个阶段说的是对各个服务的资源做检测以及对资源进行**锁定或者预留**。 -- Confirm 阶段:这个阶段说的是在各个服务中**执行实际的操作**。 -- Cancel 阶段:如果任何一个服务的业务方法执行出错,那么这里就需要**进行补偿**,就是执行已经执行成功的业务逻辑的回滚操作。(把那些执行成功的回滚) +- Try 阶段:这个阶段说的是对各个服务的资源做检测以及对资源进行**锁定或者预留**。 +- Confirm 阶段:这个阶段说的是在各个服务中**执行实际的操作**。 +- Cancel 阶段:如果任何一个服务的业务方法执行出错,那么这里就需要**进行补偿**,就是执行已经执行成功的业务逻辑的回滚操作。(把那些执行成功的回滚) 这种方案说实话几乎很少人使用,我们用的也比较少,但是也有使用的场景。因为这个**事务回滚**实际上是**严重依赖于你自己写代码来回滚和补偿**了,会造成补偿代码巨大,非常之恶心。 @@ -69,18 +69,18 @@ TCC 的全称是: `Try` 、 `Confirm` 、 `Cancel` 。 所以 Saga 模式的适用场景是: -- 业务流程长、业务流程多; -- 参与者包含其它公司或遗留系统服务,无法提供 TCC 模式要求的三个接口。 +- 业务流程长、业务流程多; +- 参与者包含其它公司或遗留系统服务,无法提供 TCC 模式要求的三个接口。 #### 优势 -- 一阶段提交本地事务,无锁,高性能; -- 参与者可异步执行,高吞吐; -- 补偿服务易于实现,因为一个更新操作的反向操作是比较容易理解的。 +- 一阶段提交本地事务,无锁,高性能; +- 参与者可异步执行,高吞吐; +- 补偿服务易于实现,因为一个更新操作的反向操作是比较容易理解的。 #### 缺点 -- 不保证事务的隔离性。 +- 不保证事务的隔离性。 ### 本地消息表 diff --git a/docs/distributed-system/dubbo-load-balancing.md b/docs/distributed-system/dubbo-load-balancing.md index 2b8361fc2..1dc272474 100644 --- a/docs/distributed-system/dubbo-load-balancing.md +++ b/docs/distributed-system/dubbo-load-balancing.md @@ -8,10 +8,10 @@ dubbo 负载均衡策略和集群容错策略都有哪些?动态代理策略 说白了,就是看你对 dubbo 熟悉不熟悉: -- dubbo 工作原理:服务注册、注册中心、消费者、代理通信、负载均衡; -- 网络通信、序列化:dubbo 协议、长连接、NIO、hessian 序列化协议; -- 负载均衡策略、集群容错策略、动态代理策略:dubbo 跑起来的时候一些功能是如何运转的?怎么做负载均衡?怎么做集群容错?怎么生成动态代理? -- dubbo SPI 机制:你了解不了解 dubbo 的 SPI 机制?如何基于 SPI 机制对 dubbo 进行扩展? +- dubbo 工作原理:服务注册、注册中心、消费者、代理通信、负载均衡; +- 网络通信、序列化:dubbo 协议、长连接、NIO、hessian 序列化协议; +- 负载均衡策略、集群容错策略、动态代理策略:dubbo 跑起来的时候一些功能是如何运转的?怎么做负载均衡?怎么做集群容错?怎么生成动态代理? +- dubbo SPI 机制:你了解不了解 dubbo 的 SPI 机制?如何基于 SPI 机制对 dubbo 进行扩展? ## 面试题剖析 diff --git a/docs/distributed-system/dubbo-operating-principle.md b/docs/distributed-system/dubbo-operating-principle.md index d9d06c7ed..89e9c216b 100644 --- a/docs/distributed-system/dubbo-operating-principle.md +++ b/docs/distributed-system/dubbo-operating-principle.md @@ -16,23 +16,23 @@ MQ、ES、Redis、Dubbo,上来先问你一些**思考性的问题**、**原理 ### dubbo 工作原理 -- 第一层:service 层,接口层,给服务提供者和消费者来实现的 -- 第二层:config 层,配置层,主要是对 dubbo 进行各种配置的 -- 第三层:proxy 层,服务代理层,无论是 consumer 还是 provider,dubbo 都会给你生成代理,代理之间进行网络通信 -- 第四层:registry 层,服务注册层,负责服务的注册与发现 -- 第五层:cluster 层,集群层,封装多个服务提供者的路由以及负载均衡,将多个实例组合成一个服务 -- 第六层:monitor 层,监控层,对 rpc 接口的调用次数和调用时间进行监控 -- 第七层:protocal 层,远程调用层,封装 rpc 调用 -- 第八层:exchange 层,信息交换层,封装请求响应模式,同步转异步 -- 第九层:transport 层,网络传输层,抽象 mina 和 netty 为统一接口 -- 第十层:serialize 层,数据序列化层 +- 第一层:service 层,接口层,给服务提供者和消费者来实现的 +- 第二层:config 层,配置层,主要是对 dubbo 进行各种配置的 +- 第三层:proxy 层,服务代理层,无论是 consumer 还是 provider,dubbo 都会给你生成代理,代理之间进行网络通信 +- 第四层:registry 层,服务注册层,负责服务的注册与发现 +- 第五层:cluster 层,集群层,封装多个服务提供者的路由以及负载均衡,将多个实例组合成一个服务 +- 第六层:monitor 层,监控层,对 rpc 接口的调用次数和调用时间进行监控 +- 第七层:protocal 层,远程调用层,封装 rpc 调用 +- 第八层:exchange 层,信息交换层,封装请求响应模式,同步转异步 +- 第九层:transport 层,网络传输层,抽象 mina 和 netty 为统一接口 +- 第十层:serialize 层,数据序列化层 ### 工作流程 -- 第一步:provider 向注册中心去注册 -- 第二步:consumer 从注册中心订阅服务,注册中心会通知 consumer 注册好的服务 -- 第三步:consumer 调用 provider -- 第四步:consumer 和 provider 都异步通知监控中心 +- 第一步:provider 向注册中心去注册 +- 第二步:consumer 从注册中心订阅服务,注册中心会通知 consumer 注册好的服务 +- 第三步:consumer 调用 provider +- 第四步:consumer 和 provider 都异步通知监控中心 ![dubbo-operating-principle](./images/dubbo-operating-principle.png) diff --git a/docs/distributed-system/dubbo-rpc-design.md b/docs/distributed-system/dubbo-rpc-design.md index c35fa93f9..cbc90f17e 100644 --- a/docs/distributed-system/dubbo-rpc-design.md +++ b/docs/distributed-system/dubbo-rpc-design.md @@ -6,8 +6,8 @@ 说实话,就这问题,其实就跟问你如何自己设计一个 MQ 一样的道理,就考两个: -- 你有没有对某个 rpc 框架原理有非常深入的理解。 -- 你能不能从整体上来思考一下,如何设计一个 rpc 框架,考考你的系统设计能力。 +- 你有没有对某个 rpc 框架原理有非常深入的理解。 +- 你能不能从整体上来思考一下,如何设计一个 rpc 框架,考考你的系统设计能力。 ## 面试题剖析 @@ -17,11 +17,11 @@ 举个栗子,我给大家说个最简单的回答思路: -- 上来你的服务就得去注册中心注册吧,你是不是得有个注册中心,保留各个服务的信息,可以用 zookeeper 来做,对吧。 -- 然后你的消费者需要去注册中心拿对应的服务信息吧,对吧,而且每个服务可能会存在于多台机器上。 -- 接着你就该发起一次请求了,咋发起?当然是基于动态代理了,你面向接口获取到一个动态代理,这个动态代理就是接口在本地的一个代理,然后这个代理会找到服务对应的机器地址。 -- 然后找哪个机器发送请求?那肯定得有个负载均衡算法了,比如最简单的可以随机轮询是不是。 -- 接着找到一台机器,就可以跟它发送请求了,第一个问题咋发送?你可以说用 netty 了,nio 方式;第二个问题发送啥格式数据?你可以说用 hessian 序列化协议了,或者是别的,对吧。然后请求过去了。 -- 服务器那边一样的,需要针对你自己的服务生成一个动态代理,监听某个网络端口了,然后代理你本地的服务代码。接收到请求的时候,就调用对应的服务代码,对吧。 +- 上来你的服务就得去注册中心注册吧,你是不是得有个注册中心,保留各个服务的信息,可以用 zookeeper 来做,对吧。 +- 然后你的消费者需要去注册中心拿对应的服务信息吧,对吧,而且每个服务可能会存在于多台机器上。 +- 接着你就该发起一次请求了,咋发起?当然是基于动态代理了,你面向接口获取到一个动态代理,这个动态代理就是接口在本地的一个代理,然后这个代理会找到服务对应的机器地址。 +- 然后找哪个机器发送请求?那肯定得有个负载均衡算法了,比如最简单的可以随机轮询是不是。 +- 接着找到一台机器,就可以跟它发送请求了,第一个问题咋发送?你可以说用 netty 了,nio 方式;第二个问题发送啥格式数据?你可以说用 hessian 序列化协议了,或者是别的,对吧。然后请求过去了。 +- 服务器那边一样的,需要针对你自己的服务生成一个动态代理,监听某个网络端口了,然后代理你本地的服务代码。接收到请求的时候,就调用对应的服务代码,对吧。 这就是一个最最基本的 rpc 框架的思路,先不说你有多牛逼的技术功底,哪怕这个最简单的思路你先给出来行不行? diff --git a/docs/distributed-system/dubbo-serialization-protocol.md b/docs/distributed-system/dubbo-serialization-protocol.md index 7e5ad5fd6..c1e53f1ea 100644 --- a/docs/distributed-system/dubbo-serialization-protocol.md +++ b/docs/distributed-system/dubbo-serialization-protocol.md @@ -16,7 +16,7 @@ dubbo 支持哪些通信协议?支持哪些序列化协议?说一下 Hessian ### dubbo 支持不同的通信协议 -- dubbo 协议 `dubbo://` +- dubbo 协议 `dubbo://` **默认**就是走 dubbo 协议,单一长连接,进行的是 NIO 异步通信,基于 hessian 作为序列化协议。使用的场景是:传输数据量小(每次请求在 100kb 以内),但是并发量很高,以及服务消费者机器数远大于服务提供者机器数的情况。 @@ -30,39 +30,39 @@ dubbo 支持哪些通信协议?支持哪些序列化协议?说一下 Hessian ![dubbo-not-keep-connection](./images/dubbo-not-keep-connection.png) -- rmi 协议 `rmi://` +- rmi 协议 `rmi://` RMI 协议采用 JDK 标准的 java.rmi.\* 实现,采用阻塞式短连接和 JDK 标准序列化方式。多个短连接,适合消费者和提供者数量差不多的情况,适用于文件的传输,一般较少用。 -- hessian 协议 `hessian://` +- hessian 协议 `hessian://` Hessian 1 协议用于集成 Hessian 的服务,Hessian 底层采用 Http 通讯,采用 Servlet 暴露服务,Dubbo 缺省内嵌 Jetty 作为服务器实现。走 hessian 序列化协议,多个短连接,适用于提供者数量比消费者数量还多的情况,适用于文件的传输,一般较少用。 -- http 协议 `http://` +- http 协议 `http://` 基于 HTTP 表单的远程调用协议,采用 Spring 的 HttpInvoker 实现。走表单序列化。 -- thrift 协议 `thrift://` +- thrift 协议 `thrift://` 当前 dubbo 支持的 thrift 协议是对 thrift 原生协议的扩展,在原生协议的基础上添加了一些额外的头信息,比如 service name,magic number 等。 -- webservice `webservice://` +- webservice `webservice://` 基于 WebService 的远程调用协议,基于 Apache CXF 的 frontend-simple 和 transports-http 实现。走 SOAP 文本序列化。 -- memcached 协议 `memcached://` +- memcached 协议 `memcached://` 基于 memcached 实现的 RPC 协议。 -- redis 协议 `redis://` +- redis 协议 `redis://` 基于 Redis 实现的 RPC 协议。 -- rest 协议 `rest://` +- rest 协议 `rest://` 基于标准的 Java REST API——JAX-RS 2.0(Java API for RESTful Web Services 的简写)实现的 REST 调用支持。 -- gPRC 协议 `grpc://` +- gPRC 协议 `grpc://` Dubbo 自 2.7.5 版本开始支持 gRPC 协议,对于计划使用 HTTP/2 通信,或者想利用 gRPC 带来的 Stream、反压、Reactive 编程等能力的开发者来说, 都可以考虑启用 gRPC 协议。 @@ -74,24 +74,24 @@ dubbo 支持 hession、Java 二进制序列化、json、SOAP 文本序列化多 Hessian 的对象序列化机制有 8 种原始类型: -- 原始二进制数据 -- boolean -- 64-bit date(64 位毫秒值的日期) -- 64-bit double -- 32-bit int -- 64-bit long -- null -- UTF-8 编码的 string +- 原始二进制数据 +- boolean +- 64-bit date(64 位毫秒值的日期) +- 64-bit double +- 32-bit int +- 64-bit long +- null +- UTF-8 编码的 string 另外还包括 3 种递归类型: -- list for lists and arrays -- map for maps and dictionaries -- object for objects +- list for lists and arrays +- map for maps and dictionaries +- object for objects 还有一种特殊的类型: -- ref:用来表示对共享对象的引用。 +- ref:用来表示对共享对象的引用。 ### 为什么 PB 的效率是最高的? diff --git a/docs/distributed-system/dubbo-service-management.md b/docs/distributed-system/dubbo-service-management.md index a84f505c2..9581fdcbe 100644 --- a/docs/distributed-system/dubbo-service-management.md +++ b/docs/distributed-system/dubbo-service-management.md @@ -28,17 +28,17 @@ 需要自动统计**各个接口和服务之间的调用次数以及访问延时**,而且要分成两个级别。 -- 一个级别是接口粒度,就是每个服务的每个接口每天被调用多少次,TP50/TP90/TP99,三个档次的请求延时分别是多少; -- 第二个级别是从源头入口开始,一个完整的请求链路经过几十个服务之后,完成一次请求,每天全链路走多少次,全链路请求延时的 TP50/TP90/TP99,分别是多少。 +- 一个级别是接口粒度,就是每个服务的每个接口每天被调用多少次,TP50/TP90/TP99,三个档次的请求延时分别是多少; +- 第二个级别是从源头入口开始,一个完整的请求链路经过几十个服务之后,完成一次请求,每天全链路走多少次,全链路请求延时的 TP50/TP90/TP99,分别是多少。 这些东西都搞定了之后,后面才可以来看当前系统的压力主要在哪里,如何来扩容和优化啊。 #### 3. 其它 -- 服务分层(避免循环依赖) -- 调用链路失败监控和报警 -- 服务鉴权 -- 每个服务的可用性的监控(接口调用成功率?几个 9?99.99%,99.9%,99%) +- 服务分层(避免循环依赖) +- 调用链路失败监控和报警 +- 服务鉴权 +- 每个服务的可用性的监控(接口调用成功率?几个 9?99.99%,99.9%,99%) ### 服务降级 @@ -115,5 +115,5 @@ public class HelloServiceMock implements HelloService { 可以结合你们公司具体的场景来说说你是怎么设置这些参数的: -- `timeout` :一般设置为 `200ms` ,我们认为不能超过 `200ms` 还没返回。 -- `retries` :设置 retries,一般是在读请求的时候,比如你要查询个数据,你可以设置个 retries,如果第一次没读到,报错,重试指定的次数,尝试再次读取。 +- `timeout` :一般设置为 `200ms` ,我们认为不能超过 `200ms` 还没返回。 +- `retries` :设置 retries,一般是在读请求的时候,比如你要查询个数据,你可以设置个 retries,如果第一次没读到,报错,重试指定的次数,尝试再次读取。 diff --git a/docs/distributed-system/zookeeper-application-scenarios.md b/docs/distributed-system/zookeeper-application-scenarios.md index 17a411161..c3ee12506 100644 --- a/docs/distributed-system/zookeeper-application-scenarios.md +++ b/docs/distributed-system/zookeeper-application-scenarios.md @@ -14,10 +14,10 @@ zookeeper 都有哪些使用场景? 大致来说,zookeeper 的使用场景如下,我就举几个简单的,大家能说几个就好了: -- 分布式协调 -- 分布式锁 -- 元数据/配置信息管理 -- HA 高可用性 +- 分布式协调 +- 分布式锁 +- 元数据/配置信息管理 +- HA 高可用性 ### 分布式协调 diff --git a/docs/extra-page/README.md b/docs/extra-page/README.md index 8fdbbb10c..a755da75d 100644 --- a/docs/extra-page/README.md +++ b/docs/extra-page/README.md @@ -2,18 +2,18 @@ ## Offer 与进阶 -- [我的 Offer 在哪里?](https://doocs.gitee.io/advanced-java/#/docs/extra-page/offer) -- [让我们同步进阶!](https://doocs.gitee.io/advanced-java/#/docs/extra-page/advanced) +- [我的 Offer 在哪里?](https://doocs.gitee.io/advanced-java/#/docs/extra-page/offer) +- [让我们同步进阶!](https://doocs.gitee.io/advanced-java/#/docs/extra-page/advanced) ## 项目 Pages 站点 -- [Netlify](https://adjava.netlify.app) -- [Gitee Pages](https://doocs.gitee.io/advanced-java) -- [GitHub Pages](https://doocs.github.io/advanced-java) +- [Netlify](https://adjava.netlify.app) +- [Gitee Pages](https://doocs.gitee.io/advanced-java) +- [GitHub Pages](https://doocs.github.io/advanced-java) ## 维权行动 -- [维护他人知识产权,尊重他人劳动成果](./rights-defending-action.md) +- [维护他人知识产权,尊重他人劳动成果](./rights-defending-action.md) --- diff --git a/docs/extra-page/subscriptions-for-doocs.md b/docs/extra-page/subscriptions-for-doocs.md index 5a1297007..147ffa790 100644 --- a/docs/extra-page/subscriptions-for-doocs.md +++ b/docs/extra-page/subscriptions-for-doocs.md @@ -16,8 +16,8 @@ GitHub 开源社区 Doocs 旗下唯一公众号“**Doocs**”,专注于挖掘 ## 公众号的定位是怎样的? -- **内容高质**:不随意从网上复制粘贴一些文章,即便是转载的技术文章,也要确保质量。 -- **定期更新**:尽量在每周输出 1-2 篇文章,保证一定的更新频率。 +- **内容高质**:不随意从网上复制粘贴一些文章,即便是转载的技术文章,也要确保质量。 +- **定期更新**:尽量在每周输出 1-2 篇文章,保证一定的更新频率。
@@ -27,21 +27,21 @@ GitHub 开源社区 Doocs 旗下唯一公众号“**Doocs**”,专注于挖掘 因为刚刚推出公众号,目前有以下几篇文章,来先睹为快吧: -- [硬核!亿级流量秒杀系统设计](https://mp.weixin.qq.com/s/Mo_knIRBQQL2s-D2aieZLg) -- [技术面试是否要看面经?面试官/面试者有话说!](https://mp.weixin.qq.com/s/fNiUmbY395rsPdEC0QDIrw) -- [如何破解极验滑动验证码?成功率 100%!](https://mp.weixin.qq.com/s/Fsl6qYN5Dw4s6Du893MkFQ) -- [免费且好用的图床,就你了,「图壳」!](https://mp.weixin.qq.com/s/0HhgHLo_tTRFZcC-CVjDbw) -- [阿里又一个 20k+ stars 开源项目诞生,恭喜 fastjson!](https://mp.weixin.qq.com/s/RNKDCK2KoyeuMeEs6GUrow) -- [刷掉 90% 候选人的互联网大厂海量数据面试题(附题解 + 方法总结)](https://mp.weixin.qq.com/s/rjGqxUvrEqJNlo09GrT1Dw) -- [好用!期待已久的文本块功能究竟如何在 Java 13 中发挥作用?](https://mp.weixin.qq.com/s/kalGv5T8AZGxTnLHr2wDsA) -- [2019 GitHub 开源贡献排行榜新鲜出炉!微软谷歌领头,阿里跻身前 12!](https://mp.weixin.qq.com/s/_q812aGD1b9QvZ2WFI0Qgw) -- [Google 搜索的即时自动补全功能究竟是如何“工作”的?](https://mp.weixin.qq.com/s/YlMISSc3Sn890BzTLytcLA) -- [厉害了,原来 Redisson 这么好用!](https://mp.weixin.qq.com/s/lpZ7eRdImy0MyTEVH68HYw) -- [一文带你搞懂 “缓存策略”](https://mp.weixin.qq.com/s/47A_iXY_nArURwUTPHr2IQ) -- [Java Getter/Setter “防坑指南”](https://mp.weixin.qq.com/s/TZqcAw7NTlcvU-p930-eHA) -- [太棒了,GitHub Review 代码能力小升级](https://mp.weixin.qq.com/s/Lok0epqn91Q51ygZo_FLkg) -- [巧用 Redis Hyperloglog,轻松统计 UV 数据](https://mp.weixin.qq.com/s/w1r-M6YVvQSfUtzO_xe44Q) -- [如何开启「GitHub+码云」双工作流模式?](https://mp.weixin.qq.com/s/byxAjr3-ifWfDYQcR7YA8Q) +- [硬核!亿级流量秒杀系统设计](https://mp.weixin.qq.com/s/Mo_knIRBQQL2s-D2aieZLg) +- [技术面试是否要看面经?面试官/面试者有话说!](https://mp.weixin.qq.com/s/fNiUmbY395rsPdEC0QDIrw) +- [如何破解极验滑动验证码?成功率 100%!](https://mp.weixin.qq.com/s/Fsl6qYN5Dw4s6Du893MkFQ) +- [免费且好用的图床,就你了,「图壳」!](https://mp.weixin.qq.com/s/0HhgHLo_tTRFZcC-CVjDbw) +- [阿里又一个 20k+ stars 开源项目诞生,恭喜 fastjson!](https://mp.weixin.qq.com/s/RNKDCK2KoyeuMeEs6GUrow) +- [刷掉 90% 候选人的互联网大厂海量数据面试题(附题解 + 方法总结)](https://mp.weixin.qq.com/s/rjGqxUvrEqJNlo09GrT1Dw) +- [好用!期待已久的文本块功能究竟如何在 Java 13 中发挥作用?](https://mp.weixin.qq.com/s/kalGv5T8AZGxTnLHr2wDsA) +- [2019 GitHub 开源贡献排行榜新鲜出炉!微软谷歌领头,阿里跻身前 12!](https://mp.weixin.qq.com/s/_q812aGD1b9QvZ2WFI0Qgw) +- [Google 搜索的即时自动补全功能究竟是如何“工作”的?](https://mp.weixin.qq.com/s/YlMISSc3Sn890BzTLytcLA) +- [厉害了,原来 Redisson 这么好用!](https://mp.weixin.qq.com/s/lpZ7eRdImy0MyTEVH68HYw) +- [一文带你搞懂 “缓存策略”](https://mp.weixin.qq.com/s/47A_iXY_nArURwUTPHr2IQ) +- [Java Getter/Setter “防坑指南”](https://mp.weixin.qq.com/s/TZqcAw7NTlcvU-p930-eHA) +- [太棒了,GitHub Review 代码能力小升级](https://mp.weixin.qq.com/s/Lok0epqn91Q51ygZo_FLkg) +- [巧用 Redis Hyperloglog,轻松统计 UV 数据](https://mp.weixin.qq.com/s/w1r-M6YVvQSfUtzO_xe44Q) +- [如何开启「GitHub+码云」双工作流模式?](https://mp.weixin.qq.com/s/byxAjr3-ifWfDYQcR7YA8Q) 后续将推出一系列原创干货文章,敬请期待。 diff --git a/docs/high-availability/README.md b/docs/high-availability/README.md index e1c8e1aed..66d562ebb 100644 --- a/docs/high-availability/README.md +++ b/docs/high-availability/README.md @@ -1,34 +1,34 @@ # 高可用架构 -- [Hystrix 介绍](./hystrix-introduction.md) -- [电商网站详情页系统架构](./e-commerce-website-detail-page-architecture.md) -- [Hystrix 线程池技术实现资源隔离](./hystrix-thread-pool-isolation.md) -- [Hystrix 信号量机制实现资源隔离](./hystrix-semphore-isolation.md) -- [Hystrix 隔离策略细粒度控制](./hystrix-execution-isolation.md) -- [深入 Hystrix 执行时内部原理](./hystrix-process.md) -- [基于 request cache 请求缓存技术优化批量商品数据查询接口](./hystrix-request-cache.md) -- [基于本地缓存的 fallback 降级机制](./hystrix-fallback.md) -- [深入 Hystrix 断路器执行原理](./hystrix-circuit-breaker.md) -- [深入 Hystrix 线程池隔离与接口限流](./hystrix-thread-pool-current-limiting.md) -- [基于 timeout 机制为服务接口调用超时提供安全保护](./hystrix-timeout.md) +- [Hystrix 介绍](./hystrix-introduction.md) +- [电商网站详情页系统架构](./e-commerce-website-detail-page-architecture.md) +- [Hystrix 线程池技术实现资源隔离](./hystrix-thread-pool-isolation.md) +- [Hystrix 信号量机制实现资源隔离](./hystrix-semphore-isolation.md) +- [Hystrix 隔离策略细粒度控制](./hystrix-execution-isolation.md) +- [深入 Hystrix 执行时内部原理](./hystrix-process.md) +- [基于 request cache 请求缓存技术优化批量商品数据查询接口](./hystrix-request-cache.md) +- [基于本地缓存的 fallback 降级机制](./hystrix-fallback.md) +- [深入 Hystrix 断路器执行原理](./hystrix-circuit-breaker.md) +- [深入 Hystrix 线程池隔离与接口限流](./hystrix-thread-pool-current-limiting.md) +- [基于 timeout 机制为服务接口调用超时提供安全保护](./hystrix-timeout.md) ## 高可用系统 -- 如何设计一个高可用系统? +- 如何设计一个高可用系统? ## 限流 -- 如何限流?在工作中是怎么做的?说一下具体的实现? +- 如何限流?在工作中是怎么做的?说一下具体的实现? ## 熔断 -- 如何进行熔断? -- 熔断框架都有哪些?具体实现原理知道吗? -- [熔断框架如何做技术选型?选用 Sentinel 还是 Hystrix?](/docs/high-availability/sentinel-vs-hystrix.md) +- 如何进行熔断? +- 熔断框架都有哪些?具体实现原理知道吗? +- [熔断框架如何做技术选型?选用 Sentinel 还是 Hystrix?](/docs/high-availability/sentinel-vs-hystrix.md) ## 降级 -- 如何进行降级? +- 如何进行降级? --- diff --git a/docs/high-availability/e-commerce-website-detail-page-architecture.md b/docs/high-availability/e-commerce-website-detail-page-architecture.md index f7c729740..8f9c03218 100644 --- a/docs/high-availability/e-commerce-website-detail-page-architecture.md +++ b/docs/high-availability/e-commerce-website-detail-page-architecture.md @@ -10,11 +10,11 @@ ```html - - 商品名称:#{productName}
- 商品价格:#{productPrice}
- 商品描述:#{productDesc} - + + 商品名称:#{productName}
+ 商品价格:#{productPrice}
+ 商品描述:#{productDesc} + ``` diff --git a/docs/high-availability/hystrix-circuit-breaker.md b/docs/high-availability/hystrix-circuit-breaker.md index db338625f..7bd7c7e17 100644 --- a/docs/high-availability/hystrix-circuit-breaker.md +++ b/docs/high-availability/hystrix-circuit-breaker.md @@ -80,9 +80,9 @@ Hystrix 并不是只要有一条请求经过就去统计,而是将整个滑动 在 GetProductInfoCommand 中配置 Setter 断路器相关参数。 -- 滑动窗口中,最少 20 个请求,才可能触发断路。 -- 异常比例达到 40% 时,才触发断路。 -- 断路后 3000ms 内,所有请求都被 reject,直接走 fallback 降级,不会调用 run() 方法。3000ms 过后,变为 half-open 状态。 +- 滑动窗口中,最少 20 个请求,才可能触发断路。 +- 异常比例达到 40% 时,才触发断路。 +- 断路后 3000ms 内,所有请求都被 reject,直接走 fallback 降级,不会调用 run() 方法。3000ms 过后,变为 half-open 状态。 run() 方法中,我们判断一下 productId 是否为 -1,是的话,直接抛出异常。这么写,我们之后测试的时候就可以传入 productId=-1,**模拟服务执行异常**了。 diff --git a/docs/high-availability/hystrix-execution-isolation.md b/docs/high-availability/hystrix-execution-isolation.md index 68f839489..7ee39d503 100644 --- a/docs/high-availability/hystrix-execution-isolation.md +++ b/docs/high-availability/hystrix-execution-isolation.md @@ -2,8 +2,8 @@ Hystrix 实现资源隔离,有两种策略: -- 线程池隔离 -- 信号量隔离 +- 线程池隔离 +- 信号量隔离 对资源隔离这一块东西,其实可以做一定细粒度的一些控制。 diff --git a/docs/high-availability/hystrix-fallback.md b/docs/high-availability/hystrix-fallback.md index fa6860212..919325007 100644 --- a/docs/high-availability/hystrix-fallback.md +++ b/docs/high-availability/hystrix-fallback.md @@ -2,18 +2,18 @@ Hystrix 出现以下四种情况,都会去调用 fallback 降级机制: -- 断路器处于打开的状态。 -- 资源池已满(线程池+队列 / 信号量)。 -- Hystrix 调用各种接口,或者访问外部依赖,比如 MySQL、Redis、Zookeeper、Kafka 等等,出现了任何异常的情况。 -- 访问外部依赖的时候,访问时间过长,报了 TimeoutException 异常。 +- 断路器处于打开的状态。 +- 资源池已满(线程池+队列 / 信号量)。 +- Hystrix 调用各种接口,或者访问外部依赖,比如 MySQL、Redis、Zookeeper、Kafka 等等,出现了任何异常的情况。 +- 访问外部依赖的时候,访问时间过长,报了 TimeoutException 异常。 ### 两种最经典的降级机制 -- 纯内存数据
- 在降级逻辑中,你可以在内存中维护一个 ehcache,作为一个纯内存的基于 LRU 自动清理的缓存,让数据放在缓存内。如果说外部依赖有异常,fallback 这里直接尝试从 ehcache 中获取数据。 +- 纯内存数据
+ 在降级逻辑中,你可以在内存中维护一个 ehcache,作为一个纯内存的基于 LRU 自动清理的缓存,让数据放在缓存内。如果说外部依赖有异常,fallback 这里直接尝试从 ehcache 中获取数据。 -- 默认值
- fallback 降级逻辑中,也可以直接返回一个默认值。 +- 默认值
+ fallback 降级逻辑中,也可以直接返回一个默认值。 在 `HystrixCommand`,降级逻辑的书写,是通过实现 getFallback() 接口;而在 `HystrixObservableCommand` 中,则是实现 resumeWithFallback() 方法。 diff --git a/docs/high-availability/hystrix-introduction.md b/docs/high-availability/hystrix-introduction.md index 5123527fe..39b345f1f 100644 --- a/docs/high-availability/hystrix-introduction.md +++ b/docs/high-availability/hystrix-introduction.md @@ -24,11 +24,11 @@ Hystrix 是高可用性保障的一个框架。Netflix(可以认为是国外 ### Hystrix 的设计原则 -- 对依赖服务调用时出现的调用延迟和调用失败进行**控制和容错保护**。 -- 在复杂的分布式系统中,阻止某一个依赖服务的故障在整个系统中蔓延。比如某一个服务故障了,导致其它服务也跟着故障。 -- 提供 `fail-fast`(快速失败)和快速恢复的支持。 -- 提供 fallback 优雅降级的支持。 -- 支持近实时的监控、报警以及运维操作。 +- 对依赖服务调用时出现的调用延迟和调用失败进行**控制和容错保护**。 +- 在复杂的分布式系统中,阻止某一个依赖服务的故障在整个系统中蔓延。比如某一个服务故障了,导致其它服务也跟着故障。 +- 提供 `fail-fast`(快速失败)和快速恢复的支持。 +- 提供 fallback 优雅降级的支持。 +- 支持近实时的监控、报警以及运维操作。 举个栗子。 @@ -42,10 +42,10 @@ Hystrix 可以对其进行资源隔离,比如限制服务 B 只有 40 个线 ### Hystrix 更加细节的设计原则 -- 阻止任何一个依赖服务耗尽所有的资源,比如 tomcat 中的所有线程资源。 -- 避免请求排队和积压,采用限流和 `fail fast` 来控制故障。 -- 提供 fallback 降级机制来应对故障。 -- 使用资源隔离技术,比如 `bulkhead`(舱壁隔离技术)、`swimlane`(泳道技术)、`circuit breaker`(断路技术)来限制任何一个依赖服务的故障的影响。 -- 通过近实时的统计/监控/报警功能,来提高故障发现的速度。 -- 通过近实时的属性和配置**热修改**功能,来提高故障处理和恢复的速度。 -- 保护依赖服务调用的所有故障情况,而不仅仅只是网络故障情况。 +- 阻止任何一个依赖服务耗尽所有的资源,比如 tomcat 中的所有线程资源。 +- 避免请求排队和积压,采用限流和 `fail fast` 来控制故障。 +- 提供 fallback 降级机制来应对故障。 +- 使用资源隔离技术,比如 `bulkhead`(舱壁隔离技术)、`swimlane`(泳道技术)、`circuit breaker`(断路技术)来限制任何一个依赖服务的故障的影响。 +- 通过近实时的统计/监控/报警功能,来提高故障发现的速度。 +- 通过近实时的属性和配置**热修改**功能,来提高故障处理和恢复的速度。 +- 保护依赖服务调用的所有故障情况,而不仅仅只是网络故障情况。 diff --git a/docs/high-availability/hystrix-process.md b/docs/high-availability/hystrix-process.md index 22d200040..518353380 100644 --- a/docs/high-availability/hystrix-process.md +++ b/docs/high-availability/hystrix-process.md @@ -2,9 +2,9 @@ 前面我们了解了 Hystrix 最基本的支持高可用的技术:**资源隔离** + **限流**。 -- 创建 command; -- 执行这个 command; -- 配置这个 command 对应的 group 和线程池。 +- 创建 command; +- 执行这个 command; +- 配置这个 command 对应的 group 和线程池。 这里,我们要讲一下,你开始执行这个 command,调用了这个 command 的 execute() 方法之后,Hystrix 底层的执行流程和步骤以及原理是什么。 @@ -18,8 +18,8 @@ 一个 HystrixCommand 或 HystrixObservableCommand 对象,代表了对某个依赖服务发起的一次请求或者调用。创建的时候,可以在构造函数中传入任何需要的参数。 -- HystrixCommand 主要用于仅仅会返回一个结果的调用。 -- HystrixObservableCommand 主要用于可能会返回多条结果的调用。 +- HystrixCommand 主要用于仅仅会返回一个结果的调用。 +- HystrixObservableCommand 主要用于可能会返回多条结果的调用。 ```java // 创建 HystrixCommand @@ -37,10 +37,10 @@ HystrixObservableCommand hystrixObservableCommand = new HystrixObservableCommand 其中 execute() 和 queue() 方法仅仅对 HystrixCommand 适用。 -- execute():调用后直接 block 住,属于同步调用,直到依赖服务返回单条结果,或者抛出异常。 -- queue():返回一个 Future,属于异步调用,后面可以通过 Future 获取单条结果。 -- observe():订阅一个 Observable 对象,Observable 代表的是依赖服务返回的结果,获取到一个那个代表结果的 Observable 对象的拷贝对象。 -- toObservable():返回一个 Observable 对象,如果我们订阅这个对象,就会执行 command 并且获取返回结果。 +- execute():调用后直接 block 住,属于同步调用,直到依赖服务返回单条结果,或者抛出异常。 +- queue():返回一个 Future,属于异步调用,后面可以通过 Future 获取单条结果。 +- observe():订阅一个 Observable 对象,Observable 代表的是依赖服务返回的结果,获取到一个那个代表结果的 Observable 对象的拷贝对象。 +- toObservable():返回一个 Observable 对象,如果我们订阅这个对象,就会执行 command 并且获取返回结果。 ```java K value = hystrixCommand.execute(); @@ -87,14 +87,14 @@ final Future delegate = toObservable().toBlocking().toFuture(); 调用 HystrixObservableCommand 对象的 construct() 方法,或者 HystrixCommand 的 run() 方法来实际执行这个 command。 -- HystrixCommand.run() 返回单条结果,或者抛出异常。 +- HystrixCommand.run() 返回单条结果,或者抛出异常。 ```java // 通过command执行,获取最新一条商品数据 ProductInfo productInfo = getProductInfoCommand.execute(); ``` -- HystrixObservableCommand.construct() 返回一个 Observable 对象,可以获取多条结果。 +- HystrixObservableCommand.construct() 返回一个 Observable 对象,可以获取多条结果。 ```java Observable observable = getProductInfosCommand.observe(); @@ -139,30 +139,30 @@ Hystrix 会把每一个依赖服务的调用成功、失败、Reject、Timeout 在以下几种情况中,Hystrix 会调用 fallback 降级机制。 -- 断路器处于打开状态; -- 线程池/队列/semaphore 满了; -- command 执行超时; -- run() 或者 construct() 抛出异常。 +- 断路器处于打开状态; +- 线程池/队列/semaphore 满了; +- command 执行超时; +- run() 或者 construct() 抛出异常。 一般在降级机制中,都建议给出一些默认的返回值,比如静态的一些代码逻辑,或者从内存中的缓存中提取一些数据,在这里尽量不要再进行网络请求了。 在降级中,如果一定要进行网络调用的话,也应该将那个调用放在一个 HystrixCommand 中进行隔离。 -- HystrixCommand 中,实现 getFallback() 方法,可以提供降级机制。 -- HystrixObservableCommand 中,实现 resumeWithFallback() 方法,返回一个 Observable 对象,可以提供降级结果。 +- HystrixCommand 中,实现 getFallback() 方法,可以提供降级机制。 +- HystrixObservableCommand 中,实现 resumeWithFallback() 方法,返回一个 Observable 对象,可以提供降级结果。 如果没有实现 fallback,或者 fallback 抛出了异常,Hystrix 会返回一个 Observable,但是不会返回任何数据。 不同的 command 执行方式,其 fallback 为空或者异常时的返回结果不同。 -- 对于 execute(),直接抛出异常。 -- 对于 queue(),返回一个 Future,调用 get() 时抛出异常。 -- 对于 observe(),返回一个 Observable 对象,但是调用 subscribe() 方法订阅它时,立即抛出调用者的 onError() 方法。 -- 对于 toObservable(),返回一个 Observable 对象,但是调用 subscribe() 方法订阅它时,立即抛出调用者的 onError() 方法。 +- 对于 execute(),直接抛出异常。 +- 对于 queue(),返回一个 Future,调用 get() 时抛出异常。 +- 对于 observe(),返回一个 Observable 对象,但是调用 subscribe() 方法订阅它时,立即抛出调用者的 onError() 方法。 +- 对于 toObservable(),返回一个 Observable 对象,但是调用 subscribe() 方法订阅它时,立即抛出调用者的 onError() 方法。 ### 不同的执行方式 -- execute(),获取一个 Future.get(),然后拿到单个结果。 -- queue(),返回一个 Future。 -- observe(),立即订阅 Observable,然后启动 8 大执行步骤,返回一个拷贝的 Observable,订阅时立即回调给你结果。 -- toObservable(),返回一个原始的 Observable,必须手动订阅才会去执行 8 大步骤。 +- execute(),获取一个 Future.get(),然后拿到单个结果。 +- queue(),返回一个 Future。 +- observe(),立即订阅 Observable,然后启动 8 大执行步骤,返回一个拷贝的 Observable,订阅时立即回调给你结果。 +- toObservable(),返回一个原始的 Observable,必须手动订阅才会去执行 8 大步骤。 diff --git a/docs/high-availability/hystrix-semphore-isolation.md b/docs/high-availability/hystrix-semphore-isolation.md index 23be97894..e225ccd18 100644 --- a/docs/high-availability/hystrix-semphore-isolation.md +++ b/docs/high-availability/hystrix-semphore-isolation.md @@ -4,8 +4,8 @@ Hystrix 里面核心的一项功能,其实就是所谓的**资源隔离**, Hystrix 实现资源隔离,主要有两种技术: -- 线程池 -- 信号量 +- 线程池 +- 信号量 默认情况下,Hystrix 使用线程池模式。 @@ -27,8 +27,8 @@ Hystrix 实现资源隔离,主要有两种技术: **适用场景**: -- **线程池技术**,适合绝大多数场景,比如说我们对依赖服务的网络请求的调用和访问、需要对调用的 timeout 进行控制(捕捉 timeout 超时异常)。 -- **信号量技术**,适合说你的访问不是对外部依赖的访问,而是对内部的一些比较复杂的业务逻辑的访问,并且系统内部的代码,其实不涉及任何的网络请求,那么只要做信号量的普通限流就可以了,因为不需要去捕获 timeout 类似的问题。 +- **线程池技术**,适合绝大多数场景,比如说我们对依赖服务的网络请求的调用和访问、需要对调用的 timeout 进行控制(捕捉 timeout 超时异常)。 +- **信号量技术**,适合说你的访问不是对外部依赖的访问,而是对内部的一些比较复杂的业务逻辑的访问,并且系统内部的代码,其实不涉及任何的网络请求,那么只要做信号量的普通限流就可以了,因为不需要去捕获 timeout 类似的问题。 ### 信号量简单 Demo diff --git a/docs/high-availability/hystrix-thread-pool-current-limiting.md b/docs/high-availability/hystrix-thread-pool-current-limiting.md index 760c1967a..912ca53b1 100644 --- a/docs/high-availability/hystrix-thread-pool-current-limiting.md +++ b/docs/high-availability/hystrix-thread-pool-current-limiting.md @@ -20,37 +20,37 @@ Hystrix 对每个外部依赖用一个单独的线程池,这样的话,如果 ### Hystrix 应用线程池机制的场景 -- 每个服务都会调用几十个后端依赖服务,那些后端依赖服务通常是由很多不同的团队开发的。 -- 每个后端依赖服务都会提供它自己的 client 调用库,比如说用 thrift 的话,就会提供对应的 thrift 依赖。 -- client 调用库随时会变更。 -- client 调用库随时可能会增加新的网络请求的逻辑。 -- client 调用库可能会包含诸如自动重试、数据解析、内存中缓存等逻辑。 -- client 调用库一般都对调用者来说是个黑盒,包括实现细节、网络访问、默认配置等等。 -- 在真实的生产环境中,经常会出现调用者,突然间惊讶的发现,client 调用库发生了某些变化。 -- 即使 client 调用库没有改变,依赖服务本身可能有会发生逻辑上的变化。 -- 有些依赖的 client 调用库可能还会拉取其他的依赖库,而且可能那些依赖库配置的不正确。 -- 大多数网络请求都是同步调用的。 -- 调用失败和延迟,也有可能会发生在 client 调用库本身的代码中,不一定就是发生在网络请求中。 +- 每个服务都会调用几十个后端依赖服务,那些后端依赖服务通常是由很多不同的团队开发的。 +- 每个后端依赖服务都会提供它自己的 client 调用库,比如说用 thrift 的话,就会提供对应的 thrift 依赖。 +- client 调用库随时会变更。 +- client 调用库随时可能会增加新的网络请求的逻辑。 +- client 调用库可能会包含诸如自动重试、数据解析、内存中缓存等逻辑。 +- client 调用库一般都对调用者来说是个黑盒,包括实现细节、网络访问、默认配置等等。 +- 在真实的生产环境中,经常会出现调用者,突然间惊讶的发现,client 调用库发生了某些变化。 +- 即使 client 调用库没有改变,依赖服务本身可能有会发生逻辑上的变化。 +- 有些依赖的 client 调用库可能还会拉取其他的依赖库,而且可能那些依赖库配置的不正确。 +- 大多数网络请求都是同步调用的。 +- 调用失败和延迟,也有可能会发生在 client 调用库本身的代码中,不一定就是发生在网络请求中。 简单来说,就是你必须默认 client 调用库很不靠谱,而且随时可能发生各种变化,所以就要用强制隔离的方式来确保任何服务的故障不会影响当前服务。 ### 线程池机制的优点 -- 任何一个依赖服务都可以被隔离在自己的线程池内,即使自己的线程池资源填满了,也不会影响任何其他的服务调用。 -- 服务可以随时引入一个新的依赖服务,因为即使这个新的依赖服务有问题,也不会影响其他任何服务的调用。 -- 当一个故障的依赖服务重新变好的时候,可以通过清理掉线程池,瞬间恢复该服务的调用,而如果是 tomcat 线程池被占满,再恢复就很麻烦。 -- 如果一个 client 调用库配置有问题,线程池的健康状况随时会报告,比如成功/失败/拒绝/超时的次数统计,然后可以近实时热修改依赖服务的调用配置,而不用停机。 -- 基于线程池的异步本质,可以在同步的调用之上,构建一层异步调用层。 +- 任何一个依赖服务都可以被隔离在自己的线程池内,即使自己的线程池资源填满了,也不会影响任何其他的服务调用。 +- 服务可以随时引入一个新的依赖服务,因为即使这个新的依赖服务有问题,也不会影响其他任何服务的调用。 +- 当一个故障的依赖服务重新变好的时候,可以通过清理掉线程池,瞬间恢复该服务的调用,而如果是 tomcat 线程池被占满,再恢复就很麻烦。 +- 如果一个 client 调用库配置有问题,线程池的健康状况随时会报告,比如成功/失败/拒绝/超时的次数统计,然后可以近实时热修改依赖服务的调用配置,而不用停机。 +- 基于线程池的异步本质,可以在同步的调用之上,构建一层异步调用层。 简单来说,最大的好处,就是资源隔离,确保说任何一个依赖服务故障,不会拖垮当前的这个服务。 ### 线程池机制的缺点 -- 线程池机制最大的缺点就是增加了 CPU 的开销。
- 除了 tomcat 本身的调用线程之外,还有 Hystrix 自己管理的线程池。 +- 线程池机制最大的缺点就是增加了 CPU 的开销。
+ 除了 tomcat 本身的调用线程之外,还有 Hystrix 自己管理的线程池。 -- 每个 command 的执行都依托一个独立的线程,会进行排队,调度,还有上下文切换。 -- Hystrix 官方自己做了一个多线程异步带来的额外开销统计,通过对比多线程异步调用+同步调用得出,Netflix API 每天通过 Hystrix 执行 10 亿次调用,每个服务实例有 40 个以上的线程池,每个线程池有 10 个左右的线程。)最后发现说,用 Hystrix 的额外开销,就是给请求带来了 3ms 左右的延时,最多延时在 10ms 以内,相比于可用性和稳定性的提升,这是可以接受的。 +- 每个 command 的执行都依托一个独立的线程,会进行排队,调度,还有上下文切换。 +- Hystrix 官方自己做了一个多线程异步带来的额外开销统计,通过对比多线程异步调用+同步调用得出,Netflix API 每天通过 Hystrix 执行 10 亿次调用,每个服务实例有 40 个以上的线程池,每个线程池有 10 个左右的线程。)最后发现说,用 Hystrix 的额外开销,就是给请求带来了 3ms 左右的延时,最多延时在 10ms 以内,相比于可用性和稳定性的提升,这是可以接受的。 我们可以用 Hystrix semaphore 技术来实现对某个依赖服务的并发访问量的限制,而不是通过线程池/队列的大小来限制流量。 @@ -64,9 +64,9 @@ semaphore 技术可以用来限流和削峰,但是不能用来对调用延迟 在 command 内部,写死代码,做一个 sleep,比如 sleep 3s。 -- withCoreSize:设置线程池大小。 -- withMaxQueueSize:设置等待队列大小。 -- withQueueSizeRejectionThreshold:这个与 withMaxQueueSize 配合使用,等待队列的大小,取得是这两个参数的较小值。 +- withCoreSize:设置线程池大小。 +- withMaxQueueSize:设置等待队列大小。 +- withQueueSizeRejectionThreshold:这个与 withMaxQueueSize 配合使用,等待队列的大小,取得是这两个参数的较小值。 如果只设置了线程池大小,另外两个 queue 相关参数没有设置的话,等待队列是处于关闭的状态。 diff --git a/docs/high-availability/sentinel-vs-hystrix.md b/docs/high-availability/sentinel-vs-hystrix.md index 504e91ec8..1c9133c6a 100644 --- a/docs/high-availability/sentinel-vs-hystrix.md +++ b/docs/high-availability/sentinel-vs-hystrix.md @@ -14,10 +14,10 @@ Sentinel 项目地址:https://github.com/alibaba/Sentinel 而 Sentinel 的侧重点在于: -- 多样化的流量控制 -- 熔断降级 -- 系统负载保护 -- 实时监控和控制台 +- 多样化的流量控制 +- 熔断降级 +- 系统负载保护 +- 实时监控和控制台 两者解决的问题还是有比较大的不同的,下面我们来具体对比一下。 @@ -71,12 +71,12 @@ Sentinel 可以针对不同的调用关系,以不同的运行指标(如 QPS Sentinel 支持多样化的流量整形策略,在 QPS 过高的时候可以自动将流量调整成合适的形状。常用的有: -- **直接拒绝模式**:即超出的请求直接拒绝。 -- **慢启动预热模式**:当流量激增的时候,控制流量通过的速率,让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。 - ![Slow-Start-Preheating-Mode](./images/Slow-Start-Preheating-Mode.jpg) +- **直接拒绝模式**:即超出的请求直接拒绝。 +- **慢启动预热模式**:当流量激增的时候,控制流量通过的速率,让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。 + ![Slow-Start-Preheating-Mode](./images/Slow-Start-Preheating-Mode.jpg) -- **匀速器模式**:利用 Leaky Bucket 算法实现的匀速模式,严格控制了请求通过的时间间隔,同时堆积的请求将会排队,超过超时时长的请求直接被拒绝。Sentinel 还支持基于调用关系的限流,包括基于调用方限流、基于调用链入口限流、关联流量限流等,依托于 Sentinel 强大的调用链路统计信息,可以提供精准的不同维度的限流。 - ![Homogenizer-mode](./images/Homogenizer-mode.jpg) +- **匀速器模式**:利用 Leaky Bucket 算法实现的匀速模式,严格控制了请求通过的时间间隔,同时堆积的请求将会排队,超过超时时长的请求直接被拒绝。Sentinel 还支持基于调用关系的限流,包括基于调用方限流、基于调用链入口限流、关联流量限流等,依托于 Sentinel 强大的调用链路统计信息,可以提供精准的不同维度的限流。 + ![Homogenizer-mode](./images/Homogenizer-mode.jpg) 目前 Sentinel 对异步调用链路的支持还不是很好,后续版本会着重改善支持异步调用。 diff --git a/docs/high-concurrency/README.md b/docs/high-concurrency/README.md index ec1356a29..3ee6e07b4 100644 --- a/docs/high-concurrency/README.md +++ b/docs/high-concurrency/README.md @@ -2,50 +2,50 @@ ## [消息队列](/docs/high-concurrency/mq-interview.md) -- [为什么使用消息队列?消息队列有什么优点和缺点?Kafka、ActiveMQ、RabbitMQ、RocketMQ 都有什么优点和缺点?](/docs/high-concurrency/why-mq.md) -- [如何保证消息队列的高可用?](/docs/high-concurrency/how-to-ensure-high-availability-of-message-queues.md) -- [如何保证消息不被重复消费?(如何保证消息消费的幂等性)](/docs/high-concurrency/how-to-ensure-that-messages-are-not-repeatedly-consumed.md) -- [如何保证消息的可靠性传输?(如何处理消息丢失的问题)](/docs/high-concurrency/how-to-ensure-the-reliable-transmission-of-messages.md) -- [如何保证消息的顺序性?](/docs/high-concurrency/how-to-ensure-the-order-of-messages.md) -- [如何解决消息队列的延时以及过期失效问题?消息队列满了以后该怎么处理?有几百万消息持续积压几小时,说说怎么解决?](/docs/high-concurrency/mq-time-delay-and-expired-failure.md) -- [如果让你写一个消息队列,该如何进行架构设计啊?说一下你的思路。](/docs/high-concurrency/mq-design.md) +- [为什么使用消息队列?消息队列有什么优点和缺点?Kafka、ActiveMQ、RabbitMQ、RocketMQ 都有什么优点和缺点?](/docs/high-concurrency/why-mq.md) +- [如何保证消息队列的高可用?](/docs/high-concurrency/how-to-ensure-high-availability-of-message-queues.md) +- [如何保证消息不被重复消费?(如何保证消息消费的幂等性)](/docs/high-concurrency/how-to-ensure-that-messages-are-not-repeatedly-consumed.md) +- [如何保证消息的可靠性传输?(如何处理消息丢失的问题)](/docs/high-concurrency/how-to-ensure-the-reliable-transmission-of-messages.md) +- [如何保证消息的顺序性?](/docs/high-concurrency/how-to-ensure-the-order-of-messages.md) +- [如何解决消息队列的延时以及过期失效问题?消息队列满了以后该怎么处理?有几百万消息持续积压几小时,说说怎么解决?](/docs/high-concurrency/mq-time-delay-and-expired-failure.md) +- [如果让你写一个消息队列,该如何进行架构设计啊?说一下你的思路。](/docs/high-concurrency/mq-design.md) ## [搜索引擎](/docs/high-concurrency/es-introduction.md) -- [ES 的分布式架构原理能说一下么(ES 是如何实现分布式的啊)?](/docs/high-concurrency/es-architecture.md) -- [ES 写入数据的工作原理是什么啊?ES 查询数据的工作原理是什么啊?底层的 Lucene 介绍一下呗?倒排索引了解吗?](/docs/high-concurrency/es-write-query-search.md) -- [ES 在数据量很大的情况下(数十亿级别)如何提高查询效率啊?](/docs/high-concurrency/es-optimizing-query-performance.md) -- [ES 生产集群的部署架构是什么?每个索引的数据量大概有多少?每个索引大概有多少个分片?](/docs/high-concurrency/es-production-cluster.md) +- [ES 的分布式架构原理能说一下么(ES 是如何实现分布式的啊)?](/docs/high-concurrency/es-architecture.md) +- [ES 写入数据的工作原理是什么啊?ES 查询数据的工作原理是什么啊?底层的 Lucene 介绍一下呗?倒排索引了解吗?](/docs/high-concurrency/es-write-query-search.md) +- [ES 在数据量很大的情况下(数十亿级别)如何提高查询效率啊?](/docs/high-concurrency/es-optimizing-query-performance.md) +- [ES 生产集群的部署架构是什么?每个索引的数据量大概有多少?每个索引大概有多少个分片?](/docs/high-concurrency/es-production-cluster.md) ## 缓存 -- [在项目中缓存是如何使用的?缓存如果使用不当会造成什么后果?](/docs/high-concurrency/why-cache.md) -- [Redis 和 Memcached 有什么区别?Redis 的线程模型是什么?为什么单线程的 Redis 比多线程的 Memcached 效率要高得多?](/docs/high-concurrency/redis-single-thread-model.md) -- [Redis 都有哪些数据类型?分别在哪些场景下使用比较合适?](/docs/high-concurrency/redis-data-types.md) -- [Redis 的过期策略都有哪些?手写一下 LRU 代码实现?](/docs/high-concurrency/redis-expiration-policies-and-lru.md) -- [如何保证 Redis 高并发、高可用?Redis 的主从复制原理能介绍一下么?Redis 的哨兵原理能介绍一下么?](/docs/high-concurrency/how-to-ensure-high-concurrency-and-high-availability-of-redis.md) -- [Redis 的持久化有哪几种方式?不同的持久化机制都有什么优缺点?持久化机制具体底层是如何实现的?](/docs/high-concurrency/redis-persistence.md) -- [Redis 集群模式的工作原理能说一下么?在集群模式下,Redis 的 key 是如何寻址的?分布式寻址都有哪些算法?了解一致性 hash 算法吗?如何动态增加和删除一个节点?](/docs/high-concurrency/redis-cluster.md) -- [了解什么是 redis 的雪崩、穿透和击穿?Redis 崩溃之后会怎么样?系统该如何应对这种情况?如何处理 Redis 的穿透?](/docs/high-concurrency/redis-caching-avalanche-and-caching-penetration.md) -- [如何保证缓存与数据库的双写一致性?](/docs/high-concurrency/redis-consistence.md) -- [Redis 的并发竞争问题是什么?如何解决这个问题?了解 Redis 事务的 CAS 方案吗?](/docs/high-concurrency/redis-cas.md) -- [生产环境中的 Redis 是怎么部署的?](/docs/high-concurrency/redis-production-environment.md) -- [有了解过 Redis rehash 的过程吗?](/docs/high-concurrency/redis-rehash.md) +- [在项目中缓存是如何使用的?缓存如果使用不当会造成什么后果?](/docs/high-concurrency/why-cache.md) +- [Redis 和 Memcached 有什么区别?Redis 的线程模型是什么?为什么单线程的 Redis 比多线程的 Memcached 效率要高得多?](/docs/high-concurrency/redis-single-thread-model.md) +- [Redis 都有哪些数据类型?分别在哪些场景下使用比较合适?](/docs/high-concurrency/redis-data-types.md) +- [Redis 的过期策略都有哪些?手写一下 LRU 代码实现?](/docs/high-concurrency/redis-expiration-policies-and-lru.md) +- [如何保证 Redis 高并发、高可用?Redis 的主从复制原理能介绍一下么?Redis 的哨兵原理能介绍一下么?](/docs/high-concurrency/how-to-ensure-high-concurrency-and-high-availability-of-redis.md) +- [Redis 的持久化有哪几种方式?不同的持久化机制都有什么优缺点?持久化机制具体底层是如何实现的?](/docs/high-concurrency/redis-persistence.md) +- [Redis 集群模式的工作原理能说一下么?在集群模式下,Redis 的 key 是如何寻址的?分布式寻址都有哪些算法?了解一致性 hash 算法吗?如何动态增加和删除一个节点?](/docs/high-concurrency/redis-cluster.md) +- [了解什么是 redis 的雪崩、穿透和击穿?Redis 崩溃之后会怎么样?系统该如何应对这种情况?如何处理 Redis 的穿透?](/docs/high-concurrency/redis-caching-avalanche-and-caching-penetration.md) +- [如何保证缓存与数据库的双写一致性?](/docs/high-concurrency/redis-consistence.md) +- [Redis 的并发竞争问题是什么?如何解决这个问题?了解 Redis 事务的 CAS 方案吗?](/docs/high-concurrency/redis-cas.md) +- [生产环境中的 Redis 是怎么部署的?](/docs/high-concurrency/redis-production-environment.md) +- [有了解过 Redis rehash 的过程吗?](/docs/high-concurrency/redis-rehash.md) ## 分库分表 -- [为什么要分库分表(设计高并发系统的时候,数据库层面该如何设计)?用过哪些分库分表中间件?不同的分库分表中间件都有什么优点和缺点?你们具体是如何对数据库如何进行垂直拆分或水平拆分的?](/docs/high-concurrency/database-shard.md) -- [现在有一个未分库分表的系统,未来要分库分表,如何设计才可以让系统从未分库分表动态切换到分库分表上?](/docs/high-concurrency/database-shard-method.md) -- [如何设计可以动态扩容缩容的分库分表方案?](/docs/high-concurrency/database-shard-dynamic-expand.md) -- [分库分表之后,id 主键如何处理?](/docs/high-concurrency/database-shard-global-id-generate.md) +- [为什么要分库分表(设计高并发系统的时候,数据库层面该如何设计)?用过哪些分库分表中间件?不同的分库分表中间件都有什么优点和缺点?你们具体是如何对数据库如何进行垂直拆分或水平拆分的?](/docs/high-concurrency/database-shard.md) +- [现在有一个未分库分表的系统,未来要分库分表,如何设计才可以让系统从未分库分表动态切换到分库分表上?](/docs/high-concurrency/database-shard-method.md) +- [如何设计可以动态扩容缩容的分库分表方案?](/docs/high-concurrency/database-shard-dynamic-expand.md) +- [分库分表之后,id 主键如何处理?](/docs/high-concurrency/database-shard-global-id-generate.md) ## 读写分离 -- [如何实现 MySQL 的读写分离?MySQL 主从复制原理是啥?如何解决 MySQL 主从同步的延时问题?](/docs/high-concurrency/mysql-read-write-separation.md) +- [如何实现 MySQL 的读写分离?MySQL 主从复制原理是啥?如何解决 MySQL 主从同步的延时问题?](/docs/high-concurrency/mysql-read-write-separation.md) ## 高并发系统 -- [如何设计一个高并发系统?](/docs/high-concurrency/high-concurrency-design.md) +- [如何设计一个高并发系统?](/docs/high-concurrency/high-concurrency-design.md) --- diff --git a/docs/high-concurrency/database-shard-dynamic-expand.md b/docs/high-concurrency/database-shard-dynamic-expand.md index f6dc6f0f1..8df5e4b2a 100644 --- a/docs/high-concurrency/database-shard-dynamic-expand.md +++ b/docs/high-concurrency/database-shard-dynamic-expand.md @@ -6,12 +6,12 @@ 对于分库分表来说,主要是面对以下问题: -- 选择一个数据库中间件,调研、学习、测试; -- 设计你的分库分表的一个方案,你要分成多少个库,每个库分成多少个表,比如 3 个库,每个库 4 个表; -- 基于选择好的数据库中间件,以及在测试环境建立好的分库分表的环境,然后测试一下能否正常进行分库分表的读写; -- 完成单库单表到分库分表的**迁移**,双写方案; -- 线上系统开始基于分库分表对外提供服务; -- 扩容了,扩容成 6 个库,每个库需要 12 个表,你怎么来增加更多库和表呢? +- 选择一个数据库中间件,调研、学习、测试; +- 设计你的分库分表的一个方案,你要分成多少个库,每个库分成多少个表,比如 3 个库,每个库 4 个表; +- 基于选择好的数据库中间件,以及在测试环境建立好的分库分表的环境,然后测试一下能否正常进行分库分表的读写; +- 完成单库单表到分库分表的**迁移**,双写方案; +- 线上系统开始基于分库分表对外提供服务; +- 扩容了,扩容成 6 个库,每个库需要 12 个表,你怎么来增加更多库和表呢? 这个是你必须面对的一个事儿,就是你已经弄好分库分表方案了,然后一堆库和表都建好了,基于分库分表中间件的代码开发啥的都好了,测试都 ok 了,数据能均匀分布到各个库和各个表里去,而且接着你还通过双写的方案咔嚓一下上了系统,已经直接基于分库分表方案在搞了。 diff --git a/docs/high-concurrency/database-shard-global-id-generate.md b/docs/high-concurrency/database-shard-global-id-generate.md index 76a4a48f2..905fd0f69 100644 --- a/docs/high-concurrency/database-shard-global-id-generate.md +++ b/docs/high-concurrency/database-shard-global-id-generate.md @@ -48,10 +48,10 @@ UUID.randomUUID().toString().replace("-", "") -> sfsdf23423rr234sfdaf snowflake 算法是 twitter 开源的分布式 id 生成算法,采用 Scala 语言实现,是把一个 64 位的 long 型的 id,1 个 bit 是不用的,用其中的 41 bits 作为毫秒数,用 10 bits 作为工作机器 id,12 bits 作为序列号。 -- 1 bit:不用,为啥呢?因为二进制里第一个 bit 为如果是 1,那么都是负数,但是我们生成的 id 都是正数,所以第一个 bit 统一都是 0。 -- 41 bits:表示的是时间戳,单位是毫秒。41 bits 可以表示的数字多达 `2^41 - 1` ,也就是可以标识 `2^41 - 1` 个毫秒值,换算成年就是表示 69 年的时间。 -- 10 bits:记录工作机器 id,代表的是这个服务最多可以部署在 2^10 台机器上,也就是 1024 台机器。但是 10 bits 里 5 个 bits 代表机房 id,5 个 bits 代表机器 id。意思就是最多代表 `2^5` 个机房(32 个机房),每个机房里可以代表 `2^5` 个机器(32 台机器)。 -- 12 bits:这个是用来记录同一个毫秒内产生的不同 id,12 bits 可以代表的最大正整数是 `2^12 - 1 = 4096` ,也就是说可以用这个 12 bits 代表的数字来区分**同一个毫秒内**的 4096 个不同的 id。 +- 1 bit:不用,为啥呢?因为二进制里第一个 bit 为如果是 1,那么都是负数,但是我们生成的 id 都是正数,所以第一个 bit 统一都是 0。 +- 41 bits:表示的是时间戳,单位是毫秒。41 bits 可以表示的数字多达 `2^41 - 1` ,也就是可以标识 `2^41 - 1` 个毫秒值,换算成年就是表示 69 年的时间。 +- 10 bits:记录工作机器 id,代表的是这个服务最多可以部署在 2^10 台机器上,也就是 1024 台机器。但是 10 bits 里 5 个 bits 代表机房 id,5 个 bits 代表机器 id。意思就是最多代表 `2^5` 个机房(32 个机房),每个机房里可以代表 `2^5` 个机器(32 台机器)。 +- 12 bits:这个是用来记录同一个毫秒内产生的不同 id,12 bits 可以代表的最大正整数是 `2^12 - 1 = 4096` ,也就是说可以用这个 12 bits 代表的数字来区分**同一个毫秒内**的 4096 个不同的 id。 ```sh 0 | 0001100 10100010 10111110 10001001 01011100 00 | 10001 | 1 1001 | 0000 00000000 diff --git a/docs/high-concurrency/database-shard.md b/docs/high-concurrency/database-shard.md index d523dff67..47a6cbff2 100644 --- a/docs/high-concurrency/database-shard.md +++ b/docs/high-concurrency/database-shard.md @@ -50,11 +50,11 @@ 比较常见的包括: -- Cobar -- TDDL -- Atlas -- Sharding-jdbc -- Mycat +- Cobar +- TDDL +- Atlas +- Sharding-jdbc +- Mycat #### Cobar @@ -106,8 +106,8 @@ Mycat 这种 proxy 层方案的**缺点在于需要部署**,自己运维一套 而且这儿还有两种**分库分表的方式**: -- 一种是按照 range 来分,就是每个库一段连续的数据,这个一般是按比如**时间范围**来的,但是这种一般较少用,因为很容易产生热点问题,大量的流量都打在最新的数据上了。 -- 或者是按照某个字段 hash 一下均匀分散,这个较为常用。 +- 一种是按照 range 来分,就是每个库一段连续的数据,这个一般是按比如**时间范围**来的,但是这种一般较少用,因为很容易产生热点问题,大量的流量都打在最新的数据上了。 +- 或者是按照某个字段 hash 一下均匀分散,这个较为常用。 range 来分,好处在于说,扩容的时候很简单,因为你只要预备好,给每个月都准备一个库就可以了,到了一个新的月份的时候,自然而然,就会写新的库了;缺点,但是大部分的请求,都是访问最新的数据。实际生产用 range,要看场景。 diff --git a/docs/high-concurrency/es-introduction.md b/docs/high-concurrency/es-introduction.md index e78b84d98..22d3f01c1 100644 --- a/docs/high-concurrency/es-introduction.md +++ b/docs/high-concurrency/es-introduction.md @@ -4,9 +4,9 @@ Lucene 是最先进、功能最强大的搜索库。如果直接基于 Lucene ElasticSearch 基于 Lucene,隐藏了 lucene 的复杂性,提供了简单易用的 RESTful api / Java api 接口(另外还有其他语言的 api 接口)。 -- 分布式的文档存储引擎 -- 分布式的搜索引擎和分析引擎 -- 分布式,支持 PB 级数据 +- 分布式的文档存储引擎 +- 分布式的搜索引擎和分析引擎 +- 分布式,支持 PB 级数据 ## ES 的核心概念 @@ -14,8 +14,8 @@ ElasticSearch 基于 Lucene,隐藏了 lucene 的复杂性,提供了简单易 近实时,有两层意思: -- 从写入数据到数据可以被搜索到有一个小延迟(大概是 1s) -- 基于 ES 执行搜索和分析可以达到秒级 +- 从写入数据到数据可以被搜索到有一个小延迟(大概是 1s) +- 基于 ES 执行搜索和分析可以达到秒级 ### Cluster 集群 @@ -31,11 +31,11 @@ Node 是集群中的一个节点,节点也有一个名称,默认是随机分 ```json { - "product_id": "1", - "product_name": "iPhone X", - "product_desc": "苹果手机", - "category_id": "2", - "category_name": "电子产品" + "product_id": "1", + "product_name": "iPhone X", + "product_desc": "苹果手机", + "category_id": "2", + "category_name": "电子产品" } ``` diff --git a/docs/high-concurrency/es-production-cluster.md b/docs/high-concurrency/es-production-cluster.md index 9733854b3..fd7093521 100644 --- a/docs/high-concurrency/es-production-cluster.md +++ b/docs/high-concurrency/es-production-cluster.md @@ -16,8 +16,8 @@ ES 生产集群的部署架构是什么?每个索引的数据量大概有多 但是如果你确实没干过,也别虚,我给你说一个基本的版本,你到时候就简单说一下就好了。 -- es 生产集群我们部署了 5 台机器,每台机器是 6 核 64G 的,集群总内存是 320G。 -- 我们 es 集群的日增量数据大概是 2000 万条,每天日增量数据大概是 500MB,每月增量数据大概是 6 亿,15G。目前系统已经运行了几个月,现在 es 集群里数据总量大概是 100G 左右。 -- 目前线上有 5 个索引(这个结合你们自己业务来,看看自己有哪些数据可以放 es 的),每个索引的数据量大概是 20G,所以这个数据量之内,我们每个索引分配的是 8 个 shard,比默认的 5 个 shard 多了 3 个 shard。 +- es 生产集群我们部署了 5 台机器,每台机器是 6 核 64G 的,集群总内存是 320G。 +- 我们 es 集群的日增量数据大概是 2000 万条,每天日增量数据大概是 500MB,每月增量数据大概是 6 亿,15G。目前系统已经运行了几个月,现在 es 集群里数据总量大概是 100G 左右。 +- 目前线上有 5 个索引(这个结合你们自己业务来,看看自己有哪些数据可以放 es 的),每个索引的数据量大概是 20G,所以这个数据量之内,我们每个索引分配的是 8 个 shard,比默认的 5 个 shard 多了 3 个 shard。 大概就这么说一下就行了。 diff --git a/docs/high-concurrency/es-write-query-search.md b/docs/high-concurrency/es-write-query-search.md index 3cdbfd5a0..3e7e304a5 100644 --- a/docs/high-concurrency/es-write-query-search.md +++ b/docs/high-concurrency/es-write-query-search.md @@ -12,10 +12,10 @@ ES 写入数据的工作原理是什么啊?ES 查询数据的工作原理是 ### es 写数据过程 -- 客户端选择一个 node 发送请求过去,这个 node 就是 `coordinating node` (协调节点)。 -- `coordinating node` 对 document 进行**路由**,将请求转发给对应的 node(有 primary shard)。 -- 实际的 node 上的 `primary shard` 处理请求,然后将数据同步到 `replica node` 。 -- `coordinating node` 如果发现 `primary node` 和所有 `replica node` 都搞定之后,就返回响应结果给客户端。 +- 客户端选择一个 node 发送请求过去,这个 node 就是 `coordinating node` (协调节点)。 +- `coordinating node` 对 document 进行**路由**,将请求转发给对应的 node(有 primary shard)。 +- 实际的 node 上的 `primary shard` 处理请求,然后将数据同步到 `replica node` 。 +- `coordinating node` 如果发现 `primary node` 和所有 `replica node` 都搞定之后,就返回响应结果给客户端。 ![es-write](./images/es-write.png) @@ -23,10 +23,10 @@ ES 写入数据的工作原理是什么啊?ES 查询数据的工作原理是 可以通过 `doc id` 来查询,会根据 `doc id` 进行 hash,判断出来当时把 `doc id` 分配到了哪个 shard 上面去,从那个 shard 去查询。 -- 客户端发送请求到**任意**一个 node,成为 `coordinate node` 。 -- `coordinate node` 对 `doc id` 进行哈希路由,将请求转发到对应的 node,此时会使用 `round-robin` **随机轮询算法**,在 `primary shard` 以及其所有 replica 中随机选择一个,让读请求负载均衡。 -- 接收请求的 node 返回 document 给 `coordinate node` 。 -- `coordinate node` 返回 document 给客户端。 +- 客户端发送请求到**任意**一个 node,成为 `coordinate node` 。 +- `coordinate node` 对 `doc id` 进行哈希路由,将请求转发到对应的 node,此时会使用 `round-robin` **随机轮询算法**,在 `primary shard` 以及其所有 replica 中随机选择一个,让读请求负载均衡。 +- 接收请求的 node 返回 document 给 `coordinate node` 。 +- `coordinate node` 返回 document 给客户端。 ### es 搜索数据过程 @@ -40,10 +40,10 @@ j2ee特别牛 你根据 `java` 关键词来搜索,将包含 `java` 的 `document` 给搜索出来。es 就会给你返回:java 真好玩儿啊,java 好难学啊。 -- 客户端发送请求到一个 `coordinate node` 。 -- 协调节点将搜索请求转发到**所有**的 shard 对应的 `primary shard` 或 `replica shard` ,都可以。 -- query phase:每个 shard 将自己的搜索结果(其实就是一些 `doc id` )返回给协调节点,由协调节点进行数据的合并、排序、分页等操作,产出最终结果。 -- fetch phase:接着由协调节点根据 `doc id` 去各个节点上**拉取实际**的 `document` 数据,最终返回给客户端。 +- 客户端发送请求到一个 `coordinate node` 。 +- 协调节点将搜索请求转发到**所有**的 shard 对应的 `primary shard` 或 `replica shard` ,都可以。 +- query phase:每个 shard 将自己的搜索结果(其实就是一些 `doc id` )返回给协调节点,由协调节点进行数据的合并、排序、分页等操作,产出最终结果。 +- fetch phase:接着由协调节点根据 `doc id` 去各个节点上**拉取实际**的 `document` 数据,最终返回给客户端。 > 写请求是写入 primary shard,然后同步给所有的 replica shard;读请求可以从 primary shard 或 replica shard 读取,采用的是随机轮询算法。 @@ -73,8 +73,8 @@ translog 日志文件的作用是什么?你执行 commit 操作之前,数据 translog 其实也是先写入 os cache 的,默认每隔 5 秒刷一次到磁盘中去,所以默认情况下,可能有 5 秒的数据会仅仅停留在 buffer 或者 translog 文件的 os cache 中,如果此时机器挂了,会**丢失** 5 秒钟的数据。但是这样性能比较好,最多丢 5 秒的数据。也可以将 translog 设置成每次写操作必须是直接 `fsync` 到磁盘,但是性能会差很多。 -- `index.translog.sync_interval` 控制 translog 多久 fsync 到磁盘,最小为 100ms; -- `index.translog.durability` translog 是每 5 秒钟刷新一次还是每次请求都 fsync,这个参数有 2 个取值:request(每次请求都执行 fsync,es 要等 translog fsync 到磁盘后才会返回成功)和 async(默认值,translog 每隔 5 秒钟 fsync 一次)。 +- `index.translog.sync_interval` 控制 translog 多久 fsync 到磁盘,最小为 100ms; +- `index.translog.durability` translog 是每 5 秒钟刷新一次还是每次请求都 fsync,这个参数有 2 个取值:request(每次请求都执行 fsync,es 要等 translog fsync 到磁盘后才会返回成功)和 async(默认值,translog 每隔 5 秒钟 fsync 一次)。 实际上你在这里,如果面试官没有问你 es 丢数据的问题,你可以在这里给面试官炫一把,你说,其实 es 第一是准实时的,数据写入 1 秒后可以搜索到;可能会丢失数据的。有 5 秒的数据,停留在 buffer、translog os cache、segment file os cache 中,而不在磁盘上,此时如果宕机,会导致 5 秒的**数据丢失**。 @@ -136,7 +136,7 @@ buffer 每 refresh 一次,就会产生一个 `segment file` ,所以默认情 要注意倒排索引的两个重要细节: -- 倒排索引中的所有词项对应一个或多个文档; -- 倒排索引中的词项**根据字典顺序升序排列** +- 倒排索引中的所有词项对应一个或多个文档; +- 倒排索引中的词项**根据字典顺序升序排列** > 上面只是一个简单的栗子,并没有严格按照字典顺序升序排列。 diff --git a/docs/high-concurrency/high-concurrency-design.md b/docs/high-concurrency/high-concurrency-design.md index bf280897d..8ecb09410 100644 --- a/docs/high-concurrency/high-concurrency-design.md +++ b/docs/high-concurrency/high-concurrency-design.md @@ -32,12 +32,12 @@ 可以分为以下 6 点: -- 系统拆分 -- 缓存 -- MQ -- 分库分表 -- 读写分离 -- ElasticSearch +- 系统拆分 +- 缓存 +- MQ +- 分库分表 +- 读写分离 +- ElasticSearch ![high-concurrency-system-design](./images/high-concurrency-system-design.png) diff --git a/docs/high-concurrency/how-to-ensure-high-concurrency-and-high-availability-of-redis.md b/docs/high-concurrency/how-to-ensure-high-concurrency-and-high-availability-of-redis.md index 3dcb7f297..7ed909c83 100644 --- a/docs/high-concurrency/how-to-ensure-high-concurrency-and-high-availability-of-redis.md +++ b/docs/high-concurrency/how-to-ensure-high-concurrency-and-high-availability-of-redis.md @@ -14,8 +14,8 @@ 由于此节内容较多,因此,会分为两个小节进行讲解。 -- [redis 主从架构](/docs/high-concurrency/redis-master-slave.md) -- [redis 基于哨兵实现高可用](/docs/high-concurrency/redis-sentinel.md) +- [redis 主从架构](/docs/high-concurrency/redis-master-slave.md) +- [redis 基于哨兵实现高可用](/docs/high-concurrency/redis-sentinel.md) redis 实现**高并发**主要依靠**主从架构**,一主多从,一般来说,很多项目其实就足够了,单主用来写入数据,单机几万 QPS,多从用来查询数据,多个从实例可以提供每秒 10w 的 QPS。 diff --git a/docs/high-concurrency/how-to-ensure-that-messages-are-not-repeatedly-consumed.md b/docs/high-concurrency/how-to-ensure-that-messages-are-not-repeatedly-consumed.md index c7c73ec2f..433674350 100644 --- a/docs/high-concurrency/how-to-ensure-that-messages-are-not-repeatedly-consumed.md +++ b/docs/high-concurrency/how-to-ensure-that-messages-are-not-repeatedly-consumed.md @@ -38,10 +38,10 @@ Kafka 实际上有个 offset 的概念,就是每个消息写进去,都有一 其实还是得结合业务来思考,我这里给几个思路: -- 比如你拿个数据要写库,你先根据主键查一下,如果这数据都有了,你就别插入了,update 一下好吧。 -- 比如你是写 Redis,那没问题了,反正每次都是 set,天然幂等性。 -- 比如你不是上面两个场景,那做的稍微复杂一点,你需要让生产者发送每条数据的时候,里面加一个全局唯一的 id,类似订单 id 之类的东西,然后你这里消费到了之后,先根据这个 id 去比如 Redis 里查一下,之前消费过吗?如果没有消费过,你就处理,然后这个 id 写 Redis。如果消费过了,那你就别处理了,保证别重复处理相同的消息即可。 -- 比如基于数据库的唯一键来保证重复数据不会重复插入多条。因为有唯一键约束了,重复数据插入只会报错,不会导致数据库中出现脏数据。 +- 比如你拿个数据要写库,你先根据主键查一下,如果这数据都有了,你就别插入了,update 一下好吧。 +- 比如你是写 Redis,那没问题了,反正每次都是 set,天然幂等性。 +- 比如你不是上面两个场景,那做的稍微复杂一点,你需要让生产者发送每条数据的时候,里面加一个全局唯一的 id,类似订单 id 之类的东西,然后你这里消费到了之后,先根据这个 id 去比如 Redis 里查一下,之前消费过吗?如果没有消费过,你就处理,然后这个 id 写 Redis。如果消费过了,那你就别处理了,保证别重复处理相同的消息即可。 +- 比如基于数据库的唯一键来保证重复数据不会重复插入多条。因为有唯一键约束了,重复数据插入只会报错,不会导致数据库中出现脏数据。 ![mq-11](./images/mq-11.png) diff --git a/docs/high-concurrency/how-to-ensure-the-order-of-messages.md b/docs/high-concurrency/how-to-ensure-the-order-of-messages.md index 1c321260d..7afeb0da2 100644 --- a/docs/high-concurrency/how-to-ensure-the-order-of-messages.md +++ b/docs/high-concurrency/how-to-ensure-the-order-of-messages.md @@ -16,11 +16,11 @@ 先看看顺序会错乱的俩场景: -- **RabbitMQ**:一个 queue,多个 consumer。比如,生产者向 RabbitMQ 里发送了三条数据,顺序依次是 data1/data2/data3,压入的是 RabbitMQ 的一个内存队列。有三个消费者分别从 MQ 中消费这三条数据中的一条,结果消费者 2 先执行完操作,把 data2 存入数据库,然后是 data1/data3。这不明显乱了。 +- **RabbitMQ**:一个 queue,多个 consumer。比如,生产者向 RabbitMQ 里发送了三条数据,顺序依次是 data1/data2/data3,压入的是 RabbitMQ 的一个内存队列。有三个消费者分别从 MQ 中消费这三条数据中的一条,结果消费者 2 先执行完操作,把 data2 存入数据库,然后是 data1/data3。这不明显乱了。 ![rabbitmq-order-01](./images/rabbitmq-order-01.png) -- **Kafka**:比如说我们建了一个 topic,有三个 partition。生产者在写的时候,其实可以指定一个 key,比如说我们指定了某个订单 id 作为 key,那么这个订单相关的数据,一定会被分发到同一个 partition 中去,而且这个 partition 中的数据一定是有顺序的。
消费者从 partition 中取出来数据的时候,也一定是有顺序的。到这里,顺序还是 ok 的,没有错乱。接着,我们在消费者里可能会搞**多个线程来并发处理消息**。因为如果消费者是单线程消费处理,而处理比较耗时的话,比如处理一条消息耗时几十 ms,那么 1 秒钟只能处理几十条消息,这吞吐量太低了。而多个线程并发跑的话,顺序可能就乱掉了。 +- **Kafka**:比如说我们建了一个 topic,有三个 partition。生产者在写的时候,其实可以指定一个 key,比如说我们指定了某个订单 id 作为 key,那么这个订单相关的数据,一定会被分发到同一个 partition 中去,而且这个 partition 中的数据一定是有顺序的。
消费者从 partition 中取出来数据的时候,也一定是有顺序的。到这里,顺序还是 ok 的,没有错乱。接着,我们在消费者里可能会搞**多个线程来并发处理消息**。因为如果消费者是单线程消费处理,而处理比较耗时的话,比如处理一条消息耗时几十 ms,那么 1 秒钟只能处理几十条消息,这吞吐量太低了。而多个线程并发跑的话,顺序可能就乱掉了。 ![kafka-order-01](./images/kafka-order-01.png) @@ -38,7 +38,7 @@ #### Kafka -- 一个 topic,一个 partition,一个 consumer,内部单线程消费,单线程吞吐量太低,一般不会用这个。 -- 写 N 个内存 queue,具有相同 key 的数据都到同一个内存 queue;然后对于 N 个线程,每个线程分别消费一个内存 queue 即可,这样就能保证顺序性。 +- 一个 topic,一个 partition,一个 consumer,内部单线程消费,单线程吞吐量太低,一般不会用这个。 +- 写 N 个内存 queue,具有相同 key 的数据都到同一个内存 queue;然后对于 N 个线程,每个线程分别消费一个内存 queue 即可,这样就能保证顺序性。 ![kafka-order-02](./images/kafka-order-02.png) diff --git a/docs/high-concurrency/how-to-ensure-the-reliable-transmission-of-messages.md b/docs/high-concurrency/how-to-ensure-the-reliable-transmission-of-messages.md index 0cd715d01..ab56eb657 100644 --- a/docs/high-concurrency/how-to-ensure-the-reliable-transmission-of-messages.md +++ b/docs/high-concurrency/how-to-ensure-the-reliable-transmission-of-messages.md @@ -117,9 +117,9 @@ while (true) { 设置持久化有**两个步骤**: -- 创建 queue 的时候将其设置为持久化。这样就可以保证 RabbitMQ 持久化 queue 的元数据,但是它是不会持久化 queue 里的数据的。 +- 创建 queue 的时候将其设置为持久化。这样就可以保证 RabbitMQ 持久化 queue 的元数据,但是它是不会持久化 queue 里的数据的。 -- 第二个是发送消息的时候将消息的 `deliveryMode` 设置为 2。就是将消息设置为持久化的,此时 RabbitMQ 就会将消息持久化到磁盘上去。 +- 第二个是发送消息的时候将消息的 `deliveryMode` 设置为 2。就是将消息设置为持久化的,此时 RabbitMQ 就会将消息持久化到磁盘上去。 必须要同时设置这两个持久化才行,RabbitMQ 哪怕是挂了,再次重启,也会从磁盘上重启恢复 queue,恢复这个 queue 里的数据。 @@ -155,10 +155,10 @@ RabbitMQ 如果丢失了数据,主要是因为你消费的时候,**刚消费 所以此时一般是要求起码设置如下 4 个参数: -- 给 topic 设置 `replication.factor` 参数:这个值必须大于 1,要求每个 partition 必须有至少 2 个副本。 -- 在 Kafka 服务端设置 `min.insync.replicas` 参数:这个值必须大于 1,这个是要求一个 leader 至少感知到有至少一个 follower 还跟自己保持联系,没掉队,这样才能确保 leader 挂了还有一个 follower 吧。 -- 在 producer 端设置 `acks=all` :这个是要求每条数据,必须是**写入所有 replica 之后,才能认为是写成功了**。 -- 在 producer 端设置 `retries=MAX` (很大很大很大的一个值,无限次重试的意思):这个是**要求一旦写入失败,就无限重试**,卡在这里了。 +- 给 topic 设置 `replication.factor` 参数:这个值必须大于 1,要求每个 partition 必须有至少 2 个副本。 +- 在 Kafka 服务端设置 `min.insync.replicas` 参数:这个值必须大于 1,这个是要求一个 leader 至少感知到有至少一个 follower 还跟自己保持联系,没掉队,这样才能确保 leader 挂了还有一个 follower 吧。 +- 在 producer 端设置 `acks=all` :这个是要求每条数据,必须是**写入所有 replica 之后,才能认为是写成功了**。 +- 在 producer 端设置 `retries=MAX` (很大很大很大的一个值,无限次重试的意思):这个是**要求一旦写入失败,就无限重试**,卡在这里了。 我们生产环境就是按照上述要求配置的,这样配置之后,至少在 Kafka broker 端就可以保证在 leader 所在 broker 发生故障,进行 leader 切换时,数据不会丢失。 diff --git a/docs/high-concurrency/how-to-limit-current.md b/docs/high-concurrency/how-to-limit-current.md index bdd61d82b..a1d30f94f 100644 --- a/docs/high-concurrency/how-to-limit-current.md +++ b/docs/high-concurrency/how-to-limit-current.md @@ -273,7 +273,7 @@ public class TokenBucket { ### spring cloud gateway -- spring cloud gateway 默认使用 redis 进行限流,笔者一般只是修改修改参数属于拿来即用,并没有去从头实现上述那些算法。 +- spring cloud gateway 默认使用 redis 进行限流,笔者一般只是修改修改参数属于拿来即用,并没有去从头实现上述那些算法。 ```xml @@ -288,25 +288,25 @@ public class TokenBucket { ```yaml spring: - cloud: - gateway: - routes: - - id: requestratelimiter_route + cloud: + gateway: + routes: + - id: requestratelimiter_route - uri: lb://pigx-upms - order: 10000 - predicates: - - Path=/admin/** + uri: lb://pigx-upms + order: 10000 + predicates: + - Path=/admin/** - filters: - - name: RequestRateLimiter + filters: + - name: RequestRateLimiter - args: - redis-rate-limiter.replenishRate: 1 # 令牌桶的容积 - redis-rate-limiter.burstCapacity: 3 # 流速 每秒 - key-resolver: "#{@remoteAddrKeyResolver}" #SPEL表达式去的对应的bean + args: + redis-rate-limiter.replenishRate: 1 # 令牌桶的容积 + redis-rate-limiter.burstCapacity: 3 # 流速 每秒 + key-resolver: '#{@remoteAddrKeyResolver}' #SPEL表达式去的对应的bean - - StripPrefix=1 + - StripPrefix=1 ``` ```java @@ -318,7 +318,7 @@ KeyResolver remoteAddrKeyResolver() { ### sentinel -- 通过配置来控制每个 url 的流量 +- 通过配置来控制每个 url 的流量 ```xml @@ -329,25 +329,25 @@ KeyResolver remoteAddrKeyResolver() { ```yaml spring: - cloud: - nacos: - discovery: - server-addr: localhost:8848 - sentinel: - transport: - dashboard: localhost:8080 - port: 8720 - datasource: - ds: - nacos: - server-addr: localhost:8848 - dataId: spring-cloud-sentinel-nacos - groupId: DEFAULT_GROUP - rule-type: flow - namespace: xxxxxxxx + cloud: + nacos: + discovery: + server-addr: localhost:8848 + sentinel: + transport: + dashboard: localhost:8080 + port: 8720 + datasource: + ds: + nacos: + server-addr: localhost:8848 + dataId: spring-cloud-sentinel-nacos + groupId: DEFAULT_GROUP + rule-type: flow + namespace: xxxxxxxx ``` -- 配置内容在 nacos 上进行编辑 +- 配置内容在 nacos 上进行编辑 ```json [ @@ -363,13 +363,13 @@ spring: ] ``` -- resource:资源名,即限流规则的作用对象。 -- limitApp:流控针对的调用来源,若为 default 则不区分调用来源。 -- grade:限流阈值类型,QPS 或线程数模式,0 代表根据并发数量来限流,1 代表根据 QPS 来进行流量控制。 -- count:限流阈值 -- strategy:判断的根据是资源自身,还是根据其它关联资源 (refResource),还是根据链路入口 -- controlBehavior:流控效果(直接拒绝 / 排队等待 / 慢启动模式) -- clusterMode:是否为集群模式 +- resource:资源名,即限流规则的作用对象。 +- limitApp:流控针对的调用来源,若为 default 则不区分调用来源。 +- grade:限流阈值类型,QPS 或线程数模式,0 代表根据并发数量来限流,1 代表根据 QPS 来进行流量控制。 +- count:限流阈值 +- strategy:判断的根据是资源自身,还是根据其它关联资源 (refResource),还是根据链路入口 +- controlBehavior:流控效果(直接拒绝 / 排队等待 / 慢启动模式) +- clusterMode:是否为集群模式 ### 总结 diff --git a/docs/high-concurrency/mq-design.md b/docs/high-concurrency/mq-design.md index d7093a670..08f47ec56 100644 --- a/docs/high-concurrency/mq-design.md +++ b/docs/high-concurrency/mq-design.md @@ -6,8 +6,8 @@ 其实聊到这个问题,一般面试官要考察两块: -- 你有没有对某一个消息队列做过较为深入的原理的了解,或者从整体了解把握住一个消息队列的架构原理。 -- 看看你的设计能力,给你一个常见的系统,就是消息队列系统,看看你能不能从全局把握一下整体架构设计,给出一些关键点出来。 +- 你有没有对某一个消息队列做过较为深入的原理的了解,或者从整体了解把握住一个消息队列的架构原理。 +- 看看你的设计能力,给你一个常见的系统,就是消息队列系统,看看你能不能从全局把握一下整体架构设计,给出一些关键点出来。 说实话,问类似问题的时候,大部分人基本都会蒙,因为平时从来没有思考过类似的问题,**大多数人就是平时埋头用,从来不去思考背后的一些东西**。类似的问题,比如,如果让你来设计一个 Spring 框架你会怎么做?如果让你来设计一个 Dubbo 框架你会怎么做?如果让你来设计一个 MyBatis 框架你会怎么做? @@ -17,12 +17,12 @@ 比如说这个消息队列系统,我们从以下几个角度来考虑一下: -- 首先这个 mq 得支持可伸缩性吧,就是需要的时候快速扩容,就可以增加吞吐量和容量,那怎么搞?设计个分布式的系统呗,参照一下 kafka 的设计理念,broker -> topic -> partition,每个 partition 放一个机器,就存一部分数据。如果现在资源不够了,简单啊,给 topic 增加 partition,然后做数据迁移,增加机器,不就可以存放更多数据,提供更高的吞吐量了? +- 首先这个 mq 得支持可伸缩性吧,就是需要的时候快速扩容,就可以增加吞吐量和容量,那怎么搞?设计个分布式的系统呗,参照一下 kafka 的设计理念,broker -> topic -> partition,每个 partition 放一个机器,就存一部分数据。如果现在资源不够了,简单啊,给 topic 增加 partition,然后做数据迁移,增加机器,不就可以存放更多数据,提供更高的吞吐量了? -- 其次你得考虑一下这个 mq 的数据要不要落地磁盘吧?那肯定要了,落磁盘才能保证别进程挂了数据就丢了。那落磁盘的时候怎么落啊?顺序写,这样就没有磁盘随机读写的寻址开销,磁盘顺序读写的性能是很高的,这就是 kafka 的思路。 +- 其次你得考虑一下这个 mq 的数据要不要落地磁盘吧?那肯定要了,落磁盘才能保证别进程挂了数据就丢了。那落磁盘的时候怎么落啊?顺序写,这样就没有磁盘随机读写的寻址开销,磁盘顺序读写的性能是很高的,这就是 kafka 的思路。 -- 其次你考虑一下你的 mq 的可用性啊?这个事儿,具体参考之前可用性那个环节讲解的 kafka 的高可用保障机制。多副本 -> leader & follower -> broker 挂了重新选举 leader 即可对外服务。 +- 其次你考虑一下你的 mq 的可用性啊?这个事儿,具体参考之前可用性那个环节讲解的 kafka 的高可用保障机制。多副本 -> leader & follower -> broker 挂了重新选举 leader 即可对外服务。 -- 能不能支持数据 0 丢失啊?可以的,参考我们之前说的那个 kafka 数据零丢失方案。 +- 能不能支持数据 0 丢失啊?可以的,参考我们之前说的那个 kafka 数据零丢失方案。 mq 肯定是很复杂的,面试官问你这个问题,其实是个开放题,他就是看看你有没有从架构角度整体构思和设计的思维以及能力。确实这个问题可以刷掉一大批人,因为大部分人平时不思考这些东西。 diff --git a/docs/high-concurrency/mq-time-delay-and-expired-failure.md b/docs/high-concurrency/mq-time-delay-and-expired-failure.md index e76c8d9b1..94641a40f 100644 --- a/docs/high-concurrency/mq-time-delay-and-expired-failure.md +++ b/docs/high-concurrency/mq-time-delay-and-expired-failure.md @@ -20,11 +20,11 @@ 一般这个时候,只能临时紧急扩容了,具体操作步骤和思路如下: -- 先修复 consumer 的问题,确保其恢复消费速度,然后将现有 consumer 都停掉。 -- 新建一个 topic,partition 是原来的 10 倍,临时建立好原先 10 倍的 queue 数量。 -- 然后写一个临时的分发数据的 consumer 程序,这个程序部署上去消费积压的数据,**消费之后不做耗时的处理**,直接均匀轮询写入临时建立好的 10 倍数量的 queue。 -- 接着临时征用 10 倍的机器来部署 consumer,每一批 consumer 消费一个临时 queue 的数据。这种做法相当于是临时将 queue 资源和 consumer 资源扩大 10 倍,以正常的 10 倍速度来消费数据。 -- 等快速消费完积压数据之后,**得恢复原先部署的架构**,**重新**用原先的 consumer 机器来消费消息。 +- 先修复 consumer 的问题,确保其恢复消费速度,然后将现有 consumer 都停掉。 +- 新建一个 topic,partition 是原来的 10 倍,临时建立好原先 10 倍的 queue 数量。 +- 然后写一个临时的分发数据的 consumer 程序,这个程序部署上去消费积压的数据,**消费之后不做耗时的处理**,直接均匀轮询写入临时建立好的 10 倍数量的 queue。 +- 接着临时征用 10 倍的机器来部署 consumer,每一批 consumer 消费一个临时 queue 的数据。这种做法相当于是临时将 queue 资源和 consumer 资源扩大 10 倍,以正常的 10 倍速度来消费数据。 +- 等快速消费完积压数据之后,**得恢复原先部署的架构**,**重新**用原先的 consumer 机器来消费消息。 ### mq 中的消息过期失效了 @@ -78,10 +78,10 @@ public ConsumeConcurrentlyStatus consumeMessage( 举例如下,某条消息的消费过程如下: -- 根据消息从 DB 查询【数据 1】 -- 根据消息从 DB 查询【数据 2】 -- 复杂的业务计算 -- 向 DB 插入【数据 3】 -- 向 DB 插入【数据 4】 +- 根据消息从 DB 查询【数据 1】 +- 根据消息从 DB 查询【数据 2】 +- 复杂的业务计算 +- 向 DB 插入【数据 3】 +- 向 DB 插入【数据 4】 这条消息的消费过程中有 4 次与 DB 的 交互,如果按照每次 5ms 计算,那么总共耗时 20ms,假设业务计算耗时 5ms,那么总过耗时 25ms,所以如果能把 4 次 DB 交互优化为 2 次,那么总耗时就可以优化到 15ms,即总体性能提高了 40%。所以应用如果对时延敏感的话,可以把 DB 部署在 SSD 硬盘,相比于 SCSI 磁盘,前者的 RT 会小很多。 diff --git a/docs/high-concurrency/mysql-read-write-separation.md b/docs/high-concurrency/mysql-read-write-separation.md index 7bef02603..1aed96504 100644 --- a/docs/high-concurrency/mysql-read-write-separation.md +++ b/docs/high-concurrency/mysql-read-write-separation.md @@ -44,7 +44,7 @@ show slave status 一般来说,如果主从延迟较为严重,有以下解决方案: -- 分库,将一个主库拆分为多个主库,每个主库的写并发就减少了几倍,此时主从延迟可以忽略不计。 -- 打开 MySQL 支持的并行复制,多个库并行复制。如果说某个库的写入并发就是特别高,单库写并发达到了 2000/s,并行复制还是没意义。 -- 重写代码,写代码的同学,要慎重,插入数据时立马查询可能查不到。 -- 如果确实是存在必须先插入,立马要求就查询到,然后立马就要反过来执行一些操作,对这个查询**设置直连主库**。**不推荐**这种方法,你要是这么搞,读写分离的意义就丧失了。 +- 分库,将一个主库拆分为多个主库,每个主库的写并发就减少了几倍,此时主从延迟可以忽略不计。 +- 打开 MySQL 支持的并行复制,多个库并行复制。如果说某个库的写入并发就是特别高,单库写并发达到了 2000/s,并行复制还是没意义。 +- 重写代码,写代码的同学,要慎重,插入数据时立马查询可能查不到。 +- 如果确实是存在必须先插入,立马要求就查询到,然后立马就要反过来执行一些操作,对这个查询**设置直连主库**。**不推荐**这种方法,你要是这么搞,读写分离的意义就丧失了。 diff --git a/docs/high-concurrency/redis-caching-avalanche-and-caching-penetration.md b/docs/high-concurrency/redis-caching-avalanche-and-caching-penetration.md index 6d5792597..eebf9e164 100644 --- a/docs/high-concurrency/redis-caching-avalanche-and-caching-penetration.md +++ b/docs/high-concurrency/redis-caching-avalanche-and-caching-penetration.md @@ -20,9 +20,9 @@ 缓存雪崩的事前事中事后的解决方案如下: -- 事前:Redis 高可用,主从+哨兵,Redis cluster,避免全盘崩溃。 -- 事中:本地 ehcache 缓存 + hystrix 限流&降级,避免 MySQL 被打死。 -- 事后:Redis 持久化,一旦重启,自动从磁盘上加载数据,快速恢复缓存数据。 +- 事前:Redis 高可用,主从+哨兵,Redis cluster,避免全盘崩溃。 +- 事中:本地 ehcache 缓存 + hystrix 限流&降级,避免 MySQL 被打死。 +- 事后:Redis 持久化,一旦重启,自动从磁盘上加载数据,快速恢复缓存数据。 ![redis-caching-avalanche-solution](./images/redis-caching-avalanche-solution.png) @@ -32,9 +32,9 @@ 好处: -- 数据库绝对不会死,限流组件确保了每秒只有多少个请求能通过。 -- 只要数据库不死,就是说,对用户来说,2/5 的请求都是可以被处理的。 -- 只要有 2/5 的请求可以被处理,就意味着你的系统没死,对用户来说,可能就是点击几次刷不出来页面,但是多点几次,就可以刷出来了。 +- 数据库绝对不会死,限流组件确保了每秒只有多少个请求能通过。 +- 只要数据库不死,就是说,对用户来说,2/5 的请求都是可以被处理的。 +- 只要有 2/5 的请求可以被处理,就意味着你的系统没死,对用户来说,可能就是点击几次刷不出来页面,但是多点几次,就可以刷出来了。 ### 缓存穿透(Cache Penetration) @@ -50,8 +50,8 @@ 当然,如果黑客如果每次使用不同的负数 id 来攻击,写空值的方法可能就不奏效了。更为经常的做法是在缓存之前增加布隆过滤器,将数据库中所有可能的数据哈希映射到布隆过滤器中。然后对每个请求进行如下判断: -- 请求数据的 key 不存在于布隆过滤器中,可以确定数据就一定不会存在于数据库中,系统可以立即返回不存在。 -- 请求数据的 key 存在于布隆过滤器中,则继续再向缓存中查询。 +- 请求数据的 key 不存在于布隆过滤器中,可以确定数据就一定不会存在于数据库中,系统可以立即返回不存在。 +- 请求数据的 key 存在于布隆过滤器中,则继续再向缓存中查询。 使用布隆过滤器能够对访问的请求起到了一定的初筛作用,避免了因数据不存在引起的查询压力。 @@ -63,6 +63,6 @@ 不同场景下的解决方式可如下: -- 若缓存的数据是基本不会发生更新的,则可尝试将该热点数据设置为永不过期。 -- 若缓存的数据更新不频繁,且缓存刷新的整个流程耗时较少的情况下,则可以采用基于 Redis、zookeeper 等分布式中间件的分布式互斥锁,或者本地互斥锁以保证仅少量的请求能请求数据库并重新构建缓存,其余线程则在锁释放后能访问到新缓存。 -- 若缓存的数据更新频繁或者在缓存刷新的流程耗时较长的情况下,可以利用定时线程在缓存过期前主动地重新构建缓存或者延后缓存的过期时间,以保证所有的请求能一直访问到对应的缓存。 +- 若缓存的数据是基本不会发生更新的,则可尝试将该热点数据设置为永不过期。 +- 若缓存的数据更新不频繁,且缓存刷新的整个流程耗时较少的情况下,则可以采用基于 Redis、zookeeper 等分布式中间件的分布式互斥锁,或者本地互斥锁以保证仅少量的请求能请求数据库并重新构建缓存,其余线程则在锁释放后能访问到新缓存。 +- 若缓存的数据更新频繁或者在缓存刷新的流程耗时较长的情况下,可以利用定时线程在缓存过期前主动地重新构建缓存或者延后缓存的过期时间,以保证所有的请求能一直访问到对应的缓存。 diff --git a/docs/high-concurrency/redis-cluster.md b/docs/high-concurrency/redis-cluster.md index 10c0969ee..74ed7292d 100644 --- a/docs/high-concurrency/redis-cluster.md +++ b/docs/high-concurrency/redis-cluster.md @@ -18,8 +18,8 @@ Redis cluster,主要是针对**海量数据+高并发+高可用**的场景。R ### Redis cluster 介绍 -- 自动将数据进行分片,每个 master 上放一部分数据 -- 提供内置的高可用支持,部分 master 不可用时,还是可以继续工作的 +- 自动将数据进行分片,每个 master 上放一部分数据 +- 提供内置的高可用支持,部分 master 不可用时,还是可以继续工作的 在 Redis cluster 架构下,每个 Redis 要放开两个端口号,比如一个是 6379,另外一个就是 加 1w 的端口号,比如 16379。 @@ -43,15 +43,15 @@ Redis 维护集群元数据采用另一个方式, `gossip` 协议,所有节 gossip 好处在于,元数据的更新比较分散,不是集中在一个地方,更新请求会陆陆续续打到所有节点上去更新,降低了压力;不好在于,元数据的更新有延时,可能导致集群中的一些操作会有一些滞后。 -- 10000 端口:每个节点都有一个专门用于节点间通信的端口,就是自己提供服务的端口号+10000,比如 7001,那么用于节点间通信的就是 17001 端口。每个节点每隔一段时间都会往另外几个节点发送 `ping` 消息,同时其它几个节点接收到 `ping` 之后返回 `pong` 。 +- 10000 端口:每个节点都有一个专门用于节点间通信的端口,就是自己提供服务的端口号+10000,比如 7001,那么用于节点间通信的就是 17001 端口。每个节点每隔一段时间都会往另外几个节点发送 `ping` 消息,同时其它几个节点接收到 `ping` 之后返回 `pong` 。 -- 交换的信息:信息包括故障信息,节点的增加和删除,hash slot 信息等等。 +- 交换的信息:信息包括故障信息,节点的增加和删除,hash slot 信息等等。 #### gossip 协议 gossip 协议包含多种消息,包含 `ping` , `pong` , `meet` , `fail` 等等。 -- meet:某个节点发送 meet 给新加入的节点,让新节点加入集群中,然后新节点就会开始与其它节点进行通信。 +- meet:某个节点发送 meet 给新加入的节点,让新节点加入集群中,然后新节点就会开始与其它节点进行通信。 ```bash Redis-trib.rb add-node @@ -59,9 +59,9 @@ Redis-trib.rb add-node 其实内部就是发送了一个 gossip meet 消息给新加入的节点,通知那个节点去加入我们的集群。 -- ping:每个节点都会频繁给其它节点发送 ping,其中包含自己的状态还有自己维护的集群元数据,互相通过 ping 交换元数据。 -- pong:返回 ping 和 meet,包含自己的状态和其它信息,也用于信息广播和更新。 -- fail:某个节点判断另一个节点 fail 之后,就发送 fail 给其它节点,通知其它节点说,某个节点宕机啦。 +- ping:每个节点都会频繁给其它节点发送 ping,其中包含自己的状态还有自己维护的集群元数据,互相通过 ping 交换元数据。 +- pong:返回 ping 和 meet,包含自己的状态和其它信息,也用于信息广播和更新。 +- fail:某个节点判断另一个节点 fail 之后,就发送 fail 给其它节点,通知其它节点说,某个节点宕机啦。 #### ping 消息深入 @@ -73,9 +73,9 @@ ping 时要携带一些元数据,如果很频繁,可能会加重网络负担 ### 分布式寻址算法 -- hash 算法(大量缓存重建) -- 一致性 hash 算法(自动缓存迁移)+ 虚拟节点(自动负载均衡) -- Redis cluster 的 hash slot 算法 +- hash 算法(大量缓存重建) +- 一致性 hash 算法(自动缓存迁移)+ 虚拟节点(自动负载均衡) +- Redis cluster 的 hash slot 算法 #### hash 算法 diff --git a/docs/high-concurrency/redis-consistence.md b/docs/high-concurrency/redis-consistence.md index 23146e1d4..aa0ff7db1 100644 --- a/docs/high-concurrency/redis-consistence.md +++ b/docs/high-concurrency/redis-consistence.md @@ -16,8 +16,8 @@ 最经典的缓存+数据库读写的模式,就是 Cache Aside Pattern。 -- 读的时候,先读缓存,缓存没有的话,就读数据库,然后取出数据后放入缓存,同时返回响应。 -- 更新的时候,**先更新数据库,然后再删除缓存**。 +- 读的时候,先读缓存,缓存没有的话,就读数据库,然后取出数据后放入缓存,同时返回响应。 +- 更新的时候,**先更新数据库,然后再删除缓存**。 **为什么是删除缓存,而不是更新缓存?** @@ -75,7 +75,7 @@ public void set(key, value) { 高并发的场景下,该解决方案要注意的问题: -- 读请求长时阻塞 +- 读请求长时阻塞 由于读请求进行了非常轻度的异步化,所以一定要注意读超时的问题,每个读请求必须在超时时间范围内返回。 @@ -95,19 +95,19 @@ public void set(key, value) { 经过刚才简单的测算,我们知道,单机支撑的写 QPS 在几百是没问题的,如果写 QPS 扩大了 10 倍,那么就扩容机器,扩容 10 倍的机器,每个机器 20 个队列。 -- 读请求并发量过高 +- 读请求并发量过高 这里还必须做好压力测试,确保恰巧碰上上述情况的时候,还有一个风险,就是突然间大量读请求会在几十毫秒的延时 hang 在服务上,看服务能不能扛的住,需要多少机器才能扛住最大的极限情况的峰值。 但是因为并不是所有的数据都在同一时间更新,缓存也不会同一时间失效,所以每次可能也就是少数数据的缓存失效了,然后那些数据对应的读请求过来,并发量应该也不会特别大。 -- 多服务实例部署的请求路由 +- 多服务实例部署的请求路由 可能这个服务部署了多个实例,那么必须**保证**说,执行数据更新操作,以及执行缓存更新操作的请求,都通过 Nginx 服务器**路由到相同的服务实例上**。 比如说,对同一个商品的读写请求,全部路由到同一台机器上。可以自己去做服务间的按照某个请求参数的 hash 路由,也可以用 Nginx 的 hash 路由功能等等。 -- 热点商品的路由问题,导致请求的倾斜 +- 热点商品的路由问题,导致请求的倾斜 万一某个商品的读写请求特别高,全部打到相同的机器的相同的队列里面去了,可能会造成某台机器的压力过大。就是说,因为只有在商品数据更新的时候才会清空缓存,然后才会导致读写并发,所以其实要根据业务系统去看,如果更新频率不是太高的话,这个问题的影响并不是特别大,但是的确可能某些机器的负载会高一些。 diff --git a/docs/high-concurrency/redis-data-types.md b/docs/high-concurrency/redis-data-types.md index bb312436f..a5eab5944 100644 --- a/docs/high-concurrency/redis-data-types.md +++ b/docs/high-concurrency/redis-data-types.md @@ -8,8 +8,8 @@ Redis 都有哪些数据类型?分别在哪些场景下使用比较合适? 其实问这个问题,主要有两个原因: -- 看看你到底有没有全面的了解 Redis 有哪些功能,一般怎么来用,啥场景用什么,就怕你别就会最简单的 KV 操作; -- 看看你在实际项目里都怎么玩儿过 Redis。 +- 看看你到底有没有全面的了解 Redis 有哪些功能,一般怎么来用,啥场景用什么,就怕你别就会最简单的 KV 操作; +- 看看你在实际项目里都怎么玩儿过 Redis。 要是你回答的不好,没说出几种数据类型,也没说什么场景,你完了,面试官对你印象肯定不好,觉得你平时就是做个简单的 set 和 get。 @@ -17,11 +17,11 @@ Redis 都有哪些数据类型?分别在哪些场景下使用比较合适? Redis 主要有以下几种数据类型: -- Strings -- Hashes -- Lists -- Sets -- Sorted Sets +- Strings +- Hashes +- Lists +- Sets +- Sorted Sets > Redis 除了这 5 种数据类型之外,还有 Bitmaps、HyperLogLogs、Streams 等。 diff --git a/docs/high-concurrency/redis-expiration-policies-and-lru.md b/docs/high-concurrency/redis-expiration-policies-and-lru.md index 8425e5649..c91d6b9d2 100644 --- a/docs/high-concurrency/redis-expiration-policies-and-lru.md +++ b/docs/high-concurrency/redis-expiration-policies-and-lru.md @@ -8,7 +8,7 @@ Redis 的过期策略都有哪些?内存淘汰机制都有哪些?手写一 常见的有两个问题: -- 往 Redis 写入的数据怎么没了? +- 往 Redis 写入的数据怎么没了? 可能有同学会遇到,在生产环境的 Redis 经常会丢掉一些数据,写进去了,过一会儿可能就没了。我的天,同学,你问这个问题就说明 Redis 你就没用对啊。Redis 是缓存,你给当存储了是吧? @@ -16,7 +16,7 @@ Redis 的过期策略都有哪些?内存淘汰机制都有哪些?手写一 那既然内存是有限的,比如 Redis 就只能用 10G,你要是往里面写了 20G 的数据,会咋办?当然会干掉 10G 的数据,然后就保留 10G 的数据了。那干掉哪些数据?保留哪些数据?当然是干掉不常用的数据,保留常用的数据了。 -- 数据明明过期了,怎么还占用着内存? +- 数据明明过期了,怎么还占用着内存? 这是由 Redis 的过期策略来决定。 @@ -42,12 +42,12 @@ Redis 过期策略是:**定期删除+惰性删除**。 Redis 内存淘汰机制有以下几个: -- noeviction: 当内存不足以容纳新写入数据时,新写入操作会报错,这个一般没人用吧,实在是太恶心了。 -- **allkeys-lru**:当内存不足以容纳新写入数据时,在**键空间**中,移除最近最少使用的 key(这个是**最常用**的)。 -- allkeys-random:当内存不足以容纳新写入数据时,在**键空间**中,随机移除某个 key,这个一般没人用吧,为啥要随机,肯定是把最近最少使用的 key 给干掉啊。 -- volatile-lru:当内存不足以容纳新写入数据时,在**设置了过期时间的键空间**中,移除最近最少使用的 key(这个一般不太合适)。 -- volatile-random:当内存不足以容纳新写入数据时,在**设置了过期时间的键空间**中,**随机移除**某个 key。 -- volatile-ttl:当内存不足以容纳新写入数据时,在**设置了过期时间的键空间**中,有**更早过期时间**的 key 优先移除。 +- noeviction: 当内存不足以容纳新写入数据时,新写入操作会报错,这个一般没人用吧,实在是太恶心了。 +- **allkeys-lru**:当内存不足以容纳新写入数据时,在**键空间**中,移除最近最少使用的 key(这个是**最常用**的)。 +- allkeys-random:当内存不足以容纳新写入数据时,在**键空间**中,随机移除某个 key,这个一般没人用吧,为啥要随机,肯定是把最近最少使用的 key 给干掉啊。 +- volatile-lru:当内存不足以容纳新写入数据时,在**设置了过期时间的键空间**中,移除最近最少使用的 key(这个一般不太合适)。 +- volatile-random:当内存不足以容纳新写入数据时,在**设置了过期时间的键空间**中,**随机移除**某个 key。 +- volatile-ttl:当内存不足以容纳新写入数据时,在**设置了过期时间的键空间**中,有**更早过期时间**的 key 优先移除。 ### 手写一个 LRU 算法 diff --git a/docs/high-concurrency/redis-master-slave.md b/docs/high-concurrency/redis-master-slave.md index dc45f3de6..34cac22c6 100644 --- a/docs/high-concurrency/redis-master-slave.md +++ b/docs/high-concurrency/redis-master-slave.md @@ -8,12 +8,12 @@ Redis replication -> 主从架构 -> 读写分离 -> 水平扩容支撑读高并 ## Redis replication 的核心机制 -- Redis 采用**异步方式**复制数据到 slave 节点,不过 Redis2.8 开始,slave node 会周期性地确认自己每次复制的数据量; -- 一个 master node 是可以配置多个 slave node 的; -- slave node 也可以连接其他的 slave node; -- slave node 做复制的时候,不会 block master node 的正常工作; -- slave node 在做复制的时候,也不会 block 对自己的查询操作,它会用旧的数据集来提供服务;但是复制完成的时候,需要删除旧数据集,加载新数据集,这个时候就会暂停对外服务了; -- slave node 主要用来进行横向扩容,做读写分离,扩容的 slave node 可以提高读的吞吐量。 +- Redis 采用**异步方式**复制数据到 slave 节点,不过 Redis2.8 开始,slave node 会周期性地确认自己每次复制的数据量; +- 一个 master node 是可以配置多个 slave node 的; +- slave node 也可以连接其他的 slave node; +- slave node 做复制的时候,不会 block master node 的正常工作; +- slave node 在做复制的时候,也不会 block 对自己的查询操作,它会用旧的数据集来提供服务;但是复制完成的时候,需要删除旧数据集,加载新数据集,这个时候就会暂停对外服务了; +- slave node 主要用来进行横向扩容,做读写分离,扩容的 slave node 可以提高读的吞吐量。 注意,如果采用了主从架构,那么建议必须**开启** master node 的[持久化](/docs/high-concurrency/redis-persistence.md),不建议用 slave node 作为 master node 的数据热备,因为那样的话,如果你关掉 master 的持久化,可能在 master 宕机重启的时候数据是空的,然后可能一经过复制, slave node 的数据也丢了。 @@ -60,23 +60,23 @@ slave node 内部有个定时任务,每秒检查是否有新的 master node ### 全量复制 -- master 执行 bgsave ,在本地生成一份 rdb 快照文件。 -- master node 将 rdb 快照文件发送给 slave node,如果 rdb 复制时间超过 60 秒(repl-timeout),那么 slave node 就会认为复制失败,可以适当调大这个参数(对于千兆网卡的机器,一般每秒传输 100MB,6G 文件,很可能超过 60s) -- master node 在生成 rdb 时,会将所有新的写命令缓存在内存中,在 slave node 保存了 rdb 之后,再将新的写命令复制给 slave node。 -- 如果在复制期间,内存缓冲区持续消耗超过 64MB,或者一次性超过 256MB,那么停止复制,复制失败。 +- master 执行 bgsave ,在本地生成一份 rdb 快照文件。 +- master node 将 rdb 快照文件发送给 slave node,如果 rdb 复制时间超过 60 秒(repl-timeout),那么 slave node 就会认为复制失败,可以适当调大这个参数(对于千兆网卡的机器,一般每秒传输 100MB,6G 文件,很可能超过 60s) +- master node 在生成 rdb 时,会将所有新的写命令缓存在内存中,在 slave node 保存了 rdb 之后,再将新的写命令复制给 slave node。 +- 如果在复制期间,内存缓冲区持续消耗超过 64MB,或者一次性超过 256MB,那么停止复制,复制失败。 ```bash client-output-buffer-limit slave 256MB 64MB 60 ``` -- slave node 接收到 rdb 之后,清空自己的旧数据,然后重新加载 rdb 到自己的内存中。注意,在清空旧数据之前,slave node 依然会**基于旧的数据版本**对外提供服务。 -- 如果 slave node 开启了 AOF,那么会立即执行 BGREWRITEAOF,重写 AOF。 +- slave node 接收到 rdb 之后,清空自己的旧数据,然后重新加载 rdb 到自己的内存中。注意,在清空旧数据之前,slave node 依然会**基于旧的数据版本**对外提供服务。 +- 如果 slave node 开启了 AOF,那么会立即执行 BGREWRITEAOF,重写 AOF。 ### 增量复制 -- 如果全量复制过程中,master-slave 网络连接断掉,那么 slave 重新连接 master 时,会触发增量复制。 -- master 直接从自己的 backlog 中获取部分丢失的数据,发送给 slave node,默认 backlog 就是 1MB。 -- master 就是根据 slave 发送的 psync 中的 offset 来从 backlog 中获取数据的。 +- 如果全量复制过程中,master-slave 网络连接断掉,那么 slave 重新连接 master 时,会触发增量复制。 +- master 直接从自己的 backlog 中获取部分丢失的数据,发送给 slave node,默认 backlog 就是 1MB。 +- master 就是根据 slave 发送的 psync 中的 offset 来从 backlog 中获取数据的。 ### heartbeat diff --git a/docs/high-concurrency/redis-persistence.md b/docs/high-concurrency/redis-persistence.md index d64f0533b..b08acb011 100644 --- a/docs/high-concurrency/redis-persistence.md +++ b/docs/high-concurrency/redis-persistence.md @@ -22,8 +22,8 @@ Redis 如果仅仅只是将数据缓存在内存里面,如果 Redis 宕机了 ### Redis 持久化的两种方式 -- RDB:RDB 持久化机制,是对 Redis 中的数据执行**周期性**的持久化。 -- AOF:AOF 机制对每条写入命令作为日志,以 `append-only` 的模式写入一个日志文件中,在 Redis 重启的时候,可以通过**回放** AOF 日志中的写入指令来重新构建整个数据集。 +- RDB:RDB 持久化机制,是对 Redis 中的数据执行**周期性**的持久化。 +- AOF:AOF 机制对每条写入命令作为日志,以 `append-only` 的模式写入一个日志文件中,在 Redis 重启的时候,可以通过**回放** AOF 日志中的写入指令来重新构建整个数据集。 通过 RDB 或 AOF,都可以将 Redis 内存中的数据给持久化到磁盘上面来,然后可以将这些数据备份到别的地方去,比如说阿里云等云服务。 @@ -33,24 +33,24 @@ Redis 如果仅仅只是将数据缓存在内存里面,如果 Redis 宕机了 #### RDB 优缺点 -- RDB 会生成多个数据文件,每个数据文件都代表了某一个时刻中 Redis 的数据,这种多个数据文件的方式,**非常适合做冷备**,可以将这种完整的数据文件发送到一些远程的安全存储上去,比如说 Amazon 的 S3 云服务上去,在国内可以是阿里云的 ODPS 分布式存储上,以预定好的备份策略来定期备份 Redis 中的数据。 -- RDB 对 Redis 对外提供的读写服务,影响非常小,可以让 Redis **保持高性能**,因为 Redis 主进程只需要 fork 一个子进程,让子进程执行磁盘 IO 操作来进行 RDB 持久化即可。 -- 相对于 AOF 持久化机制来说,直接基于 RDB 数据文件来重启和恢复 Redis 进程,更加快速。 -- 如果想要在 Redis 故障时,尽可能少的丢失数据,那么 RDB 没有 AOF 好。一般来说,RDB 数据快照文件,都是每隔 5 分钟,或者更长时间生成一次,这个时候就得接受一旦 Redis 进程宕机,那么会丢失最近 5 分钟(甚至更长时间)的数据。 -- RDB 每次在 fork 子进程来执行 RDB 快照数据文件生成的时候,如果数据文件特别大,可能会导致对客户端提供的服务暂停数毫秒,或者甚至数秒。 +- RDB 会生成多个数据文件,每个数据文件都代表了某一个时刻中 Redis 的数据,这种多个数据文件的方式,**非常适合做冷备**,可以将这种完整的数据文件发送到一些远程的安全存储上去,比如说 Amazon 的 S3 云服务上去,在国内可以是阿里云的 ODPS 分布式存储上,以预定好的备份策略来定期备份 Redis 中的数据。 +- RDB 对 Redis 对外提供的读写服务,影响非常小,可以让 Redis **保持高性能**,因为 Redis 主进程只需要 fork 一个子进程,让子进程执行磁盘 IO 操作来进行 RDB 持久化即可。 +- 相对于 AOF 持久化机制来说,直接基于 RDB 数据文件来重启和恢复 Redis 进程,更加快速。 +- 如果想要在 Redis 故障时,尽可能少的丢失数据,那么 RDB 没有 AOF 好。一般来说,RDB 数据快照文件,都是每隔 5 分钟,或者更长时间生成一次,这个时候就得接受一旦 Redis 进程宕机,那么会丢失最近 5 分钟(甚至更长时间)的数据。 +- RDB 每次在 fork 子进程来执行 RDB 快照数据文件生成的时候,如果数据文件特别大,可能会导致对客户端提供的服务暂停数毫秒,或者甚至数秒。 #### AOF 优缺点 -- AOF 可以更好的保护数据不丢失,一般 AOF 会每隔 1 秒,通过一个后台线程执行一次 `fsync` 操作,最多丢失 1 秒钟的数据。 -- AOF 日志文件以 `append-only` 模式写入,所以没有任何磁盘寻址的开销,写入性能非常高,而且文件不容易破损,即使文件尾部破损,也很容易修复。 -- AOF 日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写。因为在 `rewrite` log 的时候,会对其中的指令进行压缩,创建出一份需要恢复数据的最小日志出来。在创建新日志文件的时候,老的日志文件还是照常写入。当新的 merge 后的日志文件 ready 的时候,再交换新老日志文件即可。 -- AOF 日志文件的命令通过可读较强的方式进行记录,这个特性非常**适合做灾难性的误删除的紧急恢复**。比如某人不小心用 `flushall` 命令清空了所有数据,只要这个时候后台 `rewrite` 还没有发生,那么就可以立即拷贝 AOF 文件,将最后一条 `flushall` 命令给删了,然后再将该 `AOF` 文件放回去,就可以通过恢复机制,自动恢复所有数据。 -- 对于同一份数据来说,AOF 日志文件通常比 RDB 数据快照文件更大。 -- AOF 开启后,支持的写 QPS 会比 RDB 支持的写 QPS 低,因为 AOF 一般会配置成每秒 `fsync` 一次日志文件,当然,每秒一次 `fsync` ,性能也还是很高的。(如果实时写入,那么 QPS 会大降,Redis 性能会大大降低) -- 以前 AOF 发生过 bug,就是通过 AOF 记录的日志,进行数据恢复的时候,没有恢复一模一样的数据出来。所以说,类似 AOF 这种较为复杂的基于命令日志 `merge` 回放的方式,比基于 RDB 每次持久化一份完整的数据快照文件的方式,更加脆弱一些,容易有 bug。不过 AOF 就是为了避免 rewrite 过程导致的 bug,因此每次 rewrite 并不是基于旧的指令日志进行 merge 的,而是**基于当时内存中的数据进行指令的重新构建**,这样健壮性会好很多。 +- AOF 可以更好的保护数据不丢失,一般 AOF 会每隔 1 秒,通过一个后台线程执行一次 `fsync` 操作,最多丢失 1 秒钟的数据。 +- AOF 日志文件以 `append-only` 模式写入,所以没有任何磁盘寻址的开销,写入性能非常高,而且文件不容易破损,即使文件尾部破损,也很容易修复。 +- AOF 日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写。因为在 `rewrite` log 的时候,会对其中的指令进行压缩,创建出一份需要恢复数据的最小日志出来。在创建新日志文件的时候,老的日志文件还是照常写入。当新的 merge 后的日志文件 ready 的时候,再交换新老日志文件即可。 +- AOF 日志文件的命令通过可读较强的方式进行记录,这个特性非常**适合做灾难性的误删除的紧急恢复**。比如某人不小心用 `flushall` 命令清空了所有数据,只要这个时候后台 `rewrite` 还没有发生,那么就可以立即拷贝 AOF 文件,将最后一条 `flushall` 命令给删了,然后再将该 `AOF` 文件放回去,就可以通过恢复机制,自动恢复所有数据。 +- 对于同一份数据来说,AOF 日志文件通常比 RDB 数据快照文件更大。 +- AOF 开启后,支持的写 QPS 会比 RDB 支持的写 QPS 低,因为 AOF 一般会配置成每秒 `fsync` 一次日志文件,当然,每秒一次 `fsync` ,性能也还是很高的。(如果实时写入,那么 QPS 会大降,Redis 性能会大大降低) +- 以前 AOF 发生过 bug,就是通过 AOF 记录的日志,进行数据恢复的时候,没有恢复一模一样的数据出来。所以说,类似 AOF 这种较为复杂的基于命令日志 `merge` 回放的方式,比基于 RDB 每次持久化一份完整的数据快照文件的方式,更加脆弱一些,容易有 bug。不过 AOF 就是为了避免 rewrite 过程导致的 bug,因此每次 rewrite 并不是基于旧的指令日志进行 merge 的,而是**基于当时内存中的数据进行指令的重新构建**,这样健壮性会好很多。 ### RDB 和 AOF 到底该如何选择 -- 不要仅仅使用 RDB,因为那样会导致你丢失很多数据; -- 也不要仅仅使用 AOF,因为那样有两个问题:第一,你通过 AOF 做冷备,没有 RDB 做冷备来的恢复速度更快;第二,RDB 每次简单粗暴生成数据快照,更加健壮,可以避免 AOF 这种复杂的备份和恢复机制的 bug; -- Redis 支持同时开启开启两种持久化方式,我们可以综合使用 AOF 和 RDB 两种持久化机制,用 AOF 来保证数据不丢失,作为数据恢复的第一选择;用 RDB 来做不同程度的冷备,在 AOF 文件都丢失或损坏不可用的时候,还可以使用 RDB 来进行快速的数据恢复。 +- 不要仅仅使用 RDB,因为那样会导致你丢失很多数据; +- 也不要仅仅使用 AOF,因为那样有两个问题:第一,你通过 AOF 做冷备,没有 RDB 做冷备来的恢复速度更快;第二,RDB 每次简单粗暴生成数据快照,更加健壮,可以避免 AOF 这种复杂的备份和恢复机制的 bug; +- Redis 支持同时开启开启两种持久化方式,我们可以综合使用 AOF 和 RDB 两种持久化机制,用 AOF 来保证数据不丢失,作为数据恢复的第一选择;用 RDB 来做不同程度的冷备,在 AOF 文件都丢失或损坏不可用的时候,还可以使用 RDB 来进行快速的数据恢复。 diff --git a/docs/high-concurrency/redis-sentinel.md b/docs/high-concurrency/redis-sentinel.md index 5ae5b56ad..d6aa8dff9 100644 --- a/docs/high-concurrency/redis-sentinel.md +++ b/docs/high-concurrency/redis-sentinel.md @@ -4,21 +4,21 @@ sentinel,中文名是哨兵。哨兵是 Redis 集群架构中非常重要的一个组件,主要有以下功能: -- 集群监控:负责监控 Redis master 和 slave 进程是否正常工作。 -- 消息通知:如果某个 Redis 实例有故障,那么哨兵负责发送消息作为报警通知给管理员。 -- 故障转移:如果 master node 挂掉了,会自动转移到 slave node 上。 -- 配置中心:如果故障转移发生了,通知 client 客户端新的 master 地址。 +- 集群监控:负责监控 Redis master 和 slave 进程是否正常工作。 +- 消息通知:如果某个 Redis 实例有故障,那么哨兵负责发送消息作为报警通知给管理员。 +- 故障转移:如果 master node 挂掉了,会自动转移到 slave node 上。 +- 配置中心:如果故障转移发生了,通知 client 客户端新的 master 地址。 哨兵用于实现 Redis 集群的高可用,本身也是分布式的,作为一个哨兵集群去运行,互相协同工作。 -- 故障转移时,判断一个 master node 是否宕机了,需要大部分的哨兵都同意才行,涉及到了分布式选举的问题。 -- 即使部分哨兵节点挂掉了,哨兵集群还是能正常工作的,因为如果一个作为高可用机制重要组成部分的故障转移系统本身是单点的,那就很坑爹了。 +- 故障转移时,判断一个 master node 是否宕机了,需要大部分的哨兵都同意才行,涉及到了分布式选举的问题。 +- 即使部分哨兵节点挂掉了,哨兵集群还是能正常工作的,因为如果一个作为高可用机制重要组成部分的故障转移系统本身是单点的,那就很坑爹了。 ## 哨兵的核心知识 -- 哨兵至少需要 3 个实例,来保证自己的健壮性。 -- 哨兵 + Redis 主从的部署架构,是**不保证数据零丢失**的,只能保证 Redis 集群的高可用性。 -- 对于哨兵 + Redis 主从这种复杂的部署架构,尽量在测试环境和生产环境,都进行充足的测试和演练。 +- 哨兵至少需要 3 个实例,来保证自己的健壮性。 +- 哨兵 + Redis 主从的部署架构,是**不保证数据零丢失**的,只能保证 Redis 集群的高可用性。 +- 对于哨兵 + Redis 主从这种复杂的部署架构,尽量在测试环境和生产环境,都进行充足的测试和演练。 哨兵集群必须部署 2 个以上节点,如果哨兵集群仅仅部署了 2 个哨兵实例,quorum = 1。 @@ -63,13 +63,13 @@ sentinel,中文名是哨兵。哨兵是 Redis 集群架构中非常重要的 主备切换的过程,可能会导致数据丢失: -- 异步复制导致的数据丢失 +- 异步复制导致的数据丢失 因为 master->slave 的复制是异步的,所以可能有部分数据还没复制到 slave,master 就宕机了,此时这部分数据就丢失了。 ![async-replication-data-lose-case](./images/async-replication-data-lose-case.png) -- 脑裂导致的数据丢失 +- 脑裂导致的数据丢失 脑裂,也就是说,某个 master 所在机器突然**脱离了正常的网络**,跟其他 slave 机器不能连接,但是实际上 master 还运行着。此时哨兵可能就会**认为** master 宕机了,然后开启选举,将其他 slave 切换成了 master。这个时候,集群里就会有两个 master ,也就是所谓的**脑裂**。 @@ -90,18 +90,18 @@ min-slaves-max-lag 10 如果说一旦所有的 slave,数据复制和同步的延迟都超过了 10 秒钟,那么这个时候,master 就不会再接收任何请求了。 -- 减少异步复制数据的丢失 +- 减少异步复制数据的丢失 有了 `min-slaves-max-lag` 这个配置,就可以确保说,一旦 slave 复制数据和 ack 延时太长,就认为可能 master 宕机后损失的数据太多了,那么就拒绝写请求,这样可以把 master 宕机时由于部分数据未同步到 slave 导致的数据丢失降低的可控范围内。 -- 减少脑裂的数据丢失 +- 减少脑裂的数据丢失 如果一个 master 出现了脑裂,跟其他 slave 丢了连接,那么上面两个配置可以确保说,如果不能继续给指定数量的 slave 发送数据,而且 slave 超过 10 秒没有给自己 ack 消息,那么就直接拒绝客户端的写请求。因此在脑裂场景下,最多就丢失 10 秒的数据。 ## sdown 和 odown 转换机制 -- sdown 是主观宕机,就一个哨兵如果自己觉得一个 master 宕机了,那么就是主观宕机 -- odown 是客观宕机,如果 quorum 数量的哨兵都觉得一个 master 宕机了,那么就是客观宕机 +- sdown 是主观宕机,就一个哨兵如果自己觉得一个 master 宕机了,那么就是主观宕机 +- odown 是客观宕机,如果 quorum 数量的哨兵都觉得一个 master 宕机了,那么就是客观宕机 sdown 达成的条件很简单,如果一个哨兵 ping 一个 master,超过了 `is-master-down-after-milliseconds` 指定的毫秒数之后,就主观认为 master 宕机了;如果一个哨兵在指定时间内,收到了 quorum 数量的其它哨兵也认为那个 master 是 sdown 的,那么就认为是 odown 了。 @@ -123,10 +123,10 @@ sdown 达成的条件很简单,如果一个哨兵 ping 一个 master,超过 如果一个 master 被认为 odown 了,而且 majority 数量的哨兵都允许主备切换,那么某个哨兵就会执行主备切换操作,此时首先要选举一个 slave 来,会考虑 slave 的一些信息: -- 跟 master 断开连接的时长 -- slave 优先级 -- 复制 offset -- run id +- 跟 master 断开连接的时长 +- slave 优先级 +- 复制 offset +- run id 如果一个 slave 跟 master 断开连接的时间已经超过了 `down-after-milliseconds` 的 10 倍,外加 master 宕机的时长,那么 slave 就被认为不适合选举为 master。 @@ -136,9 +136,9 @@ sdown 达成的条件很简单,如果一个哨兵 ping 一个 master,超过 接下来会对 slave 进行排序: -- 按照 slave 优先级进行排序,slave priority 越低,优先级就越高。 -- 如果 slave priority 相同,那么看 replica offset,哪个 slave 复制了越多的数据,offset 越靠后,优先级就越高。 -- 如果上面两个条件都相同,那么选择一个 run id 比较小的那个 slave。 +- 按照 slave 优先级进行排序,slave priority 越低,优先级就越高。 +- 如果 slave priority 相同,那么看 replica offset,哪个 slave 复制了越多的数据,offset 越靠后,优先级就越高。 +- 如果上面两个条件都相同,那么选择一个 run id 比较小的那个 slave。 ## quorum 和 majority diff --git a/docs/high-concurrency/redis-single-thread-model.md b/docs/high-concurrency/redis-single-thread-model.md index 9f45b5c84..9d3ad2272 100644 --- a/docs/high-concurrency/redis-single-thread-model.md +++ b/docs/high-concurrency/redis-single-thread-model.md @@ -30,10 +30,10 @@ Redis 内部使用文件事件处理器 `file event handler` ,这个文件事 文件事件处理器的结构包含 4 个部分: -- 多个 socket -- IO 多路复用程序 -- 文件事件分派器 -- 事件处理器(连接应答处理器、命令请求处理器、命令回复处理器) +- 多个 socket +- IO 多路复用程序 +- 文件事件分派器 +- 事件处理器(连接应答处理器、命令请求处理器、命令回复处理器) 多个 socket 可能会并发产生不同的操作,每个操作对应不同的文件事件,但是 IO 多路复用程序会监听多个 socket,会将产生事件的 socket 放入队列中排队,事件分派器每次从队列中取出一个 socket,根据 socket 的事件类型交给对应的事件处理器进行处理。 @@ -55,10 +55,10 @@ Redis 内部使用文件事件处理器 `file event handler` ,这个文件事 ### 为啥 Redis 单线程模型也能效率这么高? -- 纯内存操作。 -- 核心是基于非阻塞的 IO 多路复用机制。 -- C 语言实现,一般来说,C 语言实现的程序“距离”操作系统更近,执行速度相对会更快。 -- 单线程反而避免了多线程的频繁上下文切换问题,预防了多线程可能产生的竞争问题。 +- 纯内存操作。 +- 核心是基于非阻塞的 IO 多路复用机制。 +- C 语言实现,一般来说,C 语言实现的程序“距离”操作系统更近,执行速度相对会更快。 +- 单线程反而避免了多线程的频繁上下文切换问题,预防了多线程可能产生的竞争问题。 ### Redis 6.0 开始引入多线程 diff --git a/docs/high-concurrency/why-cache.md b/docs/high-concurrency/why-cache.md index 860c744d9..ec6842002 100644 --- a/docs/high-concurrency/why-cache.md +++ b/docs/high-concurrency/why-cache.md @@ -40,8 +40,8 @@ mysql 这么重的数据库,压根儿设计不是让你玩儿高并发的, 常见的缓存问题有以下几个: -- [缓存与数据库双写不一致](/docs/high-concurrency/redis-consistence.md) -- [缓存雪崩、缓存穿透、缓存击穿](/docs/high-concurrency/redis-caching-avalanche-and-caching-penetration.md) -- [缓存并发竞争](/docs/high-concurrency/redis-cas.md) +- [缓存与数据库双写不一致](/docs/high-concurrency/redis-consistence.md) +- [缓存雪崩、缓存穿透、缓存击穿](/docs/high-concurrency/redis-caching-avalanche-and-caching-penetration.md) +- [缓存并发竞争](/docs/high-concurrency/redis-cas.md) 点击超链接,可直接查看缓存相关问题及解决方案。 diff --git a/docs/high-concurrency/why-mq.md b/docs/high-concurrency/why-mq.md index e3271a9ef..c4c8ddab9 100644 --- a/docs/high-concurrency/why-mq.md +++ b/docs/high-concurrency/why-mq.md @@ -1,28 +1,28 @@ ## 面试题 -- 为什么使用消息队列? -- 消息队列有什么优点和缺点? -- Kafka、ActiveMQ、RabbitMQ、RocketMQ 都有什么区别,以及适合哪些场景? +- 为什么使用消息队列? +- 消息队列有什么优点和缺点? +- Kafka、ActiveMQ、RabbitMQ、RocketMQ 都有什么区别,以及适合哪些场景? ## 面试官心理分析 其实面试官主要是想看看: -- **第一**,你知不知道你们系统里为什么要用消息队列这个东西? +- **第一**,你知不知道你们系统里为什么要用消息队列这个东西? - 不少候选人,说自己项目里用了 Redis、MQ,但是其实他并不知道自己为什么要用这个东西。其实说白了,就是为了用而用,或者是别人设计的架构,他从头到尾都没思考过。 + 不少候选人,说自己项目里用了 Redis、MQ,但是其实他并不知道自己为什么要用这个东西。其实说白了,就是为了用而用,或者是别人设计的架构,他从头到尾都没思考过。 - 没有对自己的架构问过为什么的人,一定是平时没有思考的人,面试官对这类候选人印象通常很不好。因为面试官担心你进了团队之后只会木头木脑的干呆活儿,不会自己思考。 + 没有对自己的架构问过为什么的人,一定是平时没有思考的人,面试官对这类候选人印象通常很不好。因为面试官担心你进了团队之后只会木头木脑的干呆活儿,不会自己思考。 -- **第二**,你既然用了消息队列这个东西,你知不知道用了有什么好处&坏处? +- **第二**,你既然用了消息队列这个东西,你知不知道用了有什么好处&坏处? - 你要是没考虑过这个,那你盲目弄个 MQ 进系统里,后面出了问题你是不是就自己溜了给公司留坑?你要是没考虑过引入一个技术可能存在的弊端和风险,面试官把这类候选人招进来了,基本可能就是挖坑型选手。就怕你干 1 年挖一堆坑,自己跳槽了,给公司留下无穷后患。 + 你要是没考虑过这个,那你盲目弄个 MQ 进系统里,后面出了问题你是不是就自己溜了给公司留坑?你要是没考虑过引入一个技术可能存在的弊端和风险,面试官把这类候选人招进来了,基本可能就是挖坑型选手。就怕你干 1 年挖一堆坑,自己跳槽了,给公司留下无穷后患。 -- **第三**,既然你用了 MQ,可能是某一种 MQ,那么你当时做没做过调研? +- **第三**,既然你用了 MQ,可能是某一种 MQ,那么你当时做没做过调研? - 你别傻乎乎的自己拍脑袋看个人喜好就瞎用了一个 MQ,比如 Kafka,甚至都从没调研过业界流行的 MQ 到底有哪几种。每一个 MQ 的优点和缺点是什么。每一个 MQ **没有绝对的好坏**,但是就是看用在哪个场景可以**扬长避短,利用其优势,规避其劣势**。 + 你别傻乎乎的自己拍脑袋看个人喜好就瞎用了一个 MQ,比如 Kafka,甚至都从没调研过业界流行的 MQ 到底有哪几种。每一个 MQ 的优点和缺点是什么。每一个 MQ **没有绝对的好坏**,但是就是看用在哪个场景可以**扬长避短,利用其优势,规避其劣势**。 - 如果是一个不考虑技术选型的候选人招进了团队,leader 交给他一个任务,去设计个什么系统,他在里面用一些技术,可能都没考虑过选型,最后选的技术可能并不一定合适,一样是留坑。 + 如果是一个不考虑技术选型的候选人招进了团队,leader 交给他一个任务,去设计个什么系统,他在里面用一些技术,可能都没考虑过选型,最后选的技术可能并不一定合适,一样是留坑。 ## 面试题剖析 @@ -84,19 +84,19 @@ 缺点有以下几个: -- 系统可用性降低 +- 系统可用性降低 - 系统引入的外部依赖越多,越容易挂掉。本来你就是 A 系统调用 BCD 三个系统的接口就好了,ABCD 四个系统还好好的,没啥问题,你偏加个 MQ 进来,万一 MQ 挂了咋整?MQ 一挂,整套系统崩溃,你不就完了?如何保证消息队列的高可用,可以[点击这里查看](/docs/high-concurrency/how-to-ensure-high-availability-of-message-queues.md)。 + 系统引入的外部依赖越多,越容易挂掉。本来你就是 A 系统调用 BCD 三个系统的接口就好了,ABCD 四个系统还好好的,没啥问题,你偏加个 MQ 进来,万一 MQ 挂了咋整?MQ 一挂,整套系统崩溃,你不就完了?如何保证消息队列的高可用,可以[点击这里查看](/docs/high-concurrency/how-to-ensure-high-availability-of-message-queues.md)。 -- 系统复杂度提高 +- 系统复杂度提高 - 硬生生加个 MQ 进来,你怎么[保证消息没有重复消费](/docs/high-concurrency/how-to-ensure-that-messages-are-not-repeatedly-consumed.md)?怎么[处理消息丢失的情况](/docs/high-concurrency/how-to-ensure-the-reliable-transmission-of-messages.md)?怎么保证消息传递的顺序性?头大头大,问题一大堆,痛苦不已。 + 硬生生加个 MQ 进来,你怎么[保证消息没有重复消费](/docs/high-concurrency/how-to-ensure-that-messages-are-not-repeatedly-consumed.md)?怎么[处理消息丢失的情况](/docs/high-concurrency/how-to-ensure-the-reliable-transmission-of-messages.md)?怎么保证消息传递的顺序性?头大头大,问题一大堆,痛苦不已。 -- 一致性问题 +- 一致性问题 - A 系统处理完了直接返回成功了,人都以为你这个请求就成功了;但是问题是,要是 BCD 三个系统那里,BD 两个系统写库成功了,结果 C 系统写库失败了,咋整?你这数据就不一致了。 + A 系统处理完了直接返回成功了,人都以为你这个请求就成功了;但是问题是,要是 BCD 三个系统那里,BD 两个系统写库成功了,结果 C 系统写库失败了,咋整?你这数据就不一致了。 - 所以消息队列实际是一种非常复杂的架构,你引入它有很多好处,但是也得针对它带来的坏处做各种额外的技术方案和架构来规避掉,做好之后,你会发现,妈呀,系统复杂度提升了一个数量级,也许是复杂了 10 倍。但是关键时刻,用,还是得用的。 + 所以消息队列实际是一种非常复杂的架构,你引入它有很多好处,但是也得针对它带来的坏处做各种额外的技术方案和架构来规避掉,做好之后,你会发现,妈呀,系统复杂度提升了一个数量级,也许是复杂了 10 倍。但是关键时刻,用,还是得用的。 ### Kafka、ActiveMQ、RabbitMQ、RocketMQ 有什么优缺点? diff --git a/docs/micro-services/README.md b/docs/micro-services/README.md index 4691a8630..963bb9ad5 100644 --- a/docs/micro-services/README.md +++ b/docs/micro-services/README.md @@ -1,24 +1,24 @@ # 微服务架构 -- [微服务架构整个章节内容属额外新增,后续抽空更新,也欢迎读者们参与补充完善](https://github.com/doocs/advanced-java) -- [关于微服务架构的描述](/docs/micro-services/microservices-introduction.md) -- [从单体式架构迁移到微服务架构](/docs/micro-services/migrating-from-a-monolithic-architecture-to-a-microservices-architecture.md) -- [微服务的事件驱动数据管理](/docs/micro-services/event-driven-data-management-for-microservices.md) -- [选择微服务部署策略](/docs/micro-services/choose-microservice-deployment-strategy.md) -- [微服务架构的优势与不足](/docs/micro-services/advantages-and-disadvantages-of-microservice.md) +- [微服务架构整个章节内容属额外新增,后续抽空更新,也欢迎读者们参与补充完善](https://github.com/doocs/advanced-java) +- [关于微服务架构的描述](/docs/micro-services/microservices-introduction.md) +- [从单体式架构迁移到微服务架构](/docs/micro-services/migrating-from-a-monolithic-architecture-to-a-microservices-architecture.md) +- [微服务的事件驱动数据管理](/docs/micro-services/event-driven-data-management-for-microservices.md) +- [选择微服务部署策略](/docs/micro-services/choose-microservice-deployment-strategy.md) +- [微服务架构的优势与不足](/docs/micro-services/advantages-and-disadvantages-of-microservice.md) ## Spring Cloud 微服务架构 -- [什么是微服务?微服务之间是如何独立通讯的?](/docs/micro-services/what's-microservice-how-to-communicate.md) -- Spring Cloud 和 Dubbo 有哪些区别? -- Spring Boot 和 Spring Cloud,谈谈你对它们的理解? -- 什么是服务熔断?什么是服务降级? -- 微服务的优缺点分别是什么?说一下你在项目开发中碰到的坑? -- [你所知道的微服务技术栈都有哪些?](/docs/micro-services/micro-services-technology-stack.md) -- [微服务治理策略](/docs/micro-services/micro-service-governance.md) -- Eureka 和 Zookeeper 都可以提供服务注册与发现的功能,它们有什么区别? -- [谈谈服务发现组件 Eureka 的主要调用过程?](/docs/micro-services/how-eureka-enable-service-discovery-and-service-registration.md) -- ...... +- [什么是微服务?微服务之间是如何独立通讯的?](/docs/micro-services/what's-microservice-how-to-communicate.md) +- Spring Cloud 和 Dubbo 有哪些区别? +- Spring Boot 和 Spring Cloud,谈谈你对它们的理解? +- 什么是服务熔断?什么是服务降级? +- 微服务的优缺点分别是什么?说一下你在项目开发中碰到的坑? +- [你所知道的微服务技术栈都有哪些?](/docs/micro-services/micro-services-technology-stack.md) +- [微服务治理策略](/docs/micro-services/micro-service-governance.md) +- Eureka 和 Zookeeper 都可以提供服务注册与发现的功能,它们有什么区别? +- [谈谈服务发现组件 Eureka 的主要调用过程?](/docs/micro-services/how-eureka-enable-service-discovery-and-service-registration.md) +- ...... --- diff --git a/docs/micro-services/choose-microservice-deployment-strategy.md b/docs/micro-services/choose-microservice-deployment-strategy.md index 85409764a..1fdbafbe2 100644 --- a/docs/micro-services/choose-microservice-deployment-strategy.md +++ b/docs/micro-services/choose-microservice-deployment-strategy.md @@ -100,10 +100,10 @@ Lambda 函数 是无状态服务。一般通过激活 AWS 服务处理请求。 有四种方法激活 Lambda 函数: -- 直接方式,使用 web 服务请求 -- 自动方式,回应例如 AWS S3,DynamoDB,Kinesis 或者 Simple Email Service 等产生的事件 -- 自动方式,通过 AWS API 网关来处理应用客户端发出的 HTTP 请求 ​ -- 定时方式,通过 cron 响应 ​--很像定时器方式 +- 直接方式,使用 web 服务请求 +- 自动方式,回应例如 AWS S3,DynamoDB,Kinesis 或者 Simple Email Service 等产生的事件 +- 自动方式,通过 AWS API 网关来处理应用客户端发出的 HTTP 请求 ​ +- 定时方式,通过 cron 响应 ​--很像定时器方式 可以看出,AWS Lambda 是一种很方便部署微服务的方式。基于请求计费方式意味着用户只需要承担处理自己业务那部分的负载;另外,因为不需要了解基础架构,用户只需要开发自己的应用。 diff --git a/docs/micro-services/micro-service-governance.md b/docs/micro-services/micro-service-governance.md index 28d7b05d9..ba7363748 100644 --- a/docs/micro-services/micro-service-governance.md +++ b/docs/micro-services/micro-service-governance.md @@ -6,8 +6,8 @@ 解决方法: -- Eureka -- Zookeeper +- Eureka +- Zookeeper ## 负载均衡 @@ -15,8 +15,8 @@ 解决方法: -- Nginx -- Ribbon +- Nginx +- Ribbon ## 通讯 @@ -24,9 +24,9 @@ 解决方法: -- REST(同步) -- RPC(同步) -- MQ(异步) +- REST(同步) +- RPC(同步) +- MQ(异步) ## 配置管理 @@ -34,9 +34,9 @@ 解决方法: -- Nacos -- Spring Cloud Config -- Apollo +- Nacos +- Spring Cloud Config +- Apollo ## 容错和服务降级 @@ -44,7 +44,7 @@ 解决方法: -- Hystrix +- Hystrix ## 服务依赖关系 @@ -58,8 +58,8 @@ 解决方法: -- Swagger -- Java doc +- Swagger +- Java doc ## 服务安全问题 @@ -67,9 +67,9 @@ 解决方法: -- Oauth -- Shiro -- Spring Security +- Oauth +- Shiro +- Spring Security ## 流量控制 @@ -77,7 +77,7 @@ 解决方法: -- Hystrix +- Hystrix ## 自动化测试 @@ -85,7 +85,7 @@ 解决方法: -- junit +- junit ## 服务上线,下线的流程 @@ -105,8 +105,8 @@ 解决方法: -- Docker -- K8s +- Docker +- K8s ## 资源调度 @@ -114,9 +114,9 @@ 解决方法: -- JVM 隔离 -- Classload 隔离 -- 硬件隔离 +- JVM 隔离 +- Classload 隔离 +- 硬件隔离 ## 容量规划 diff --git a/docs/micro-services/micro-services-technology-stack.md b/docs/micro-services/micro-services-technology-stack.md index 1119bef40..c91a3177f 100644 --- a/docs/micro-services/micro-services-technology-stack.md +++ b/docs/micro-services/micro-services-technology-stack.md @@ -6,9 +6,9 @@ 作用:快速开发服务。 -- Spring -- Spring MVC -- Spring Boot +- Spring +- Spring MVC +- Spring Boot [Spring](https://spring.io/) 目前是 JavaWeb 开发人员必不可少的一个框架,SpringBoot 简化了 Spring 开发的配置目前也是业内主流开发框架。 @@ -18,9 +18,9 @@ #### Eureka -- Eureka Server : 提供服务注册服务, 各个节点启动后,会在 Eureka Server 中进行注册。 -- Eureka Client : 简化与 Eureka Server 的交互操作。 -- Spring Cloud Netflix : [GitHub](https://github.com/spring-cloud/spring-cloud-netflix),[文档](https://cloud.spring.io/spring-cloud-netflix/reference/html/) +- Eureka Server : 提供服务注册服务, 各个节点启动后,会在 Eureka Server 中进行注册。 +- Eureka Client : 简化与 Eureka Server 的交互操作。 +- Spring Cloud Netflix : [GitHub](https://github.com/spring-cloud/spring-cloud-netflix),[文档](https://cloud.spring.io/spring-cloud-netflix/reference/html/) #### Zookeeper @@ -32,9 +32,9 @@ Zookeeper 保证 CP,Eureka 保证 AP: -- C:数据一致性; -- A:服务可用性; -- P:服务对网络分区故障的容错性,这三个特性在任何分布式系统中不能同时满足,最多同时满足两个。 +- C:数据一致性; +- A:服务可用性; +- P:服务对网络分区故障的容错性,这三个特性在任何分布式系统中不能同时满足,最多同时满足两个。 ### 微服务配置管理 @@ -78,12 +78,12 @@ Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能 #### Rest -- 通过 HTTP/HTTPS 发送 Rest 请求进行数据交互 +- 通过 HTTP/HTTPS 发送 Rest 请求进行数据交互 #### RPC -- Remote Procedure Call -- 它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC 不依赖于具体的网络传输协议,tcp、udp 等都可以。 +- Remote Procedure Call +- 它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC 不依赖于具体的网络传输协议,tcp、udp 等都可以。 #### [gRPC](https://www.grpc.io/) @@ -93,8 +93,8 @@ Apollo(阿波罗)是携程框架部门研发的分布式配置中心,能 #### RMI -- Remote Method Invocation -- 纯 Java 调用 +- Remote Method Invocation +- 纯 Java 调用 ### 服务接口调用 diff --git a/docs/micro-services/migrating-from-a-monolithic-architecture-to-a-microservices-architecture.md b/docs/micro-services/migrating-from-a-monolithic-architecture-to-a-microservices-architecture.md index 6b34e5ff8..9c616c46a 100644 --- a/docs/micro-services/migrating-from-a-monolithic-architecture-to-a-microservices-architecture.md +++ b/docs/micro-services/migrating-from-a-monolithic-architecture-to-a-microservices-architecture.md @@ -24,9 +24,9 @@ Law of Holes 是说当自己进洞就应该停止挖掘。对于单体式应用 微服务有三种方式访问单体应用数据: -- 换气单体应用提供的远程 API -- 直接访问单体应用数据库 -- 自己维护一份从单体应用中同步的数据 +- 换气单体应用提供的远程 API +- 直接访问单体应用数据库 +- 自己维护一份从单体应用中同步的数据 胶水代码也被称为容灾层(anti-corruption layer),这是因为胶水代码保护微服务全新域模型免受传统单体应用域模型污染。胶水代码在这两种模型间提供翻译功能。术语 anti-corruption layer 第一次出现在 Eric Evans 撰写的必读书 _Domain Driven Design_,随后就被提炼为一篇白皮书。开发容灾层可能有点不是很重要,但却是避免单体式泥潭的必要部分。 diff --git a/docs/micro-services/what's-microservice-how-to-communicate.md b/docs/micro-services/what's-microservice-how-to-communicate.md index 6e72be57a..7367a81c1 100644 --- a/docs/micro-services/what's-microservice-how-to-communicate.md +++ b/docs/micro-services/what's-microservice-how-to-communicate.md @@ -2,8 +2,8 @@ ## 什么是微服务 -- 微服务架构是一个分布式系统,按照业务进行划分成为不同的服务单元,解决单体系统性能等不足。 -- 微服务是一种架构风格,一个大型软件应用由多个服务单元组成。系统中的服务单元可以单独部署,各个服务单元之间是松耦合的。 +- 微服务架构是一个分布式系统,按照业务进行划分成为不同的服务单元,解决单体系统性能等不足。 +- 微服务是一种架构风格,一个大型软件应用由多个服务单元组成。系统中的服务单元可以单独部署,各个服务单元之间是松耦合的。 > 微服务概念起源:[Microservices](https://martinfowler.com/articles/microservices.html) diff --git a/summary.md b/summary.md index c7ca8a630..881feb09f 100644 --- a/summary.md +++ b/summary.md @@ -1,145 +1,145 @@ -- 高并发架构 +- 高并发架构 - - [消息队列](/docs/high-concurrency/mq-interview.md) + - [消息队列](/docs/high-concurrency/mq-interview.md) - - [为什么使用消息队列?](/docs/high-concurrency/why-mq.md) - - [如何保证消息队列的高可用?](/docs/high-concurrency/how-to-ensure-high-availability-of-message-queues.md) - - [如何保证消息不被重复消费?](/docs/high-concurrency/how-to-ensure-that-messages-are-not-repeatedly-consumed.md) - - [如何保证消息的可靠性传输?](/docs/high-concurrency/how-to-ensure-the-reliable-transmission-of-messages.md) - - [如何保证消息的顺序性?](/docs/high-concurrency/how-to-ensure-the-order-of-messages.md) - - [如何解决消息队列的延时以及过期失效问题?](/docs/high-concurrency/mq-time-delay-and-expired-failure.md) - - [如何设计一个消息队列?](/docs/high-concurrency/mq-design.md) + - [为什么使用消息队列?](/docs/high-concurrency/why-mq.md) + - [如何保证消息队列的高可用?](/docs/high-concurrency/how-to-ensure-high-availability-of-message-queues.md) + - [如何保证消息不被重复消费?](/docs/high-concurrency/how-to-ensure-that-messages-are-not-repeatedly-consumed.md) + - [如何保证消息的可靠性传输?](/docs/high-concurrency/how-to-ensure-the-reliable-transmission-of-messages.md) + - [如何保证消息的顺序性?](/docs/high-concurrency/how-to-ensure-the-order-of-messages.md) + - [如何解决消息队列的延时以及过期失效问题?](/docs/high-concurrency/mq-time-delay-and-expired-failure.md) + - [如何设计一个消息队列?](/docs/high-concurrency/mq-design.md) - - [搜索引擎](/docs/high-concurrency/es-introduction.md) + - [搜索引擎](/docs/high-concurrency/es-introduction.md) - - [ES 的分布式架构原理是什么?](/docs/high-concurrency/es-architecture.md) - - [ES 写入数据的工作原理是什么?](/docs/high-concurrency/es-write-query-search.md) - - [ES 在数十亿级别数量下如何提高查询效率?](/docs/high-concurrency/es-optimizing-query-performance.md) - - [ES 生产集群的部署架构是什么?](/docs/high-concurrency/es-production-cluster.md) + - [ES 的分布式架构原理是什么?](/docs/high-concurrency/es-architecture.md) + - [ES 写入数据的工作原理是什么?](/docs/high-concurrency/es-write-query-search.md) + - [ES 在数十亿级别数量下如何提高查询效率?](/docs/high-concurrency/es-optimizing-query-performance.md) + - [ES 生产集群的部署架构是什么?](/docs/high-concurrency/es-production-cluster.md) - - 缓存 + - 缓存 - - [在项目中缓存是如何使用的?](/docs/high-concurrency/why-cache.md) - - [Redis 和 Memcached 有什么区别?](/docs/high-concurrency/redis-single-thread-model.md) - - [Redis 都有哪些数据类型以及适用场景?](/docs/high-concurrency/redis-data-types.md) - - [Redis 的过期策略都有哪些?](/docs/high-concurrency/redis-expiration-policies-and-lru.md) - - [如何保证 Redis 高并发、高可用?](/docs/high-concurrency/how-to-ensure-high-concurrency-and-high-availability-of-redis.md) - - [Redis 主从架构是怎样的?](/docs/high-concurrency/redis-master-slave.md) - - [Redis 的持久化有哪几种方式?](/docs/high-concurrency/redis-persistence.md) - - [Redis 如何基于哨兵集群实现高可用?](/docs/high-concurrency/redis-sentinel.md) - - [Redis 集群模式的工作原理能说一下么?](/docs/high-concurrency/redis-cluster.md) - - [Redis 的雪崩、穿透和击穿,如何应对?](/docs/high-concurrency/redis-caching-avalanche-and-caching-penetration.md) - - [如何保证缓存与数据库双写一致性?](/docs/high-concurrency/redis-consistence.md) - - [如何解决 Redis 的并发竞争问题?](/docs/high-concurrency/redis-cas.md) - - [生产环境中的 Redis 是怎么部署的?](/docs/high-concurrency/redis-production-environment.md) + - [在项目中缓存是如何使用的?](/docs/high-concurrency/why-cache.md) + - [Redis 和 Memcached 有什么区别?](/docs/high-concurrency/redis-single-thread-model.md) + - [Redis 都有哪些数据类型以及适用场景?](/docs/high-concurrency/redis-data-types.md) + - [Redis 的过期策略都有哪些?](/docs/high-concurrency/redis-expiration-policies-and-lru.md) + - [如何保证 Redis 高并发、高可用?](/docs/high-concurrency/how-to-ensure-high-concurrency-and-high-availability-of-redis.md) + - [Redis 主从架构是怎样的?](/docs/high-concurrency/redis-master-slave.md) + - [Redis 的持久化有哪几种方式?](/docs/high-concurrency/redis-persistence.md) + - [Redis 如何基于哨兵集群实现高可用?](/docs/high-concurrency/redis-sentinel.md) + - [Redis 集群模式的工作原理能说一下么?](/docs/high-concurrency/redis-cluster.md) + - [Redis 的雪崩、穿透和击穿,如何应对?](/docs/high-concurrency/redis-caching-avalanche-and-caching-penetration.md) + - [如何保证缓存与数据库双写一致性?](/docs/high-concurrency/redis-consistence.md) + - [如何解决 Redis 的并发竞争问题?](/docs/high-concurrency/redis-cas.md) + - [生产环境中的 Redis 是怎么部署的?](/docs/high-concurrency/redis-production-environment.md) - - 分库分表 + - 分库分表 - - [为什么要分库分表?](/docs/high-concurrency/database-shard.md) - - [分库分表如何平滑过渡?](/docs/high-concurrency/database-shard-method.md) - - [设计一个动态扩容缩容的分库分表方案?](/docs/high-concurrency/database-shard-dynamic-expand.md) - - [分库分表之后,id 主键如何处理?](/docs/high-concurrency/database-shard-global-id-generate.md) + - [为什么要分库分表?](/docs/high-concurrency/database-shard.md) + - [分库分表如何平滑过渡?](/docs/high-concurrency/database-shard-method.md) + - [设计一个动态扩容缩容的分库分表方案?](/docs/high-concurrency/database-shard-dynamic-expand.md) + - [分库分表之后,id 主键如何处理?](/docs/high-concurrency/database-shard-global-id-generate.md) - - 读写分离 + - 读写分离 - - [如何实现 MySQL 的读写分离?](/docs/high-concurrency/mysql-read-write-separation.md) + - [如何实现 MySQL 的读写分离?](/docs/high-concurrency/mysql-read-write-separation.md) - - 高并发系统 - - [如何设计一个高并发系统?](/docs/high-concurrency/high-concurrency-design.md) + - 高并发系统 + - [如何设计一个高并发系统?](/docs/high-concurrency/high-concurrency-design.md) -* 分布式系统 +* 分布式系统 - - [面试连环炮](/docs/distributed-system/distributed-system-interview.md) - - 系统拆分 + - [面试连环炮](/docs/distributed-system/distributed-system-interview.md) + - 系统拆分 - - [为什么要进行系统拆分?](/docs/distributed-system/why-dubbo.md) + - [为什么要进行系统拆分?](/docs/distributed-system/why-dubbo.md) - - 分布式服务框架 + - 分布式服务框架 - - [说一下 Dubbo 的工作原理?](/docs/distributed-system/dubbo-operating-principle.md) - - [Dubbo 支持哪些序列化协议?](/docs/distributed-system/dubbo-serialization-protocol.md) - - [Dubbo 负载均衡策略和集群容错策略?](/docs/distributed-system/dubbo-load-balancing.md) - - [Dubbo 的 SPI 思想是什么?](/docs/distributed-system/dubbo-spi.md) - - [如何基于 Dubbo 进行服务治理?](/docs/distributed-system/dubbo-service-management.md) - - [分布式服务接口的幂等性如何设计?](/docs/distributed-system/distributed-system-idempotency.md) - - [分布式服务接口请求的顺序性如何保证?](/docs/distributed-system/distributed-system-request-sequence.md) - - [如何自己设计一个类似 Dubbo 的 RPC 框架?](/docs/distributed-system/dubbo-rpc-design.md) - - [CAP 定理的 P 是什么?](/docs/distributed-system/distributed-system-cap.md) + - [说一下 Dubbo 的工作原理?](/docs/distributed-system/dubbo-operating-principle.md) + - [Dubbo 支持哪些序列化协议?](/docs/distributed-system/dubbo-serialization-protocol.md) + - [Dubbo 负载均衡策略和集群容错策略?](/docs/distributed-system/dubbo-load-balancing.md) + - [Dubbo 的 SPI 思想是什么?](/docs/distributed-system/dubbo-spi.md) + - [如何基于 Dubbo 进行服务治理?](/docs/distributed-system/dubbo-service-management.md) + - [分布式服务接口的幂等性如何设计?](/docs/distributed-system/distributed-system-idempotency.md) + - [分布式服务接口请求的顺序性如何保证?](/docs/distributed-system/distributed-system-request-sequence.md) + - [如何自己设计一个类似 Dubbo 的 RPC 框架?](/docs/distributed-system/dubbo-rpc-design.md) + - [CAP 定理的 P 是什么?](/docs/distributed-system/distributed-system-cap.md) - - 分布式锁 + - 分布式锁 - - [Zookeeper 都有哪些应用场景?](/docs/distributed-system/zookeeper-application-scenarios.md) - - [分布式锁如何设计?](/docs/distributed-system/distributed-lock-redis-vs-zookeeper.md) + - [Zookeeper 都有哪些应用场景?](/docs/distributed-system/zookeeper-application-scenarios.md) + - [分布式锁如何设计?](/docs/distributed-system/distributed-lock-redis-vs-zookeeper.md) - - 分布式事务 + - 分布式事务 - - [分布式事务了解吗?](/docs/distributed-system/distributed-transaction.md) + - [分布式事务了解吗?](/docs/distributed-system/distributed-transaction.md) - - 分布式会话 - - [集群分布式 Session 如何实现?](/docs/distributed-system/distributed-session.md) + - 分布式会话 + - [集群分布式 Session 如何实现?](/docs/distributed-system/distributed-session.md) -* 高可用架构 +* 高可用架构 - - 基于 Hystrix 实现高可用 + - 基于 Hystrix 实现高可用 - - [Hystrix 介绍](/docs/high-availability/hystrix-introduction.md) - - [电商网站详情页系统架构](/docs/high-availability/e-commerce-website-detail-page-architecture.md) - - [Hystrix 线程池技术实现资源隔离](/docs/high-availability/hystrix-thread-pool-isolation.md) - - [Hystrix 信号量机制实现资源隔离](/docs/high-availability/hystrix-semphore-isolation.md) - - [Hystrix 隔离策略细粒度控制](/docs/high-availability/hystrix-execution-isolation.md) - - [深入 Hystrix 执行时内部原理](/docs/high-availability/hystrix-process.md) - - [基于 request cache 请求缓存技术优化批量商品数据查询接口](/docs/high-availability/hystrix-request-cache.md) - - [基于本地缓存的 fallback 降级机制](/docs/high-availability/hystrix-fallback.md) - - [深入 Hystrix 断路器执行原理](/docs/high-availability/hystrix-circuit-breaker.md) - - [深入 Hystrix 线程池隔离与接口限流](/docs/high-availability/hystrix-thread-pool-current-limiting.md) - - [基于 timeout 机制为服务接口调用超时提供安全保护](/docs/high-availability/hystrix-timeout.md) + - [Hystrix 介绍](/docs/high-availability/hystrix-introduction.md) + - [电商网站详情页系统架构](/docs/high-availability/e-commerce-website-detail-page-architecture.md) + - [Hystrix 线程池技术实现资源隔离](/docs/high-availability/hystrix-thread-pool-isolation.md) + - [Hystrix 信号量机制实现资源隔离](/docs/high-availability/hystrix-semphore-isolation.md) + - [Hystrix 隔离策略细粒度控制](/docs/high-availability/hystrix-execution-isolation.md) + - [深入 Hystrix 执行时内部原理](/docs/high-availability/hystrix-process.md) + - [基于 request cache 请求缓存技术优化批量商品数据查询接口](/docs/high-availability/hystrix-request-cache.md) + - [基于本地缓存的 fallback 降级机制](/docs/high-availability/hystrix-fallback.md) + - [深入 Hystrix 断路器执行原理](/docs/high-availability/hystrix-circuit-breaker.md) + - [深入 Hystrix 线程池隔离与接口限流](/docs/high-availability/hystrix-thread-pool-current-limiting.md) + - [基于 timeout 机制为服务接口调用超时提供安全保护](/docs/high-availability/hystrix-timeout.md) - - 高可用系统 + - 高可用系统 - - 如何设计一个高可用系统? + - 如何设计一个高可用系统? - - 限流 + - 限流 - - [如何限流?说一下具体的实现?](/docs/high-concurrency/how-to-limit-current.md) + - [如何限流?说一下具体的实现?](/docs/high-concurrency/how-to-limit-current.md) - - 熔断 - - - 如何进行熔断? - - 熔断框架都有哪些?具体实现原理知道吗? - - [熔断框架,选用 Sentinel 还是 Hystrix?](/docs/high-availability/sentinel-vs-hystrix.md) + - 熔断 + + - 如何进行熔断? + - 熔断框架都有哪些?具体实现原理知道吗? + - [熔断框架,选用 Sentinel 还是 Hystrix?](/docs/high-availability/sentinel-vs-hystrix.md) - - 降级 - - 如何进行降级? + - 降级 + - 如何进行降级? -* 微服务架构 +* 微服务架构 - - 微服务的一些概念 + - 微服务的一些概念 - - [关于微服务架构的描述](/docs/micro-services/microservices-introduction.md) - - [从单体式架构迁移到微服务架构](/docs/micro-services/migrating-from-a-monolithic-architecture-to-a-microservices-architecture.md) - - [微服务的事件驱动数据管理](/docs/micro-services/event-driven-data-management-for-microservices.md) - - [选择微服务部署策略](/docs/micro-services/choose-microservice-deployment-strategy.md) - - - Spring Cloud 微服务架构 - - [什么是微服务?微服务之间是如何独立通讯的?](/docs/micro-services/what's-microservice-how-to-communicate.md) - - Spring Cloud 和 Dubbo 有哪些区别? - - Spring Boot 和 Spring Cloud,谈谈你对它们的理解? - - 什么是服务熔断?什么是服务降级? - - 微服务的优缺点分别是什么?说一下你在项目开发中碰到的坑? - - [你所知道的微服务技术栈都有哪些?](/docs/micro-services/micro-services-technology-stack.md) - - [微服务治理策略](/docs/micro-services/micro-service-governance.md) - - Eureka 和 Zookeeper 都可以提供服务注册与发现的功能,它们有什么区别? - - [谈谈服务发现组件 Eureka 的主要调用过程?](/docs/micro-services/how-eureka-enable-service-discovery-and-service-registration.md) + - [关于微服务架构的描述](/docs/micro-services/microservices-introduction.md) + - [从单体式架构迁移到微服务架构](/docs/micro-services/migrating-from-a-monolithic-architecture-to-a-microservices-architecture.md) + - [微服务的事件驱动数据管理](/docs/micro-services/event-driven-data-management-for-microservices.md) + - [选择微服务部署策略](/docs/micro-services/choose-microservice-deployment-strategy.md) + + - Spring Cloud 微服务架构 + - [什么是微服务?微服务之间是如何独立通讯的?](/docs/micro-services/what's-microservice-how-to-communicate.md) + - Spring Cloud 和 Dubbo 有哪些区别? + - Spring Boot 和 Spring Cloud,谈谈你对它们的理解? + - 什么是服务熔断?什么是服务降级? + - 微服务的优缺点分别是什么?说一下你在项目开发中碰到的坑? + - [你所知道的微服务技术栈都有哪些?](/docs/micro-services/micro-services-technology-stack.md) + - [微服务治理策略](/docs/micro-services/micro-service-governance.md) + - Eureka 和 Zookeeper 都可以提供服务注册与发现的功能,它们有什么区别? + - [谈谈服务发现组件 Eureka 的主要调用过程?](/docs/micro-services/how-eureka-enable-service-discovery-and-service-registration.md) -* 海量数据处理 - - 10 道经典的海量数据处理面试题 - - [如何从大量的 URL 中找出相同的 URL?](/docs/big-data/find-common-urls.md) - - [如何从大量数据中找出高频词?](/docs/big-data/find-top-100-words.md) - - [如何找出某一天访问百度网站最多的 IP?](/docs/big-data/find-top-1-ip.md) - - [如何在大量的数据中找出不重复的整数?](/docs/big-data/find-no-repeat-number.md) - - [如何在大量的数据中判断一个数是否存在?](/docs/big-data/find-a-number-if-exists.md) - - [如何查询最热门的查询串?](/docs/big-data/find-hotest-query-string.md) - - [如何统计不同电话号码的个数?](/docs/big-data/count-different-phone-numbers.md) - - [如何从 5 亿个数中找出中位数?](/docs/big-data/find-mid-value-in-500-millions.md) - - [如何按照 query 的频度排序?](/docs/big-data/sort-the-query-strings-by-counts.md) - - [如何找出排名前 500 的数?](/docs/big-data/find-rank-top-500-numbers.md) +* 海量数据处理 + - 10 道经典的海量数据处理面试题 + - [如何从大量的 URL 中找出相同的 URL?](/docs/big-data/find-common-urls.md) + - [如何从大量数据中找出高频词?](/docs/big-data/find-top-100-words.md) + - [如何找出某一天访问百度网站最多的 IP?](/docs/big-data/find-top-1-ip.md) + - [如何在大量的数据中找出不重复的整数?](/docs/big-data/find-no-repeat-number.md) + - [如何在大量的数据中判断一个数是否存在?](/docs/big-data/find-a-number-if-exists.md) + - [如何查询最热门的查询串?](/docs/big-data/find-hotest-query-string.md) + - [如何统计不同电话号码的个数?](/docs/big-data/count-different-phone-numbers.md) + - [如何从 5 亿个数中找出中位数?](/docs/big-data/find-mid-value-in-500-millions.md) + - [如何按照 query 的频度排序?](/docs/big-data/sort-the-query-strings-by-counts.md) + - [如何找出排名前 500 的数?](/docs/big-data/find-rank-top-500-numbers.md)