0xCAFEBABE

Just for fun


  • 首页

  • 分类

  • 标签

  • 归档

  • 关于

  • 搜索

服务发现比较:Eureka vs Consul vs ZooKeeper

发表于 2019-02-04 | 分类于 Microservice | | 阅读次数:
字数统计: 1,645 字

总结

Eureka Consul ZooKeeper
CAP AP CP CP
一致性算法 / Raft ZAB
服务健康检查 需配置 服务状态、内存、硬盘 长连接,KeepAlive
K-V 存储 / 支持 支持
自身监控 Metrics Metrics /
开发语言 Java Go Java

Consul

Consul 为服务发现、健康检查、K-V存储提供了一套开箱即用的解决方案。

Consul 官网中介绍了 Consul 的以下几个核心功能:

  • 服务发现(Service Discovery):提供 HTTP 与DNS 两种方式。
  • 健康检查(Health Checking):提供多种健康检查方式,比如 HTTP 状态码、内存使用情况、硬盘等等。
  • 键值存储(KV Store):可以作为服务配置中心使用,类似 Spring Cloud Config。
  • 加密服务通信(Secure Service Communication)
  • 多数据中心(Multi Datacenter):Consul 通过 WAN 的 Gossip 协议,完成跨数据中心的同步。

“In CAP terms, Consul uses a CP architecture, favoring consistency over availability. “
Consul 官网中明确指出 Consul 是 CP 的。

阅读全文 »

分布式Session一致性问题与JWT的强制失效方案

发表于 2019-01-30 | | 阅读次数:
字数统计: 461 字

Session一致性解决方案

利用 Cookie 记录 Session

将session存储到浏览器cookie中。

缺点:

  • 极其容易被窃取,不安全
  • 受Cookie的大小限制

Session 复制

多台服务器间相互同步 session,这样每台服务器都包含全部的session。

优点:

  • 任何一台服务器宕机都不会丢失session

缺点:

  • session同步需要数据传输,有延迟
  • 浪费内存

Session 绑定

对客户端 IP地址做 hash(如 nginx 的 ip_hash),将 Session 与某一服务器绑定,保证该客户端的每次请求都落在同一服务器上。

优点:

  • 负载均衡,只要hash够平均
  • 不需要修改服务器代码,只需要修改nginx配置

缺点:

  • 某个服务器宕机后,对应的session就会丢失
  • 水平扩展服务器后,session会被rehash,客户端可能拿不到正确的session
阅读全文 »

从源码中浅析Java反射原理

发表于 2019-01-11 | 分类于 Java | | 阅读次数:
字数统计: 2,791 字

何为反射

Oracle 的官方文档中是这么解释反射的:

“Reflection enables Java code to discover information about the fields, methods and constructors of loaded classes, and to use reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions. The API accommodates applications that need access to either the public members of a target object (based on its runtime class) or the members declared by a given class. It also allows programs to suppress default reflective access control.”

具体而言,反射 (Reflection) 提供了一种在程序运行时动态获取 Class 方法、属性、接口等内部信息的机制。通过反射可以让在程序运行期实例化对象、调用方法、获取属性,即使方法或属性是 private 的也可以通过反射机制调用。

反射原理

篇幅和精力有限,只看了获取 Class 、获取与调用 Method 和获取 Field 的源码。

反射获取 Class 原理(Class.forName()方法)

