零散知识捡拾(一)
Redis
线程模型:
- 套接字:套接字操作抽象成文件事件
- I/O多路复用:监听多个套接字,把文件事件放入队列
- 文件事件分派:接收并传给相应的事件处理器
- 事件处理器:处理事件
Redis为什么快:
- 绝大部分请求是纯粹的内存操作(非常快速)
- 采用单线程,避免了不必要的上下文切换和竞争条件
- 非阻塞IO
并发问题:思路可参考《6.14-Redis分布式锁》
序列化用哪种方式:
- Json:适用于只有存取操作
- Map:对象被缓存期间有对属性的操作
缓存穿透:
- 缓存一个存活时期很短的空结果
与MySQL的数据一致性
- 并发不高读:读Redis,若没有,读DB,写Redis,若有,直接取得
- 并发不高写:写DB成功,写Redis
- 并发高读:读Redis,若没有,读DB,写Redis,若有,直接取得(可以降级成只读Redis)
- 并发高写:异步写,写入Redis缓存,定时同步到MySQL
MQ
- 原理:先进先出的队列,实现消费者和生产者解耦
如何保证消息可靠传输:
- 使用failover,配置备用机
如何处理消息丢失:
- 确认才消费:使用listener回调函数,在有消息到达时,会调用listener接口的onMessage方法。在这种情况下,在onMessage方法执行完毕后,消息才会被确认,此时只要在方法中抛出异常,该消息就不会被确认
- 过期的、多次处理失败的消息将会被ActiveMQ置入“ActiveMQ.DLQ”这个队列中
配置:
- randomize=false不使用负载均衡
- jms.prefetchPolicy.all=1消费者每次最多取一条信息
- initialReconnectDelay=500重连等待
- maxReconnectAttempts=60最大重连尝试数
- priorityBackup=true主机恢复后使用主机
并发
- AQS实现原理
- segement锁如何实现:
- Segment类继承于ReentrantLock类
- 每个Segment对象包含一个volatile的计数器
- Segment中volatile的HashEntry
数组table负责整个ConcurrentHashMap包含桶总数的一部分(默认为1/16)
MySQL
- 主从同步延迟:
- 原理:主库对所有DDL和 DML产生顺序的binlog,从库用Slave_IO_Running到从库取日志,用单线程Slave_SQL_Running执行
- 原因:主库TPS并发较高,DDL数量超过从库一个线程所能承受的范围;产生锁等待
- 解决方案:从库硬件升级;降低从库安全设置,关闭binlog等
MyBatis
原理:
- XML文件加载到内存中会生成一个对应的MappedStatement对象,以Key-Value形式存储在Configuration的Map中
- 创建SqlSession开启数据库访问
- 传递SQL语句的StatementId和参数
- 根据StatementId找到MappedStatement(包含SQLSource和ResultMap)
- Exector执行,完成SQL语句动态解析,生成BoundSQL,提供给StatementHandler
- 创建JDBC的Statement,传递给StatementHandler
- StatementHandler填充参数,执行并返回List
与数据库交互方式:
- Mybatis提供的API:创建一个和数据库打交道的SqlSession对象,根据StatementId和参数来操作数据库
- Mapper接口:通过SqlSession.getMapper(XXXMapper.class)方法,MyBatis 会根据相应的接口声明的方法信息,通过动态代理实现生成Mapper实例,底层仍然通过API调用
