BT

如何利用碎片时间提升技术认知与能力? 点击获取答案

Ballerina微服务编程语言:最新发布版本与“Ballerina Central”简介

| 作者 Tyler Jewell 关注 1 他的粉丝 ,译者 张卫滨 关注  他的粉丝 发布于 2018年7月9日. 估计阅读时间: 35 分钟 | ArchSummit北京2018 共同探讨机器学习、信息安全、微服务治理的关键点

核心要点

  • 该教程阐述了Ballerina,这是一个新的编程语言和平台,它的目标在于让创建具有弹性的服务变得更加容易,这些服务会跨分布式端点进行集成和编排。
  • Ballerina .970已经释放,语言的稳定性会不断提升,有望在2108年底发布1.0;
  • Ballerina现在托管在该站点上,包括包管理、依赖管理、版本化,Ballerina Central上有一个全局托管的注册表,用于连接器(connector)和注解(annotation)。
  • Ballerina的设计原则在于将集成的概念转换为一种语言,包括一个网络感知的类型系统、序列图语法、并发工作者、为“采用DevOps做好准备”以及环境感知。

Ballerina是一种让微服务编程更加简单的方式,它通过简化集成API来实现这一点。Ballerina是三年前由WSO2的架构师发起的,在与EAI、ESB和工作流产品构建集成时,他们遇到了各种挑战,Ballerina则是他们对此给出的响应。

关于Ballerina

开发一种新的编程语言和运行时技术栈并不是一件常见的事情。Ballerina起源于项目领导者在进行项目集成时所遇到的挫败感,这种集成的工作越来越多地干扰了开发人员的常规工作流程,即周而复始地编辑、构建、测试。

基于配置的集成产品,如用于ESB的Apache Camel和Synapse、用于BPM的Bonitasoft,都有复杂的生命周期,它们必须要部署服务器、配置连接器、使用XML编写逻辑并使用XPath完成数据操作。这种方式没有带来良好的开发人员体验,因为工作流和集成难以编辑、管理启动阶段(stage)以及测试。

还有种替代方案就是使用通用的编程语言,如Java和JavaScript,采用任意的生命周期工具链都能实践敏捷,但是开发人员需要编码实现集成的语义。像Spring这样的框架提供了一个抽象来辅助集成,但是通常情况下为了实现简单的集成,依然需要编写YAML、XML和多个单独的源码文件。

Ballerina致力于填补集成产品和通用编程语言之间的空白,借助它能够很容易地编写有弹性的程序,实现跨分布式端点的集成和编排。

Ballerina同时提供敏捷性和集成的便利性。Ballerina通过将语言、集成语法以及环境化部署构造打包到一个代码文件中实现这一点,这个代码文件会被编译为可在VM中执行的二进制文件,然后利用智能感知服务和IDE调试器使其成为开发人员工具链的一部分。

Ballerina是这样描述自己的:“Ballerina是一门编译式的、事务性的、静态和强类型编程语言,具备文本和图形化语法。Ballerina将分布式系统集成的基本概念组合到了语言之中,并且提供了一个类型安全的、并发的环境,以便于实现具备分布式事务、可靠消息传递、流处理和工作流的微服务。”

HelloWorld是什么样子的呢?

举例来说,Hello World API服务可以写成一个简单的文本文件,并通过`ballerina run <file>`来运行:

// Packages contain functions, annotations and
// connectors. This package is referenced by
// ‘http’ namespace in the code body.
import ballerina/http;
import ballerina/io;

// A service is a network-accessible API. This
// service accessible at '/hello', and bound to a
// default listener on port 9090. `http:Service`
// is a connector in the `http` package.
service<http:Service> hello bind {port:9090} {

 // A resource is an invokable API method
 // Accessible at '/hello/hi’
 // 'caller' is the client invoking this resource
 hi (endpoint caller, http:Request request) {

   // Create object to carry data back to caller
   http:Response response = new;

   // Objects have function calls
   response.setPayload("Hello Ballerina!\n");

   // Send a response back to caller
   // Errors are ignored with '_'
   // ‘->’ is a synchronous network-bound call
   _ = caller -> respond(response);
 }
}

Ballerina的设计理念

Ballerina的语言和运行时设计为描述集成流、开发和部署。按照定义,集成流假定会与绑定网络的端点进行交互,并且特定的构造可以合成到语言和运行时中,从而简化开发。

