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

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

扩容

垂直扩容(纵向扩展):提高系统部件能力

水平扩容(横向扩容):增加更多系统成员来实现

缓存

缓存特征

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

一、影响因素

业务场景和业务需求

缓存的设计(粒度和策略)

缓存的容量和基础设施

二、缓存分类和应用场景

本地缓存:编程实现(成员变量,局部变量,静态变量)、Guava Cache

分布式缓存:Memcache、Redis

三、常用组件

Guava Cache public class GuavaCacheExample1 {

public static void main(String[] args) {

LoadingCache cache = CacheBuilder.newBuilder()

.maximumSize(10) // 最多存放10个数据

.expireAfterWrite(10, TimeUnit.SECONDS) // 缓存10秒

.recordStats() // 开启记录状态数据功能

.build(new CacheLoader() {

@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分布式锁实现

监控报警机制

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值