0%

前言

定时任务,在很多业务场景中都会存在.一般,我们简单解决的话,就是使用数据库来存储数据供服务端周期获取执行.显然,对于数据库处理,如果多线程或者多机器处理,就会存在扩展的问题.比如:现在一个任务记录到时间了需要执行,同时被多个executor抓取来执行,就会浪费不必要的资源;并且,这种场景还非常常见. 因此, 需要额外状态处理,或者其他分库分表策略保证尽量一个executor来操作一个记录,并且如果executor失败了,其他的executor才会去执行分配给失败executor的任务. 整个设计相对而言,就相当复杂了.

基于上面的一些原因,这里我们设计了一个简单的基于kafka消息队列的定时任务方案.

这里,首先定义一下定时消息。所谓定时消息,就是业务方根据自己的业务需求,指定在接下来的大概某个时间点来发送某条消息,从而保证该消息在某个时间点之后可接受的时间区间内消费该消息。所以这里需要指出:

Note:
消息机制都是异步的,所以如果存在大量消息累积未消费,则无法保证定时消息指定的时间区间。因此,使用的时候,必须预计定时消息服务提供的服务能否满足业务的QPS要求。定时消息服务设计保证支持水平扩展,因此,可以根据业务性能需求,部署足够的服务。

kafka消息队列,所有触发都是基于消息机制的。所以,定时任务的设计必须要有定时消息服务来提供基础核心功能。首先,就需要设计一个基于kafka队列的定时消息服务。

阅读全文 »

前言

该文档是提供给期望使用 Zookeeper协作服务功能的开发者创建分布式应用的。文档内部包含了一些概念上和实践应用上的资料信息。

在指南的前四节主要讨论了 Zookeeper 各方面的概念。这些东西对于理解 Zookeeper如何工作以及如何去使用 Zookeeper 是非常必要的。它虽然没有包含源代码,但是它是假设读者对于分布式计算相关的问题是很熟悉的。它们主要如下介绍:

后面四节主要提供了一些实践编程相关的资料。主要是:

文档最后的附录部分包含了一些有用的,Zookeeper 相关的链接。

虽然,该指南中的很多资料在其他一些独立的文章博客中都已经存在了,但是对于开始第一个 Zookeeper 应用的你来说,还是最后阅读完Zookeeper 数据模型Zookeeper 操作指南

Zookeeper 数据模型

Zookeeper 有一个分级的命名空间,类似于一个分布式的文件系统。唯一不同的是命名空间中每个节点可以有对应的数据关联它,就像孩子一样。这一点类似于文件系统中允许一个文件也可以成为目录一样。到节点的路径常常表示成正则的,绝对的,斜线分隔的路径;它们没有相对的引用。在路径上使用的任何编码需要满足以下限制:

  • null字符不可以成为路径名字的一部分。
  • 由于显示的问题,如下字符不能使用:\u0001-\u001F\u007F-\u009F.
  • 下面字符同样不被允许:\ud800-\u0F8FF\uFFF0-\uFFFF.
  • .字符可以作为路径名字中某块名的一部分,但是...不能单独作为路径的一块,因为在 Zookeeper 中不允许相对路径。因此,如下是非法的:/a/b/./c或者/a/b/../c.
  • zookeeper字符串保留。
阅读全文 »

前言

Nginx是一款面向性能设计的HTTP服务器,其性能相对于其他服务器表现优异。内部使用异步的事件处理模型,比如linux平台的epoll事件模型,unix平台的kqueue事件模型等。在Nginx源码的src/event/modules目录下,其对各个平台不同的异步模型进行了二次封装。此外,Nginx在代码实现的时候,会考虑到众多细节优化。比如:根据CPU亲缘性来分配进程和事件,避免CPU级的缓存失效;比如字符串比较时,四字节转换为整数来进行快速指令级比较,等等。

本博文主要目的不是Nginx源码分析,所以,对源码及其独特优秀的代码设计不会去详细介绍。