1
2
3
4
5
6
7
8
9
10
11
12
13
@CallerSensitive
public static Class<?> forName(String className) throws ClassNotFoundException {
// 通过反射获取调用forName()方法的类caller
Class<?> caller = Reflection.getCallerClass();
// 根据caller获取当前的classLoader,继续调用forName0()方法
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

// forName0()是一个native方法,可以获取指定的class信息
private static native Class<?> forName0(String name, boolean initialize,
ClassLoader loader,
Class<?> caller)
throws ClassNotFoundException;
阅读全文 »

《Spring实战》阅读笔记

发表于 2019-01-09 | 分类于 读书笔记 | | 阅读次数:
字数统计: 2,282 字

简化 Java 开发

为了降低 Java 开发的复杂性, Spring 采取了以下 4 种关键策略:

  • 基于POJO (Plain Old Java object) 的轻量级和最小侵入性编程
  • 通过依赖注入和面向接口实现松耦合
  • 基于切面和惯例进行声明式编程
  • 通过切面和模板减少样板式代码

依赖注入 (DI)

传统做法下,每个对象负责管理与自己所依赖的对象的引用,这样会导致高耦合。

通过依赖注入,对象的依赖关系将由一个第三方组件在创建对象时进行自动注入,对象无需管理它们的依赖关系。
依赖注入

依赖注入的实现方式:

  • 构造器注入:在构造方法中将依赖对象作为参数传入
  • XML
  • 注解

Spring 通过 Application Context 装载 bean 的定义并负责对象的创建与组装。

面向切面编程 (AOP)

AOP 允许将遍布应用各处的重复功能,分离出来形成可重用的组件。

Spring 提供了 4 种类型的 AOP 支持:

  • 基于代理的经典 Spring AOP
  • 纯 POJO切 面
  • @AspectJ 注解驱动的切面
  • 注入式 AspectJ 切面(适用于 Spring 各版本)
阅读全文 »

Redis知识点总结

发表于 2018-12-25 | 分类于 Redis | | 阅读次数:
字数统计: 2,361 字

Redis(Remote Dictionary Server)的特点

  • 纯内存操作
  • 采用单线程,避免了不必要的上下文切换和竞争条件,不用考虑各种锁的问题
  • 使用多路 I/O 复用模型,非阻塞型IO
  • 高效优化的数据结构(如 SDS,Zset 中的跳表等等)

Redis Object

Redis 中的每个键值对的键和值都由redisObject结构体表示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
typedef struct redisObject {
unsigned type:4; // 对象的类型
unsigned encoding:4; // 为了节省空间,同个type的数据可以采用不同的编码方式,如Zset中的同时使用了ziplist和skipset
unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */
int refcount; // 引用计数
void *ptr;
} robj;

/* type类型如下 */
/* The actual Redis Object */
#define OBJ_STRING 0
#define OBJ_LIST 1
#define OBJ_SET 2
#define OBJ_ZSET 3
#define OBJ_HASH 4

/* encoding类型如下 */
/* Objects encoding. Some kind of objects like Strings and Hashes can be
* internally represented in multiple ways. The 'encoding' field of the object
* is set to one of this fields for this object.
*/
#define OBJ_ENCODING_RAW /* Raw representation */ 简单动态字符串
#define OBJ_ENCODING_INT /* Encoded as integer */ 整数
#define OBJ_ENCODING_HT /* Encoded as hash table */ 字典
#define OBJ_ENCODING_ZIPLIST /* Encoded as ziplist */ 压缩列表
#define OBJ_ENCODING_INTSET /* Encoded as intset */ 整数集合
#define OBJ_ENCODING_SKIPLIST /* Encoded as skiplist */ 跳跃表
#define OBJ_ENCODING_EMBSTR /* Embedded sds string encoding */ embstr编码的简单动态字符串
#define OBJ_ENCODING_QUICKLIST /* Encoded as linked list of ziplists */
阅读全文 »

Java8 HashMap源码阅读

发表于 2018-12-17 | 分类于 Java | | 阅读次数:
字数统计: 16,555 字

概述

1
2
public class HashMap<K,V> extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable

HashMap 是一个使用数组与链表(红黑树)实现的键值对集合,继承自抽象类 AbstractMap,实现了 Map 、Cloneable、Serializable 接口。

HashMap 是非线程安全的,key 与 value 允许 null 值(key的 null 只允许有一个,value无限制),遍历顺序和插入顺序不保证不一致。

hashmap

几个重要参数

  • DEFAULT_INITIAL_CAPACITY:默认容量,为 2 的 4 次方(16)
  • loadFacotr:负载因子,默认为 0.75,如果实际 entry 数量超过了 capacity与loadFacotr 的乘积,将会进行resize
  • MAXIMUM_CAPACITY:最大容量,默认为 2 的 30 次方
  • TREEIFY_THRESHOLD:树化阈值,默认为 8,当 Bins内 的 Node 超过该数值,会将链表转成红黑树
  • UNTREEIFY_THRESHOLD:链表化阈值,默认为 6,当 Bins 内的 Node 小于该数值,会将红黑树转成链表转成
  • MIN_TREEIFY_CAPACITY:链表转树的最小容量,,默认为 64,只有容量超过该值才能进行树化。这个值至少是 4 * TREEIFY_THRESHOLD, treeifyBin() 方法中会先判断容量,如果小于 64 会直接 reszie 而不是 树化。
阅读全文 »

《Spring微服务实战》阅读笔记

发表于 2018-12-13 | 分类于 读书笔记 | | 阅读次数:
字数统计: 6,683 字

总结

Eureka:服务注册与发现
Ribbon:客户端负载均衡
Hystrix:服务降级、熔断
Feign:集成Ribbon的Spring RestTemplate替代方案
Zuul:服务网关
Config:集中式配置服务
Stream:消息驱动
Sleuth:服务跟踪
Zipkin:服务监控

服务治理 Spring Cloud Eureka

服务注册

  • 服务注册:在服务治理框架中,通常会构建一个服务注册中心,每个服务单元向注册中心登记自己提供的服务并告知主机、端口号、版本号、通信协议等附加信息。

  • 服务发现:服务调用方调用服务时,需要先向服务注册中心咨询服务,并获取所有服务的实例清单。实际的框架为了性能等因素,不会采用每次都向服务注册中心获取服务的方式。

Eureka 服务端就是服务注册中心,用于提供服务的注册与发现;Eureka 客户端则是服务提供者与服务消费者。

服务调用方每次调用服务时都向服务注册中心请求获取所有实例明显是一个不可取的策略,可以考虑引入缓存实现客户端的负载均衡。这样,服务调用方将定期与服务注册中心进行联系并刷新服务实例的缓存,当拿到不健康的实例时,再去向服务中注册重新获取实例。

客户端负载均衡

阅读全文 »

记一次随机验证码生成的优化过程

发表于 2018-12-10 | 分类于 Java | | 阅读次数:
字数统计: 1,304 字

总结

拼接字符串最好不要直接用 “+” ,因为编译器遇到 “+” 的时候,会 new 一个 StringBuilder 出来,接着调用 append 方法进行追加,再调用 toString 方法,生成新字符串。在每次循环中,都会创建一个 StringBuilder 对象,且都会调用一次 toString 方法,可见用 “+” 拼接字符串的成本是十分高的。

PS:执行一次字符串 “str += a”,相当于 “str = new StringBuilder(str).append(“a”).toString()”

String、StringBuilder、StringBuffer 的区别

String 为字符串常量,而 StringBuilder 和 StringBuffer 均为字符串变量,即 String 对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。

运行效率:StringBuilder > StringBuffer > String

StringBuffer 和 StringBuilder 都继承自 AbstractStringBuilder,原理一样,就是在底层维护了一个 char 数组,唯一的区别只是 StringBuffer 是线程安全的,它对所有方法都做了同步,而 StringBuilder 是非线程安全的。

1
2
3
AbstractStringBuilder(int capacity) {
value = new char[capacity];
}

每次 append 的时候就会往 char[ ] 中填入字符,在最终调用 sb.toString( ) 的时候,用一个 new String( ) 方法把 char 数组里面的内容都转成 String,这样,整个过程中只产生了一个 StringBuilder 对象与一个 String 对象,非常节省空间。

StringBuilde r唯一的性能损耗点在于 char[ ] 容量不够的时候需要进行扩容,扩容需要进行数组拷贝,一定程度上降低了效率。

考虑到扩容的时候有性能上的损耗,尽量在初始化时预估长度并传入该长度,可以避免扩容的发生。

阅读全文 »

Java8 Object源码阅读

发表于 2018-12-02 | 分类于 Java | | 阅读次数:
字数统计: 3,483 字

概述

Object类是类层次结构的根类,是每个Class的超类,Java中的所有类都默认继承自Object类,可以直接调用Object的成员方法。

方法摘要:

  • clone():创建并返回此对象的一个副本
  • equals(Object obj) :判断两个对象是否相等
  • hashCode():返回该对象的哈希码值
  • getClass():返回该对象的运行时类
  • toString():返回该对象的字符串表示
  • notify():唤醒在此对象monitor上等待的单个线程
  • notifyAll():唤醒在此对象monitor上等待的所有线程
  • wai():在其他线程调用此对象的notify()方法或notifyAll()方法前,导致当前线程等待,这个方法有三个重载
  • finalize():当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法
阅读全文 »

StrongFriends开发笔记

发表于 2018-11-20 | 分类于 Java | | 阅读次数:
字数统计: 4,932 字

前言

StrongFriends,又称壮壮朋友(๑•̀ㅂ•́)و✧,是我开发的一个举铁爱好者论坛。主要功能包括:发帖、评论、赞踩、私信、RM 计算器、维京系数计算器、力量排行榜、帖子 / 评论 / 用户管理。

前端:BootStraps 后端:SpringBoot / Mybatis DB: MySQL / Redis

以下是个人在实现一些重点功能所做的笔记。

Spring 接收参数的几种方式

1. 通过 @RequestParam 获取请求参数

用注解@RequestParam绑定请求参数 param 到变量 testParam,当请求参数 param 不存在时会有异常发生,可以通过设置属性 required=false 解决,例如 @RequestParam(value="a", required=false)。

1
2
3
4
5
6
@RequestMapping(value = "/test", method = RequestMethod.GET, RequestMethod.POST)
@ResponseBody
public String test(@RequestParam("param") String testParam) {
System.out.println("Requst parm is "+testParam);
return "Test";
}

2. 通过 @PathVariable 获取请求参数

1
2
3
4
5
6
@RequestMapping(value = "/test/{parm}", method = RequestMethod.GET, RequestMethod.POST)
@ResponseBody
public String test(@PathVariable("parm") String testParm){
System.out.println("Requst parm is "+testParm);
return "Test";
}
阅读全文 »
12345
Marticles

Marticles

48 日志
15 分类
15 标签
GitHub E-Mail
Creative Commons
© 2018 LJH's Blog | 累计字数 137.1k
载入天数...载入时分秒...
访问量