ZooKeeper 快速搭建与体验

Apache ZooKeeper 是一个面向分布式应用程序的高性能协调服务器, 至于它的具体介绍像能提供命名和配置管理、同步和组服务等, 请自个 Google. 虽然对 ZooKeeper 早有耳闻, 也只最近因为项目中有 Kafka 内部用到了 ZooKeeper, 所以才促使我着手去了解一下 ZooKeeper 为何物. ZooKeeper 脱胎于著名的项目 Hadoop, 它也像 Hazelcast 那样未采用严格意义的 Master-Slave 的集群方式, 而是动态选出 Leader, 这避免了单点故障的问题.

既然是集群, 实际应用是会在不同的机器上启动服务, 现如今有了 docker 很容易用它来测试多主机环境, 用 docker search zookeeper 就知道了. 本实例中暂不涉及 docker, 而是在同一个系统中用多个端口来启动三个 ZooKeeper 实例进行测试. 下面以 Mac/Linux 为例:

下载安装 ZooKeeper

https://zookeeper.apache.org/releases.html#download 下载, 写下此文时的最新稳定版是 zookeeper-3.4.9.tar.gz, 下载后解压到某处, 为方便起见把解压后的 zookeeper-3.4.9/bin 加到系统环境变量 $PATH 中, 以后方便任何时候运行 zkServer.sh, zkCli.sh 这样的命令. 阅读全文 >>

Hazelcast 介绍与使用(整理)

要用到 Hazelcast 这个东西用作分布式缓存, 网上搜索了下发现这篇文章对我理解 Hazelcast 那种无主从之分, 避免了单点故障很有帮助, Hazelcast 的数据分布方式很有点像磁盘阵列 RAID 1, RAID0+1 的影子. 基本上在一个节点出现故障的情况下是不会影响数据访问的.

下面这个系列讲的很详细:

  1. Hazelcast集群服务(1)——Hazelcast介绍
  2. Hazelcast集群服务(2)——Hazelcast基本配置
  3. Hazelcast集群服务(3)——集群功能详解
  4. Hazelcast集群服务(4)——分布式Map

Hazelcast 是一个开源的可嵌入式数据网格(社区版免费,企业版收费)。你可以把它看做是内存数据库,不过它与 Redis 等内存数据库又有些不同。项目地址:http://hazelcast.org/

Hazelcast 使得 Java 程序员更容易开发分布式计算系统,提供了很多 Java 接口的分布式实现,如:Map, Queue, Topic, ExecutorService, Lock, 以及 JCache 等。它以一个 JAR 包的形式提供服务,只依赖于 Java,并且提供 Java, C/C++, .NET 以及 REST 客户端,因此十分容易使用。

如何存储数据

Hazelcast 服务之间是端对端的,没有主从之分,因此也不存在单点故障。集群中所有的节点都存储等量的数据以及进行等量的计算。

Hazelcast 缺省情况下把数据分为 271 个区。这个值可配置于系统属性 hazelcast.partition.count。 对于一个给定的键,在经过序列号、哈希并对分区总数取模之后能得到此键对应的分区号。所有的分区等量的分布与集群中所有的节点中,每个分区对应的备份也同样分布在集群中。 阅读全文 >>

使用 Java8 Optional 的正确姿势

我们知道 Java 8 增加了一些很有用的 API, 其中一个就是 Optional. 如果对它不稍假探索, 只是轻描淡写的认为它可以优雅的解决 NullPointException 的问题, 于是代码就开始这么写了

Optional<User> user = ...... 
if (user.isPresent()) {
    return user.getOrders();
} else {
    return Collections.emptyList();
}

那么不得不说我们的思维仍然是在原地踏步, 只是本能的认为它不过是 User 实例的包装, 这与我们之前写成

User user = .....
if (user != null) {
    return user.getOrders();
} else {
    return Collections.emptyList();
}

实质上是没有任何分别. 这就是我们将要讲到的使用好 Java 8 Optional 类型的正确姿势.

在里约奥运之时, 新闻一再提起五星红旗有问题, 可是我怎么看都看不出来有什么问题, 后来才道是小星星膜拜中央的姿势不对. 因此我们千万也别对自己习以为常的事情觉得理所当然, 丝毫不会觉得有何不妥, 换句话说也就是当我们切换到 Java 8 的 Optional 时, 不能继承性的对待过往 null 时的那种思维, 应该掌握好新的, 正确的使用 Java 8 Optional 的正确姿势. 阅读全文 >>