在最近的一些项目中,涉及到nginx的反向代理配置,然后花了一些时间了解下关于Nginx的整体请求处理流程和返现代理的实现机制。

Nginx虽然代码整洁,模块清晰,但是代码量毕竟还是很多,而且注释实在是太少,所以把一些学习的资料和心得整理一下,以便以后查看。

Nginx 反向代理配置说明

反向代理指以代理服务器来接受Internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给Internet上请求连接到客户端,此时代理服务器对外就表现为一个服务器,而此种工作模式类似于LVS-NET模型。

反向代理也可以理解为web服务器加速,它是一种通过在繁忙的web服务器和外部网络之间增加的 一个高速web缓冲服务器,用来降低实际的web服务器的负载的一种技术。反向代理是针对web服务器提高加速功能,所有外部网络要访问服务器时的所有请求都要通过它,这样反向代理服务器负责接收客户端的请求,然后到源服务器上获取内容,把内容返回给用户,并把内容保存在本地,以便日后再收到同样的信息请求时,它会将本地缓存里的内容直接发给用户,已减少后端web服务器的压力,提高响应速度。因此Nginx还具有缓存功能。

阅读全文 »

前言

如今,在 Java 开发中,日志的打印输出是必不可少的,Slf4j + LogBack 的组合是最通用的方式。

关于 Slf4j 的介绍,请参考本博客http://ketao1989.github.io/posts/Java-slf4j-Introduce.html

有了日志之后,我们就可以追踪各种线上问题。但是,在分布式系统中,各种无关日志穿行其中,导致我们可能无法直接定位整个操作流程。因此,我们可能需要对一个用户的操作流程进行归类标记,比如使用线程+时间戳,或者用户身份标识等;如此,我们可以从大量日志信息中grep出某个用户的操作流程,或者某个时间的流转记录。

因此,这就有了 Slf4j MDC 方法。

Slf4j MDC 介绍

MDC ( Mapped Diagnostic Contexts ),顾名思义,其目的是为了便于我们诊断线上问题而出现的方法工具类。虽然,Slf4j 是用来适配其他的日志具体实现包的,但是针对 MDC功能,目前只有logback 以及 log4j 支持,或者说由于该功能的重要性,slf4j 专门为logback系列包装接口提供外部调用(玩笑~:))。

logback 和 log4j 的作者为同一人,所以这里统称logback系列。

先来看看 MDC 对外提高的接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

public class MDC {
//Put a context value as identified by key
//into the current thread's context map.
public static void put(String key, String val);

//Get the context identified by the key parameter.
public static String get(String key);

//Remove the context identified by the key parameter.
public static void remove(String key);

//Clear all entries in the MDC.
public static void clear();
}

接口定义非常简单,此外,其使用也非常简单。

阅读全文 »

前言

在之前的学习中,基本上都是使用类似于面对过程的方式来写代码,学习各种 Python 的基础知识,接下来,我们需要继续学习面向对象的Python,也就是类对象继承等概念。

对象和属性,这些概念在任务编程语言中,其定义都是一致的。我们通过一个对象来表示一个物体,而这个物体的一些特征,就是对象中的属性。比如,一个人,作为一个对象 Person,则会有姓名,身高,体重,性别,出生日期等属性,这些属性就是这个人的对外特性了。

Python 面向对象编程介绍

类,就是对一类物体进行抽象的表示,比如上面的 Person;而实例,则是具体化了每一个类的属性值,其可以决定某一个物体特征的对象。

在 Python 中,可以如下来定义一个类:

1
2
3
4
5
6
7
8
9

class Person(object):

"""docstring for Person"""

def __init__(self, name):
super(Person, self).__init__()
self.__name = name

阅读全文 »

前言

函数式编程是一种比较抽象的编程范式,其将各种指令计算运行作为数学中函数计算一样,尽量避免状态和变量的概念,因此函数式编程,一大特点就是无副作用,这对于并发编程大行其道的今天,是非常优良的特点.

