synchronized 和 ReentrantLock 区别

  • 都是可重入锁

  • synchronized 是 JVM 层面的锁,是 java 关键字,Reentrantlock 是 lock 接口的实现,是 API 层面的锁

  • Reentrantlock 显式获得锁,释放锁,synchronized 隐式获取锁,释放锁

  • ReentrantLock 可响应中断,synchronized 是不可以响应中断的,阻塞的线程会一直阻塞

  • synchronized 的实现涉及到锁的升级,是同步阻塞,ReentrantLock 通过利用 CAS 自旋机制保证线程操作的原子性和 volatile 保证数据可见性,非同步阻塞,采用的是乐观并发策略

  • ReentrantLock 可以实现公平锁

  • ReentrantLock 可以通过 Condition 绑定多个条件

  • synchronized 在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象,而 ReentrantLock 需要主动释放锁才能避免死锁

  • ReentrantLock 可以知道有没有成功获取锁,synchronized 不能

  • synchronized 锁的是对象,锁是保存到对象头里面的,根据对象头数据来标识是否有线程获得锁/争抢锁,ReentrantLock 锁的是线程,根据进入的线程和 int 类型的 state 标识锁的获得/争抢

synchronized 保证了那些特性

  • 原子性: 确保线程互斥地访问同步代码

  • 可见性: 保证共享变量的修改对其他线程可见。线程加锁时,将清空工作内存中共享变量的值,从而使用共享变量时需要从主内存中获取最新的值。线程解锁前,必须把共享变量中的值刷新到主内存中。

  • 有序性: 对一个监视器锁的释放操作先行发生于后面对该监视器锁的获取操作(happens-before)

java 对象布局

阅读全文 »

1.dubbo 负载均衡策略

  • 随机模式 RandomLoadBalance:按权重设置随机概率,在一个截面上碰撞的概率较高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重

  • 轮询模式 RoundRobinLoadBlance:按公约后的权重设置轮询比例,但存在响应慢的服务提供者会堆积请求

  • 最少活跃调用 LeastActiveLoadBlance:相同活跃数的随机,活跃数指调用前后计数差,使慢的提供者收到更少请求,因为越慢的提供者的调用前后计数差会越大

  • 一致性 hash 调用 ConsistentHashLoadBalance:相同参数的请求总是发到统一提供者,当某台提供者挂掉时,原本发往该提供者的请求,基于虚拟节点,平摊到其他提供者,不会引起剧烈变动

2.dubbo 集群容错

  • Failover cluster:失败重试,当服务消费者调用服务提供者失败后自动切换到其他服务提供者进行重试,通常用于读操作或者具有幂等的写操作,需要注意的是重试会带来更长延迟.可通过 retries=2 来设置重试次数(不含第一次)

  • Failfast cluster:快速失败,当服务消费方调用服务提供者失败后,立即报错,也就是只调用一次,通常这种模式用于非幂等性的写操作

  • Failsafe cluster:失败安全,当服务消费者调用服务提供者出现异常时,直接忽略异常.这种模式通常用于写入审计日志等操作

  • Failback cluster:失败自动恢复.当服务消费者调用服务提供者出现异常之后,在后台记录失败的请求,并按照一定的策略后期再进行重试,这种模式通常用于消息通知操作

  • Forking cluster:并行调用.当消费者调用一个接口方法后,dubboclient 会并行调用多个提供者提供的服务,只要一个成功返回,这种模式通常用于实时性要求较高的读操作,但需要浪费更多服务资源,可通过 forks=2 来设置最大并行数

  • Broadcast cluster:广播调用.当消费者调用一个接口方法后,dubboclient 会逐个调用所有服务提供者,任意一台调用异常则这次调用就标志失败,这种模式通常用于通知所有提供者更新缓存或日志等本地资源信息.

3.dubbo 支持的协议

阅读全文 »

redis 数据丢失

Redis 哨兵,当主节点发生故障时,需要进行主备切换,可能会导致数据丢失

异步复制数据导致的数据丢失

主节点异步同步数据给备用节点的过程中,主节点宕机了,导致有部分数据未同步到备用节点。而这个从节点又被选举为主节点,这时候就会有部分数据丢失

脑裂导致的数据丢失

阅读全文 »

某天凌晨接到售后的电话,说线上设备出现了批量离线的问题,下意识以为是之前 Netty 相关服务代码导致的问题又复现了,但是排查了一下发现并不是这个原因
现在把这个问题记录下来,虽然至今还没有找到具体原因但是已经大致缩小了范围

  1. 各个服务平台报出无法与 mq 建立连接的错误

  2. 查询 mq 服务进程发现进程 pid 还在但是端口号却没了

  3. 因为急着解决问题,于是联系运维重启了 mq 服务(这里不应该,其实应该先查一下 mq 进程的状态,这里直接重启导致后面无法细致排查)

  4. 事后分析 mq 日志及源码,发现在出现问题之前的一些迹象:

    • 凌晨 00:10,mq 集群 Master 主机发生了不明原因的网络波动,导致 master 与 zookeeper 的连接超时,断开连接

    • 断开连接之后 mq master 自动降级为 slave

    • mq master 在降级为 slave 的过程中先要将自己的 master 服务和 broker 服务停止,然后以 slave 角色重新启动

    • 在 mq 重启的过程中又恢复了与 zookeeper 的连接

    • 在 mq 停止 master 服务过程中没有停止成功,处于挂起状态

    • 由于 mq master 服务 hang 在挂起状态,导致 mq 集群没有完成角色切换,这个状态就是 master 死了一半,但是其他 slave 依旧还是 slave

    • 整个 mq 集群没有办法对外服务,消费者无法消费,导致 mq 消息堆积,导致设备显示离线

  5. 以上就是目前分析出的整个状况,因为没有保留事故现场并且因为急着恢复服务导致没有排查出真正的原因,是什么原因导致的 master 与 zookeeper 连接断开,以及为什么 master 服务会没有完成重启动作

本篇不写参与试用方法,只记录启动实例之后做的一系列操作,只要是 ubuntu-18.04 版本的系统都可以参考此操作流程

更新 apt

1
apt-get update

安装 shadowsocks-libev

因为服务器在东京,正好手头没有合适的梯子,不利用起来就是浪费

阅读全文 »

事故描述

公司的硬件设备和设备网关服务是以 TCP 长连接方式通讯的,网关服务用到了 Netty

前段时间突然线上一批新的设备集体离线, 查看设备网关发现网关进程的 netstat 存在大量的 CLOSE_WAIT 状态连接

第一时间重启了设备网关,很快设备正常上线了,观察一段时间之后发现又开始陆续出现 CLOSE_WAIT 状态的连接

分析原因

阅读全文 »

最近在开发中使用了 RedisTemplate 来操作 redis 缓存,SpringBoot 集合 RedisTemplate 感觉用起来也不错,同时在开发过程中也遇到了一些问题,在这里记录一下整个过程

配置

  • 创建 SrpingBoot 项目或者模块工程,引入依赖
1
2
3
4
5
6
7
8
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
</dependency>
  • 添加 redis 配置参数
阅读全文 »