最近在听李志的歌。

李志人称逼哥。实在想不明白为什么有人喜欢这哥们的歌儿,人又矮又丑又老,关键是唱功垃圾到家,一副大白嗓子在那 XJB 喊。

但是这哥们有个经历,还是让我印象比较深刻的,据他自己说,他出名之后唱的很多歌,都是他出名之前就写好的歌。也就是说,他在音乐方面还是有才华的,只是碰巧出名了。在他出名之前的经历,就是典型的屌丝青年的经历,追姑娘的时候受到嘲笑,卖弄所谓的才华时受到更大的嘲笑:一个屌丝穷逼青年,还在这儿谈什么狗屁才华,简直傻逼一样。

出名之后,境遇当然就不一样了,所谓的音乐人们赞叹他的才华了,自己也有钱了,也有大把的姑娘可以日了。唱的歌还是那些歌,差的只是名气而已。

这些都是逼哥自己说的。

这个世界运作的方式,真的像是强奸一样。你就是按照这个世界本身的运作方式来生活,还是会遭到强奸,因为它会变,更别说你想任性一些按照自己理解的方式去生活。逼哥应该能体会到这个世界任性,所以很多歌曲里都是一副被强奸多了,无力反抗的感觉。世界就是这么任性的运作,不知道会不会好了。