Python 作为一个动态脚本语言,其很早就支持了函数式编程范式。

Python 函数式编程

Python 函数式编程,涉及太多的内容。简单介绍几个点。

高阶函数

所谓高阶函数,和数学上的高阶函数定义基本一样,就是对函数进行计算处理的函数。其处理对象是另一个函数。

Map 和 Reduce 函数

云计算中,关于 MapReduce 的并行计算框架,在其他很多编程语言中,都会提供 API 方法。即使在Java这种笨重的语言中,也已经提供了相关的方法给开发者使用。

Python 的 map 方法,表示分别对列表中的元素独立处理;Reduce 方法,则表示对map处理完的结果,按照指定的方式进行聚合处理。

阅读全文 »

前言

上一篇博客简单介绍了 Python 基本的概念和操作方法。但是,和其他编程语言一样,是缺少不了函数的。有了函数,代码才会被多次复用,程序才会简洁和易读。

同样,也是为了开发的简洁,Python 还为提供了 Slice切片等高级特性。切片可让我们更方便的操作列表数据结构,也使得代码更易开发和阅读。

Python 函数

Python 函数和数学中函数的概念是一致的,都是对逻辑的一种抽象表示。在 Python 中,我们通过def来定义一个函数方法。

阅读全文 »

前言

2015年春节临近,提前请假回家,闲下来的功夫,系统学习下 python 语言,倒是也好。

Python 在日常工作中,主要是脚本语言的开发,由于开发快捷容易,并且在所有 Linux 版本都会安装 Python 的语言环境,不需要额外的配置工作。

Sublime Python 插件安装

对于 Python 的基础知识的学习,已经工作中脚本语言的开发,使用 Sublime 编辑器可以非常好的满足我们的需求,并且 Sublime 提供了丰富的插件供使用,非常便捷。

开发 Python(Django) 语言,一般推荐安装 :

  • SublimeCodeIntel 插件:一款代码自动提示的插件。

  • Python PEP8 Autoformat 插件:一款针对 Python 的代码格式化插件,快捷键为Ctrl + Shift + R

  • SublimeTmpl 插件:一款自定义文件模板的插件,可以跟进我们的配置在创建文件时,跟进模板完成初始化填充。关于 Python 的代码模板如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Date : ${date}
# @Author : ${author}
# @Version : \$Id\$


import sys
${1:import os}

reload(sys)
sys.setdefaultencoding('utf8')
$0

Notes:打开 preferences --> pachages,在打开的目录下依次找到sublimeTmpl --> templates --> python.tmpl,直接修改就好了。

阅读全文 »

前言

上一篇博客,介绍了关于Jackson 自定义序列化,本文将介绍关于 Jackson 自定义反序列化。

反序列化,Jackson 工具包中已经支持了开发中常用的 Java 类型的解析功能;但是还是会遇到一些我们需要自定义的解析转换工作。比如外部的一些非主流时间格式转换,再比如说对于一些类型转换,做一些额外数据校验和默认容错处理工作,再比如说前端的某种格式的字符串,我们想直接使用自定义反序列化类来完成到 Java Object 的转换工作等等,都需要我们去自己实现 Jackson 反序列化类。

Jackson 自定义序列化相似,Jackson 为自定义的反序列化扩展,也提供了简单易用的接口。

Jackson 自定义反序列化方法

在 Jackson 自定义序列化中提供了两种接口,但是在反序列的时候,只有一个接口使用。不过,和序列化一样,反序列化的扩展也很简单,接口为:org.codehaus.jackson.map.JsonDeserializer,Jackson还提供了一个通用的扩展子类com.fasterxml.jackson.databind.deser.std.StdDeserializer

一般,我们可以直接继承JsonDeserializer抽象类就已经足够满足我们的自定义反序列化需求了。

JsonDeserializer 接口

