分布式(一) 搞定服务注册与发现
背景
最近在做分布式相关的工作,由于人手不够只能我一个人来怼;看着这段时间的加班表想想就是够惨的。
不过其中也有遇到的不少有意思的事情今后再拿来分享,今天重点来讨论服务的注册与发现。
分布式带来的问题
我的业务比较简单,只是需要知道现在有哪些服务实例可供使用就可以了(并不是做远程调用,只需要拿到信息即可)。
要实现这一功能最简单的方式可以在应用中配置所有的服务节点,这样每次在使用时只需要通过某种算法从配置列表中选择一个就可以了。
但这样会有一个非常严重的问题:
由于应用需要根据应用负载情况来灵活的调整服务节点的数量,这样我的配置就不能写死。
不然就会出现要么新增的节点没有访问或者是已经 down 掉的节点却有请求,这样肯定是不行的。
往往要解决这类分布式问题都需要一个公共的区域来保存这些信息,比如是否可以利用 Redis?
每个节点启动之后都向 Redis 注册信息,关闭时也删除数据。
其实就是存放节点的 ip + port
,然后在需要知道服务节点信息时候只需要去 Redis 中获取即可。
什么样的简历不会被丢进回收站
GitHub 1W star 成就达成!
如何成为一位「不那么差」的程序员
Netty(三) 什么是 TCP 拆、粘包?如何解决?
如何优雅的使用和理解线程池
前言
平时接触过多线程开发的童鞋应该都或多或少了解过线程池,之前发布的《阿里巴巴 Java 手册》里也有一条:
可见线程池的重要性。
简单来说使用线程池有以下几个目的:
- 线程是稀缺资源,不能频繁的创建。
- 解耦作用;线程的创建于执行完全分开,方便维护。
- 应当将其放入一个池子中,可以给其他任务进行复用。
线程池原理
谈到线程池就会想到池化技术,其中最核心的思想就是把宝贵的资源放到一个池子中;每次使用都从里面获取,用完之后又放回池子供其他人使用,有点吃大锅饭的意思。
那在 Java 中又是如何实现的呢?
在 JDK 1.5 之后推出了相关的 api,常见的创建线程池方式有以下几种:
Executors.newCachedThreadPool()
:无限线程池。Executors.newFixedThreadPool(nThreads)
:创建固定大小的线程池。Executors.newSingleThreadExecutor()
:创建单个线程的线程池。
HashMap? ConcurrentHashMap? 相信看完这篇没人能难住你!
Guava 源码分析(Cache 原理【二阶段】)
前言
在上文「Guava 源码分析(Cache 原理)」中分析了 Guava Cache
的相关原理。
文末提到了回收机制、移除时间通知等内容,许多朋友也挺感兴趣,这次就这两个内容再来分析分析。
在开始之前先补习下 Java 自带的两个特性,Guava 中都有具体的应用。
Java 中的引用
首先是 Java 中的引用。
在之前分享过 JVM 是根据可达性分析算法找出需要回收的对象,判断对象的存活状态都和引用
有关。
在 JDK1.2 之前这点设计的非常简单:一个对象的状态只有引用和没被引用两种区别。
一次线上问题排查所引发的思考
前言
之前或多或少分享过一些内存模型、对象创建之类的内容,其实大部分人看完都是懵懵懂懂,也不知道这些的实际意义。
直到有一天你会碰到线上奇奇怪怪的问题,如:
- 线程执行一个任务迟迟没有返回,应用假死。
- 接口响应缓慢,甚至请求超时。
- CPU 高负载运行。
这类问题并不像一个空指针、数组越界这样明显好查,这时就需要刚才提到的内存模型、对象创建、线程等相关知识结合在一起来排查问题了。
正好这次借助之前的一次生产问题来聊聊如何排查和解决问题。
生产现象
首先看看问题的背景吧:
我这其实是一个定时任务,在固定的时间会开启 N 个线程并发的从 Redis 中获取数据进行运算。
业务逻辑非常简单,但应用一般涉及到多线程之后再简单的事情都要小心对待。
果不其然这次就出问题了。
现象:原本只需要执行几分钟的任务执行了几个小时都没退出。翻遍了所有的日志都没找到异常。
于是便开始定位问题之路。