就像逼哥的那首歌, 《这个世界会好吗》 (https://y.qq.com/n/yqq/song/003sVciy0nE1VJ.html)

这个任务调度框架应该做成一个类库,还是做成一个平台,这是一个需要明确的问题。

如果仅仅是一个类库,那么对用调用方来说,需要做的事情会比较多,除了要基于这个类库开发自己Job之外,还要关注数据库的部署,调度器的部署;另一方面,对类库维护者来说,虽然类库看似比较易于维护,仅仅只是发布一个jar包出去而已,但是如果类库依赖方比较多,会难以控制类库的版本升级,并且需要特别注意升级的兼容性问题,实际上不是那么容易维护。

如果做成一个平台,对于调用方来说,使用起来比类库是要方便许多的,只需要关注自己Job的开发,而不再需要数据库部署,调度部署—这些工作调度平台会负责;但是对于调度平台的维护者来说,要做的事情则要比调度类库多的多,例如平台肯定是要运行在一个集群上的,那就需要一些集群管理能力;平台上运行的任务多了之后,还需要任务监视和管理能力,这样才能知道每个任务的状态是否正常,任务的一些统计指标是否正常;为了方便每个调用方的Job代码部署和更新,还需要平台支持动态代码部署,防止一个调用方的代码更新要重启整个集群。

但是,服务化仍然是正确的方向,即便是任务调度服务相对于任务调度类库要做很多额外的工作。因为对于使用方来说,一个任务调度服务使用起来要方便太多,而且长期来说,平台能力的建设是可以长期受益的,只要建设起来,后续的维护升级就不会那么困难了,接入的项目越多平摊到每个项目的技术成本会越低。

建设一个任务调度框架,有几个问题需要解决:

  • 1.模块之间隔离 可以认为一个项目的所有Job都属于一个模块,平台需要做到每个模块之间都相互隔离,防止产生模块间依赖和冲突;
  • 2.模块动态加载 如果平台中模块很多,那就需要做到少数模块的代码更新不会导致整个平台的进程都重启,这就需要一些模块动态加载技术来实现;
  • 3.平台的企业级管理问题 对于一个企业级平台来说,运行中的各种管理能力是不可或缺的,例如任务的监控和告警,任务执行情况的统计和分析,集群状态管理等等;

有几项技术或者思想对于解决这些问题或许是帮助的:

  • 1.OSGi (https://www.osgi.org/) OSGi可以说是一个模块系统,所有OSGi应用中的代码都属于一个模块,模块之间可以隔离,而且可以对模块进行动态加载。目前也有一些基于OSGi标准的框架,例如Eclipse Equinox(http://www.eclipse.org/equinox/),Apache Karaf(https://karaf.apache.org/)和Apache Felix(http://felix.apache.org/)。这些框架简化了OSGi应用的部署和管理,其中karaf的能力比较全面,可以与一些集群管理平台如Mesos,还提供Bundle管理模块Karaf Decanter。
  • 2.jigsaw (https://www.osgi.org/) jigsaw项目已经随着Java9发布了,作为Java9内置的模块系统,自然要比OSGi更顺手,但是jigsaw在模块动态加载方面不如OSGi,而且配套工具很少,没有我们需要的企业级管理能力。
  • 3.akka (https://akka.io/) akka与上面两个实际上不是平行的概念,OSGi和jigsaw都是java的模块系统,而akka是Actor模型的一个框架,用于编写消息驱动型应用。假如用akka来实现我们的的任务调度平台,那么形态上跟我们的之前设想的有些不同,我们不在需要一个中心化的数据库来保存任务信息了,或者说不需要中心化的数据库来新增待调度的任务了,akka的封装性很高,一切消息序列化,反序列化,网络传输,actor状态持久化等待都被封装了起来,对于基于akka应用来说,只需要关注怎么把自己的应用抽象成Actor模型,也就是说怎么抽象出每个Actor,怎么制定Actor之间的消息传递逻辑。 我们的任务调度平台初步来看也是可以在不改变现有接口的情况下用akka的Actor模型来实现的。但是akka的封装的特别厚重,对于企业管理来说不见得是好事。而且akka应该是没有代码动态加载机制的,需要找其他方案实现。
  • 4.docker (https://www.docker.com/) Docker的Containner的动态启停和隔离性对任务调度平台来说是很有帮助的,但是隔离性高会给模块与平台的集成带来困难。

Here be a sample post with a custom background image. To utilize this “feature” just add the following YAML to a post’s front matter.

image:
  background: filename.png

This little bit of YAML makes the assumption that your background image asset is in the /images folder. If you place it somewhere else or are hotlinking from the web, just include the full http(s):// URL. Either way you should have a background image that is tiled.

If you want to set a background image for the entire site just add background: filename.png to your _config.yml and BOOM — background images on every page!

Background images from Subtle Patterns (Subtle Patterns) / CC BY-SA 3.0
Syntax Highlighting Post

Syntax highlighting is a feature that displays source code, in different colors and fonts according to the category of terms. This feature facilitates writing in a structured language such as a programming language or a markup language as both structures and syntax errors are visually distinct. Highlighting does not affect the meaning of the text itself; it is intended only for human readers.1

GFM Code Blocks

GitHub Flavored Markdown fenced code blocks are supported. To modify styling and highlight colors edit /_sass/syntax.scss.

#container {
  float: left;
  margin: 0 -240px 0 0;
  width: 100%;
}
.highlight {
  margin: 0;
  padding: 1em;
  font-family: $monospace;
  font-size: $type-size-7;
  line-height: 1.8;
}
<nav class="pagination" role="navigation">
  {% if page.previous %}
    <a href="{{ site.url }}{{ page.previous.url }}" class="btn" title="{{ page.previous.title }}">Previous article</a>
  {% endif %}
  {% if page.next %}
    <a href="{{ site.url }}{{ page.next.url }}" class="btn" title="{{ page.next.title }}">Next article</a>
  {% endif %}
</nav><!-- /.pagination -->
1
2
3
4
5
6
7
8
<nav class="pagination" role="navigation">
  {% if page.previous %}
    <a href="{{ site.url }}{{ page.previous.url }}" class="btn" title="{{ page.previous.title }}">Previous article</a>
  {% endif %}
  {% if page.next %}
    <a href="{{ site.url }}{{ page.next.url }}" class="btn" title="{{ page.next.title }}">Next article</a>
  {% endif %}
</nav><!-- /.pagination -->
module Jekyll
  class TagIndex < Page
    def initialize(site, base, dir, tag)
      @site = site
      @base = base
      @dir = dir
      @name = 'index.html'
      self.process(@name)
      self.read_yaml(File.join(base, '_layouts'), 'tag_index.html')
      self.data['tag'] = tag
      tag_title_prefix = site.config['tag_title_prefix'] || 'Tagged: '
      tag_title_suffix = site.config['tag_title_suffix'] || '&#8211;'
      self.data['title'] = "#{tag_title_prefix}#{tag}"
      self.data['description'] = "An archive of posts tagged #{tag}."
    end
  end
end

Code Blocks in Lists

Indentation matters. Be sure the indent of the code block aligns with the first non-space character after the list item marker (e.g., 1.). Usually this will mean indenting 3 spaces instead of 4.

  1. Do step 1.
  2. Now do this:

    def print_hi(name)
      puts "Hi, #{name}"
    end
    print_hi('Tom')
    #=> prints 'Hi, Tom' to STDOUT.
    
  3. Now you can do this.

GitHub Gist Embed

An example of a Gist embed below.

Sample Link Post

This theme supports link posts, made famous by John Gruber. To use, just add link: http://url-you-want-linked to the post’s YAML front matter and you’re done.