zoukankan      html  css  js  c++  java
  • java并发编程笔记(十一)——高并发处理思路和手段

    java并发编程笔记(十一)——高并发处理思路和手段

    扩容

    • 垂直扩容(纵向扩展):提高系统部件能力
    • 水平扩容(横向扩容):增加更多系统成员来实现

    缓存

    缓存特征

    命中率:命中数/(命中数+没有命中数)

    一、影响因素

    • 业务场景和业务需求
    • 缓存的设计(粒度和策略)
    • 缓存的容量和基础设施

    二、缓存分类和应用场景

    • 本地缓存:编程实现(成员变量,局部变量,静态变量)、Guava Cache
    • 分布式缓存:Memcache、Redis

    三、常用组件

    • Guava Cache

      public class GuavaCacheExample1 {
      
          public static void main(String[] args) {
      
              LoadingCache<String, Integer> cache = CacheBuilder.newBuilder()
                      .maximumSize(10) // 最多存放10个数据
                      .expireAfterWrite(10, TimeUnit.SECONDS) // 缓存10秒
                      .recordStats() // 开启记录状态数据功能
                      .build(new CacheLoader<String, Integer>() {
                          @Override
                          public Integer load(String key) throws Exception {
                              return -1;
                          }
                      });
      
              log.info("{}", cache.getIfPresent("key1")); // null
              cache.put("key1", 1);
              log.info("{}", cache.getIfPresent("key1")); // 1
              cache.invalidate("key1");
              log.info("{}", cache.getIfPresent("key1")); // null
      
              try {
                  log.info("{}", cache.get("key2")); // -1
                  cache.put("key2", 2);
                  log.info("{}", cache.get("key2")); // 2
      
                  log.info("{}", cache.size()); // 1
      
                  for (int i = 3; i < 13; i++) {
                      cache.put("key" + i, i);
                  }
                  log.info("{}", cache.size()); // 10
      
                  log.info("{}", cache.getIfPresent("key2")); // null
      
                  Thread.sleep(11000);
      
                  log.info("{}", cache.get("key5")); // -1
      
                  log.info("{},{}", cache.stats().hitCount(), cache.stats().missCount());
      
                  log.info("{},{}", cache.stats().hitRate(), cache.stats().missRate());
              } catch (Exception e) {
                  log.error("cache exception", e);
              }
          }
      }
      
    • Memcache

    • Redis

    **最大元素(空间):缓存大小 **

    清空策略:FIFO、LFO、LRU、过期时间,随机等

    FIFO: 先进先出策略

    LFO:最少使用策略

    LRU:最近最少使用策略

    高并发场景下缓存常见问题

    缓存一致性

    造成这种问题的场景:

    • 更新数据库成功--更新缓存失败--数据不一致
    • 更新缓存成功--更新数据库失败--数据不一致
    • 更新数据库成功--淘汰缓存失败--数据不一致
    • 淘汰缓存成功--更新数据库失败--查询缓存miss

    缓存并发问题

    同时大量请求访问缓存未命中,然后大量请求同时访问数据库造成数据库压力增大,解决办法是加锁,避免同时执行

    缓存穿透问题

    某个查询结果为空,导致缓存为存储,因此大量请求会去查询数据库,造成对数据库的压力大增

    解决办法:

    1、缓存空对象,缓存时间要短,适合命中率不高,但是需要频繁修改的数据

    2、进行单独过滤处理,对所有可能结果为空的请求进行统一存放,并且对请求进行拦截,避免请求到数据库对数据库造成大量压力

    缓存雪崩现象

    导致原因:缓存并发,缓存穿透等

    解决办法:过期时间设置随机数,避免同时失效10

    消息队列

    特性

    • 业务无关:只做消息分发
    • FIFO:先投递先到达
    • 容灾:节点的动态增加和消息的持久化
    • 性能:吞吐量提升,系统内部通信效率提高

    为什么需要消息队列

    • 【生产和消费】的速度或稳定性等因素不一致

    消息队列的好处

    • 业务解耦
    • 最终一致性
    • 广播
    • 错峰和流控

    举例

    • Kafka
    • RabbitMQ

    应用拆分

    拆分原则

    • 业务优先
    • 循序渐进
    • 兼顾技术:重构、分层
    • 可靠测试

    需要考虑的问题

    • 应用之间的通信:RPC(dubbo等)、消息队列
    • 应用之间数据数据库设计:每个应用都有独立的数据库
    • 避免事务操作跨应用

    通信工具

    • dubbo
    • springCloud

    应用限流

    常用限流算法

    • 计数器法

    • 滑动窗口法

    • 漏桶算法

    • 令牌桶算法(Guava RateLimit)

      @Slf4j
      public class RateLimiterExample1 {
      
          private static RateLimiter rateLimiter = RateLimiter.create(5);
      
          public static void main(String[] args) throws Exception {
      
              for (int index = 0; index < 100; index++) {
                  if (rateLimiter.tryAcquire(190, TimeUnit.MILLISECONDS)) {
                      handle(index);
                  }
              }
          }
      
          private static void handle(int i) {
             log.info("{}", i);
          }
      }
      
      @Slf4j
      public class RateLimiterExample2 {
      
          private static RateLimiter rateLimiter = RateLimiter.create(5);
      
          public static void main(String[] args) throws Exception {
      
              for (int index = 0; index < 100; index++) {
                  rateLimiter.acquire();
                  handle(index);
              }
          }
      
          private static void handle(int i) {
             log.info("{}", i);
          }
      }
      

      Guava RateLimiter是单机版的限流

      如果是分布式可以采用 分布式限流:

      可以采用Redis作为中间组件,使用Redis的incrby key num 方法

    服务降级与服务熔断

    服务降级

    • 自动降级:超时、失败次数、故障、限流
    • 人工降级:秒杀、双11大促

    服务熔断

    总结

    共性:目的、最终表现、粒度、自治

    区别:

    • 触发原因、管理目标层次、实现方式

    服务降级要考虑的问题

    • 核心服务、非核心服务
    • 是否支持降级、降级策略
    • 业务放通场景,策略

    Hystrix

    • 在通过第三方客户端访问(通常是通过网络)依赖服务出现高延迟或者失败时,为系统提供保护和控制。
    • 在分布式系统中防止级联失败
    • 快速失败(fail fast)同时能快速恢复
    • 提供失败回退(Fallback)和优雅的服务降级机制
    • 提供近实时的监控、报警和运维控制手段

    数据库切库、分库、分表

    数据库瓶颈

    • 单个库数据量太大(1T~2T):多个库
    • 单个数据库服务器压力过大、读写瓶颈:多个库
    • 单个表数据量过大:分表

    数据库切库

    • 切库的基础及实际运用:读写分离

    • 自定义注解完成数据库切库-代码实现

    • 支持多数据源、分库

    • 数据库支持多个数据源-代码实现

    数据库分表

    • 什么时候考虑分表
    • 横向(水平)分表和纵向(垂直)分表
    • 数据库分表:mybatis分表插件shardbatis2.0

    高可用的一些手段

    • 任务调度系统分布式:elastic-job+zookeeper
    • 主备切换:apache curator + zookeeper分布式锁实现
    • 监控报警机制
  • 相关阅读:
    对MVC模型的自悟,详尽解释,为了更多非计算机人员可以理解
    openSUSE leap 42.3 实现有线 无线同时用
    Fedora27 源配置
    Ubuntu16.04添加HP Laserjet Pro M128fn打印机和驱动
    openSUSE leap 42.3 添加HP Laserjet Pro M128fn打印机和驱动
    OpenSUSE Leap 42.3下通过Firefox Opera Chromium浏览器直接执行java应用程序(打开java jnlp文件)实现在服务器远程虚拟控制台完成远程管理的方法
    OpenSUSE Leap 42.3 安装java(Oracle jre)
    linux下支持托盘的邮件客户端Sylpheed
    Ubuntu下通过Firefox Opera Chromium浏览器直接执行java应用程序(打开java jnlp文件)实现在服务器远程虚拟控制台完成远程管理的方法
    Firefox 浏览器添加Linux jre插件
  • 原文地址:https://www.cnblogs.com/xujie09/p/11710675.html
Copyright © 2011-2022 走看看