.NET Core 上的 Web -- ASP.NET Core

.NET Core 上不光可以做控制台的程序, 还可也实现 AST.NET 的 Web 应用, 而且是自带服务器的那种. 像 NodeJS, Spring Boot, Netty 那种非容器型的嵌入式的 Web Server, 非常适合于做微服务应用. 谁说 ASP.NET 就一定要部署到 IIS 上呢?

本文参考 https://docs.asp.net/en/latest/getting-started.html 而来, 基本步骤是一致的

1. 安装 .NET Core

参考上一篇 .NET Core 上手体验 Hello World

2. 创建 .NET Core 项目

mkdir appnetcoreapp
cd aspnetcoreapp
dotnet new

3. 更新 project.json 引入 Kestrel HTTP server 依赖

阅读全文 >>

.NET Core 上手体验 Hello World

别人开源是种奉献精神, 微软突然把 .Net Framework 也开源, 人们看到的却是一种野心, 现在 .NET Core 开源还真正跨平台了, 真是雄心壮志啊.

本人 Java 多年, 但不可否认 C# 是一个很好的语言, 我认为单纯从语言上来说要优于 Java 语言, 所以 .NET Core 搭上 C# 力量更是不能小觑, 不得不摸索一下.

之前虽有浅尝 .NET Core 的 Hello World,   以及最简单的 ASP.NET 应用, 但未有成文, 在此再作演练一番以备忘.

安装 .NET Core

本人所用平台为 Mac, 所以当打开 .NET Core 的首页面 https://www.microsoft.com/net/core 时直接激活了 Mac 标签, 在这个页面我们知道 .NET Core 支持 Windows, Linux, Mac; 还有现成的 Docker 镜像拉下即用. .NET Core 当前版本是 1.0, 可以照着官方向导来做, 不过我倾向于全控制台来完成. 首先你的 Mac 得先有个 brew,  现在用 port 管理应用比较少了吧.

说白了, 安装 .NET Core 只需要用 brew cask install dotnet, 第一条命令没事都应该运行一下的, 发现有可升级的就运行一下 brew upgrade.

brew cask install dotnet 会检测是否有 openssl, 没有的话自动安装, 接着帮你下载 dotnet 安装包装上: 阅读全文 >>

Clojure REPL 连接远程会话

学习 Clojure 一般是用 lein repl 启动控制台, 每次启动 lein repl 都会发现它打开了一个端口, 例如

➜ ~ lein repl
nREPL server started on port 57212 on host 127.0.0.1 - nrepl://127.0.0.1:57212
REPL-y 0.3.7, nREPL 0.2.12
Clojure 1.8.0
...........

一直不清楚上面显示的 nrepl://127.0.0.1:57212 该作何用, 而且端口号是随机的, 这其中定有文章.

幸好有 Google 帮忙, 查一查, 然后才意识到何不运行  lein help repl 来看看 repl 中到底有何玄机, 原来是:

<none> -> :start     lein repl 默认的行为, 见下. 未指定 :host 或 :port , :host 默认为 127.0.0.1,  :port 为随机
:start [:host host] [:port port] 原来  lein repl 设计为为 CS 结构. :start 会启动一个 nREPL  server, 并且立即启动一个 client 连接上它. :host 默认为 127.0.0.1, :port 默认为随机的
:headless [:host host] [:port port]   只启动 nREPL server, 等待别人来连接它, 相同的默认 :host, :port 规则.  也就是它不会进到 Clojure 控制台
:connect [dest]   连接一个 nREPL server. 目标服务器的指定有三种方式: HTTPS(S) URL, host:port, 或 port 阅读全文 >>

Scala 中置, 前置, 后置操作符

拟此篇以温习 Scala 对方法调用上的一些约定. 标题中说是关于操作符的事, 其实 Scala 像有了访问方法和属性的一致性原则一样, 可以说操作符与方法更是统一的, 或者说只有方法调用. 此处所称的操作符只不过是 Scala 对无参(prrameterless), 或只有一个参数的方法, 和特殊的四个 unary_+, unary_-, unary_!, unary_~ 方法的便捷的调用约定格式.