和序列化很像,这里我们也只需要实现一个反序列化方法deserialize 就足够了。当然,如果你有其他的更高的需求,可以进一步 override 其他的方法。

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51

/**
* Abstract class that defines API used by {@link ObjectMapper} (and
* other chained {@link JsonDeserializer}s too) to deserialize Objects of
* arbitrary types from JSON, using provided {@link JsonParser}.
*/
public abstract class JsonDeserializer<T>
{

/**
* 当请求将JSON内容反序列成java类型对象的时候,该方法将会被调用。然后,会返回一个
* 由方法自己构造的对象实例。
*
* 需要注意的是,当JSON为null的时候,该方法该不会被调用,因此,方法不需要去
* check 该值是否为null。
*/
public abstract T deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException;

/**
* 和上面常用的方法不同,这个方法带有一个初始化的对象实例,该实例由反序列类配置的。
*
* 当然,这个方法是不必须实现的。一般的,我们转换一个JSON为集合或者Map的时候,可以把
* 通用的元素put到集合中,这样返回的时候,就不需要再操作了。
*/
public T deserialize(JsonParser jp, DeserializationContext ctxt,
T intoValue)
throws IOException, JsonProcessingException
{
throw new UnsupportedOperationException("Can not update object of type "
+intoValue.getClass().getName()+" (by deserializer of type "+getClass().getName()+")");
}

/**
* 这个方法主要是用来支持兼容老的代码,编码编译错误。
*
* 也就是说,当我们使用新的代码和反序列化工具的时候,可能还需要去兼容老的代码数据
* 反序列化,这样子就可以尝试使用老的反序列化类进行解析工作。
*
*/
@SuppressWarnings("unchecked")
public Object deserializeWithType(JsonParser jp, DeserializationContext ctxt,
TypeDeserializer typeDeserializer)
throws IOException, JsonProcessingException
{
// We could try calling
return (T) typeDeserializer.deserializeTypedFromAny(jp, ctxt);
}

// ........
}

Tips:这个反序列化方法实现起来很简单,只需要实现核心的deserialize方法,使用jp.getText获取 value 然后对字符串进行我们需要的各种操作转换,赋值给创建的对象实例,就 OK 了。

阅读全文 »

前言

关于Jackson工具类的相关学习和研究,先前已经写过一篇博文;但是,后来由于工作事情就草草结尾.此外,虽然对Jackson序列化和反序列化的实现机制进行了初步学习,但是现在看看,那时候的博客经验和技术水平决定了整篇博文结构并不是清晰明了,并且反序列化的整个简单的解析,对日常开发并没有直接帮助.对于Jackson这种模块化设计,轻巧灵活的扩展方法,多维度的性能效率优化,导致了最后博文的质量非常不好.因此,接下来几篇博文,将会以日常开发使用的一些API为入口,来分别介绍其使用方式和内部实现,然后在此基础上,对此博文进行分拆.

在开发中,前后端交互的项目,现在一般都是基于JSON文本格式给出API接口,因此对于java对象的序列化就是十分重要的了。基于Spring MVC的配置中,我们配置org.springframework.http.converter.json.MappingJacksonHttpMessageConverter bean时,就是需要配置messageConverters转换器。而针对json的转换器,就可以使用Jackson的objectMapper对象了。

返回给前端的Response Body一般需要良好的可读性,不能因为后端处理方便,就直接破坏前端展示。比如,我们后端使用枚举处理一些情况,但是如果把枚举英文或者数字返回给前端页面,对用户来说是非常不友好的。因此,这里就是涉及到了java对象自定义序列化的问题了。Jackson工具为我们提供了非常多的常见默认的序列化方法,以及一些扩展的接口;参考系统的序列化方法,我们就可以实现自定义的了。

Jackson自定义序列化方法

在Jackson中,提供了多种方式去实现自定义的序列化方法。例如,org.codehaus.jackson.map.JsonSerializableWithType接口以及org.codehaus.jackson.map.JsonSerializer接口。

阅读全文 »