网络感知的类型安全性:Ballerina有一个结构化的类型系统,包括原始类型、对象、联合类型(union)以及元组类型。网络系统所返回的信息会具有不同的载荷类型和错误。Ballerina的类型系统采用基于联合类型的方式来实现这种可变性。这个类型安全的模型在赋值时添加了类型推断的功能,对于绑定网络载荷来说,这种方式能够提供强大的编译时完整性检查。 

any anything; // can be any type
int integer = 0;
float floatingPoint = 0.0;

// constants are final instances of a type
@final float PI = 3.1415926;

boolean b = true;
string hi = "hello";
blob bl = hi.toBlob("UTF-8");

// json is a primitive
json js = {
   a: "hello",
   b: 5
};

// xml is a primitive
xml x = xml `<ballerina>
               <supports>XML natively</supports>
           </ballerina>`;

// type inference
var x = xml `<myXML/>`;

// errors are built in types
error e;

string[] stringArray = ["hi", "there"];
int[][] arrayOfArrays = [[1,2],[3,4]];

// union and tuple types
json | xml | string networkResponse;
(string, int) tuple = ("hello", 5);
() n = (); // the empty tuple is "null"
string | int stringOrInt = 5; 

// maps are built in
map<boolean> myMap = {"ballerina": true};

// new types can be declared
// a "record" type is a simple structure
type myRecord { string a; int b; };

// records can be converted to/from JSON with error handling
rec | error  myRec = <rec>j;

// you can re-declare existing types
type myInt int;

// objects have public and private fields, initialisers and logic
type myObj object {
   public { string x; }
   private { string y; }
   new (string a, string b) {
       x = a; y = b;
   }
   function getY() {
       return y;
   }
};

// enumerations are union types:
type aOrB "A" | "B";
aOrB myEnum = "A";
aOrB compilationError = "C"; // this won't compile due to type checking

// streams are first-class types
stream<obj> str;

// futures are built in types for asynchronous activities
future<string> f;

// functions are types and support lambda expressions
function (string, int) returns (string) func =
   (string x, int i) => (string) { return "lambda"; };

序列图形化:Ballerina底层的语言语义在设计之时就建模了相互独立的各方如何通过结构化的交互来进行通信。因此,每个Ballerina程序都能以序列图的形式来展现其端点的流动,其中包括同步和异步的调用。序列图反映了设计师和架构师如何思考和记录系统之间的关联的。Ballerina的语法是结构化的,它允许任何的工具或系统生成序列图,因此,鼓励开发人员编写Ballerina代码时的思考方式要遵循强交互的最佳实践。Ballerina自带的智能感知语言服务器能够将服务渲染为序列图,比如下图展现了VS Code中某个服务异步调用一个端点:

上图是由该源码文件衍生出来的:

import ballerina/http;
import ballerina/io;
import ballerina/runtime;

@http:ServiceConfig {
   basePath:"/quote"
}
service<http:Service> AsyncInvoker bind {} {

 @http:ResourceConfig {
     methods:["GET"],
     path:"/"
 }
 getQuote (endpoint caller, http:Request req) {
  
   // ‘endpoint’ declares a connection to a networked location.
   endpoint http:SimpleClient nasdaqServiceEP {
     url:"http://localhost:9095"
   };

   io:println(" >> Invoking service asynchronounsly...");

   // 'start' allows you to invoke a function or client
   // connector action asynchronously. This is a remote
   // invocation that returns without waiting for response.
   future<http:Response | http:HttpConnectorError> f1
     = start nasdaqServiceEP
           -> get("/nasdaq/quote/GOOG", new);
   io:println(" >> Invocation completed!"
     + " Proceed without blocking for a response.");

   io:println(" >> Check for response availability...");

   // ‘await` blocks until the previously started
   // async function returns.
   var response = await f1;
   io:println(" >> Response available! ");
   match response {
     http:Response resp => {
       string responseStr = check resp.getStringPayload();
       io:println(" >> Response : "
                  + responseStr);
       _ = caller -> respond(resp);
     }
     http:HttpConnectorError err => {
       io:println(err.message);
     }
   }
 }
}

并发工作者(Concurrency Worker):Ballerina的执行模型是由一个名为工作者(worker)的轻量级并行执行单元组成的。工作者使用完全非阻塞的策略,这里不会有函数锁定一个执行中的线程,比如HTTP I/O调用等待响应。这些语义表明它们是序列并发的,工作者是相互独立的actor,它们之间不会共享状态,而是通过消息进行交互,这类似于分布式系统通过网络传递消息。工作者和fork/join语言语义抽象了底层非阻塞的运行方式,从而让我们能够使用一个更简单的并发编程模型。