一. 中置操作符(对只有一个参数方法的调用约定, a plus b)

case class MyNumber(value: Int) {
  def +(that: MyNumber) = MyNumber(this.value + that.value)
}

调用方式

第一行是用点语法的标准方法调用格式, Scala 在当方法只有一个参数时, 可以省略点, 以及括号, 因此可写为上面第二行种的格式. 所以方法 + 就化身为了中置操作符了. 阅读全文 >>

如何直接运行 Clojure 脚本文件

对于大多数的脚本编程语言来说, 提供有现成的分别进入控制台与执行脚本文件的命令. 例如 Scala, Python 默认进入控制台(REPL), 接文件路径为参数则执行脚本文件. 还有分别进入控制台和执行脚本的命令是: irb 与 ruby, groovsh 与 groovy, php -a 与 php, perl -de1 和 perl. 可以 Clojure 本身就没有 clojure 这样的命令. 当我们试图在 Mac 下用 brew install clojure 安装时, 得到的提示是没有 clojure, 应该用 brew install leiningen 去安装 leiningen, 它是一个类似于 Scala sbt 的工具.

所以启动 Clojure REPL 的命令就是 lein repl, 其实还有一个办法来启动 Clojure 的控制台, 因为 Clojure 也是构筑于 JVM 之上的, 所以也能像启 Groovy/Scala 一样通过  java 指令加载 jar 文件来启动. 去官网 http://clojure.org/ 下载 Clojure 安装包(例如: ), 解压, 假定它的 jar 文件是 ~/Developers/clojure-1.8.0/clojure-1.8.0.jar, 那么也可以用命令 java -jar ~/Developers/clojure-1.8.0/clojure-1.8.0.jar 进到 Clojure 控制台.

进到 Clojure 的提示符 user=> 下就可以测试 Clojure 代码了, 那么如何加载一个写在 clj 文件里的代码呢? 我们可以在 Clojure 控制台下用方法 load-file. 假定 ~/hello.clj 文件的内容是 阅读全文 >>

想像中理想编程语言的几个特征

代码写多了, 总希望能从繁琐的代码中挣脱出来, 编程语言的设计应为快速解决问题为目的. 不断重复的表达式应有相应的语法糖加以简化.

函数式语言设计之初不被人重视, 进入到多核化之后我也渐渐从面向对象转入到了函数式的阵营.

学习设计模式时 Java Swing 堪称各种模式的典范, 但是设计的后用起来顺手又能如何, 不过 Java Swing 的性能更是硬伤, 所以有了 SWT 那种更接近于本地化的组件库.

编程语言有两种哲学: 条条大路通罗马 与 一条大路罗马. 前者可以让语言更灵活, 但却容易走上一条不归路, 譬如 Scala; 后者让你专注于解决实际的问题, 像 Python 的语法非常简单.

填满了博客中文章概要显示中的内容, 可以说一说我希望中的语言的几个特征, 主要关注语法: 阅读全文 >>

Java 语言的几个缺陷之六: 无字符串插值

Java 在定义字符串的时候不支持字符串插值, 即不能在字符串中捕获作用域中的变量, 用来组成当前字符串. 而这可以说是其他各种言都具备的基本特性. 例如 Bash 中可以这样

bash-3.2$ name=Yanbin
bash-3.2$ echo "Hello $name"
Hello Yanbin

Java 中不支持类似的方式

String name = "Yanbin";
String greeting = "Hello $name";  //Java 中无法把 $name 替换为 name 变量值 "Yanbin"

而使用 Java 必须用 String 的静态方法 format (注意是静态方法哦) 来间接的格式化出一个字符串, 可以这么写

String.format("Hello %s", "World");
String.format("%1$s %1$s %s %s %2$s", "aa", 10);    //aa aa aa 10 10

我们看到在用 format 格式化时匹配参数会是一个不小的问题, 相同使用法的打印输出方法是 System.out.printf(). 别说字符串插值了, 如果 format 方法是 String 的一个实例方法应用起来都会便利些, 如 "Hello %s".format("World") 会容易读些, Scala 的字符串实例就有 format 方法了. 阅读全文 >>