import ballerina/io;
function main (string... args) {    
    worker w1 {
        int i = 100;
        float k = 2.34;

        // Pass variables to w2
        (i, k) -> w2;
        json j = {};
        
        // Receive a message from w2
        j <- w2;
    }    

    worker w2 {
        int iw;
        float kw;
        any vW1;

        // Receive a message from w1
        vW1 <-  w1;

        (iw, kw) = check <(int, float)>vW1;

        json jw = {"name":"Ballerina"};

        // Send a message to w1
        jw -> w1;
    }
}

DevOps就绪:在过去的15年间,人们对语言所提供的最佳实践和相关工具集的期望在不断发展。现在,如果某种语言不能包含单元测试框架、构建系统、依赖管理、版本化以及共享可重用代码的模块,那么可以说这种语言并没有为真正使用做好准备。Ballerina包含了所有上述的子系统,并将其作为核心分发版本的一部分,所以不存在社区漂移(community drift),如果生态系统需要在语言之上构建工具,而不是设计在语言内部的话,将会发生这种漂移的情况。

Ballerina的包管理、依赖和版本模型是在学习Docker、Elm和NPM的基础上实现的。尽管可以构建和运行单独的Ballerina源文件,但是包(模块)只能作为项目的一部分来构建,项目是由Ballerina管理的。每个项目有自己的依赖缓存,所有的包都按照语义(semver)规则进行版本化。严格的规则会防止应用出现依赖冲突,应用会在一个中央注册表中导入包。

$ tree
/
  .ballerina/             # Dependencies downloaded and cached locally
  Ballerina.toml          # Defines project build intent
  my.package/             # Any folder is a package                 
    RouterService.bal           
    tests/
      RouterTests.bal


$ ballerina build
Pulling dependencies…
  ballerinax/http     [central.ballerina.io -> home repo] [====>] 56/56 
  ballerinax/rpc      [central.ballerina.io -> home repo] [====>] 98/98
  ballerinax/twitter  [central.ballerina.io -> home repo] [====>] 79/79 

Building binaries…
  something.bal ⇒ target/something.balo
  something.bal ⇒ target/something.balo
  something.bal ⇒ target/something.balo

Running tests…
  Test <mytest> ⇒ RUNNING … SUCCESS
  Test <mytest> ⇒ RUNNING … SUCCESS
  Test <mytest> ⇒ RUNNING … SUCCESS

Generating deployment artifacts…
  @docker                 - complete 1/1
  @kubernetes:ingress     - complete 3/3
  @kubernetes:svc         - complete 3/3
  @kubernetes:deployment  - complete 1/1

SUCCESS

$ ballerina run 
Service ready at http://192.168.1.101/customer

$ ballerina run kubernetes 
Service ready at http://wso2.com:4056/customer

环境感知:Ballerina和它的组件是用于分布式、事件驱动架构的。Ballerina中编写的每个服务都会位于一定的环境中,该环境可能还会包括其他的服务、遗留服务、服务网格、编排器、API网关、标识网关(identity gateway)、消息代理和数据库。

Ballerina的语言和注解设计为能够感知环境的,它会将这些其他的组件作为语法对象来处理,并将关系作为装饰过的注解来处理。语言和构建系统能够根据环境感知我们的服务相关的其他组件,这样我们就能在CI/CD之前生成必要的制件(artifact)、针对网络相关的负载进行数据和完整性检查并将依赖却还没有部署的组件进行预打包,使其成为Ballerina二进制的一部分。

Ballerina自带的注解能够将服务连接至不同的组件,如API网关、消息代理以及标识服务器。除此之外,Ballerina还包含了可定制化的注解,它们能够标记服务该如何进行打包部署。生态系统供应商可以添加自定义的注解和编译器扩展,它们将会作为构建过程的一部分用于生成可直接部署的制件。通过在同一个文件中以源码的方式添加这样的注解,开发人员就能够维护流程、通过编译器实现增量式快速构建并让语言服务器智能感知在自己的环境中定义该如何进行集成。

例如,hello world服务可以转换为调用一个带有断路器的不可靠的外部REST端点,并让编译器生成Kubernetes部署制件:

// Packages contain functions, annotations and
// connectors. This package is referenced by
// ‘http’ namespace in the code body.
import ballerina/http;
import ballerina/io;

// A connector to a REST endpoint with a circuit
// breaker that will be compiled into the service
endpoint http:Client homer {
   targets : [{url:"http://www.simpsonquotes.xyz"}],
   circuitBreaker: {
       failureThreshold:0,
       resetTimeMillies:3000,
       statusCodes:[400, 404, 500]
   },
   timeoutMillis:500
};

@kubernetes:Deployment {
   image: "demo/home-demo",
   name: "homer-demo"
}
@kubernetes:Service {
  serviceType:"NodePort",
  name:"homer-demo"   
}
service<http:Service> hello bind {port:9090} {
 hi (endpoint caller, http:Request request) {

   // The ‘check’ operator will propagate any error
   string name = check homer -> get (“/quote”);

   http:Response response = new;
   response.setPayload("Hello Ballerina!\n");
   _ = caller -> respond(response);
 }
}

Ballerina Central

Ballerina搭建到了beta版本的central.ballerina.io中,这是一个中心化的、共享的注册表,允许开发人员查找可重用代码的包并在他们的服务中组装这些包。

所有人都可以创建账号,它是免费使用的,遵循类似DockerHub共享镜像的模型。

Ballerina的包可以包含函数、连接器、注解(比如部署所需的注解)、枚举、对象和记录。

包遵循<org-name>/<package-name>模型。Ballerina Central会为每个用户和每个组织定义组织的名称。创建包并将其推送至Ballerina Central是非常简单的,开发人员可以按照下面的命令来实现:

// Create a project with a package
// Subfolders are packages
ballerina init

// Search local repositories and Ballerina central for packages
ballerina search

ballerina pull <org-name>/<package-name>

// Push your packages up to Ballerina Central
// Kicks off an oAuth authorization flow in your browser to
// obtain a CLI key that is installed onto your system
ballerina push <org-name>/<package-name>

Ballerina的状态

Ballerina团队已经发布了.970,这是该语言类型系统、并发语法以及连接器结构的重要演进。另外,该版本引入了对服务器连接器的支持、对JSON和XML的内置原生支持、用于Docker和Kubernetes的注解以及流式SQL语法。在过去的一年中,大约有来自100个贡献者的15,000次提交。Ballerina是基于ASL 2.0许可证的。

该项目的贡献者搭建了Ballerina.io,将其作为Ballerina的主页。它包含了一个执行Ballerina服务的实验场所、学习该语言的100个样例以及学习如何集成一个完整的开发人员工作流的指南,该指南包含了搭建IDE、编写代码、开发集成单元测试、构建、部署至Docker和Kubernetes、通过跟踪和度量指标实现可观测性。

以后会如何发展?

Ballerina正在朝着1.0稳定版本而努力,他们希望能有3到5年的语言稳定性和向后兼容性,其目标是在2018年底之前完成1.0的长期稳定(Long Term Stability)发布版本。同时,WSO2承诺提供在今年夏天提供商业支持,其中会包括针对VM的增量式补丁机制。

开发人员可以期待每月的功能增强发布,今年剩余的关注点包括提供一个LLVM实现的原型、继续稳定包的标准库、结合Ballerina Central推进该生态系统的使用以及增加有状态的服务。

他们鼓励开发人员通过该 站点学习更多的知识,在这里可以下载SDK和二进制文件。Ballerina还会举办第一届Ballerinacon,这是一个为期一天的学习活动,既包括实体活动,也有虚拟的活动。开发人员可以通过该网址进行注册。

关于作者

Tyler Jewell 是WSO2的CEO,WSO2是最大的开源集成提供商,他还是Toba Capital的合伙人。他曾经创建并管理云DevOps公司Codenvy,该公司于2017年被Red Hat收购。作为风险投资人、天使投资人和董事会成员,他在DevOps公司方面主导了1亿美元的投资,包括WSO2、Cloudant(被IBM收购)、 Sauce Labs、Sourcegraph、ZeroTurnaround(被Rogewave收购)、InfoQ和AppHarbor(被微软收购)。在此之前,Tyler曾经在Oracle、Quest、MySQL和BEA工作,在Java领域参与出版过三本图书。

查看英文原文:Ballerina Microservices Programming Language: Introducing the Latest Release and "Ballerina Central"

评价本文

专业度
风格

您好,朋友!

您需要 注册一个InfoQ账号 或者 才能进行评论。在您完成注册后还需要进行一些设置。

获得来自InfoQ的更多体验。

告诉我们您的想法

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我
社区评论

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

允许的HTML标签: a,b,br,blockquote,i,li,pre,u,ul,p

当有人回复此评论时请E-mail通知我

讨论

登陆InfoQ,与你最关心的话题互动。


找回密码....

Follow

关注你最喜爱的话题和作者

快速浏览网站内你所感兴趣话题的精选内容。

Like

内容自由定制

选择想要阅读的主题和喜爱的作者定制自己的新闻源。

Notifications

获取更新

设置通知机制以获取内容更新对您而言是否重要

BT