国庆节开始了,为大家献上一篇!
- 前言
- 开战函数式-faas on docker!
- 开战云计算-faas on k8s!
一. 前言: faas时代已至,云计算领域必将欣起一场血雨腥风。。。
微服务已逐渐被人们所接受,没吃过猪肉的,想必也见过猪跑。。。
大量的人在迷信微服务,把整个系统搞得一团乱,我是非常气愤的!
但是我不排斥微服务,因为我相信
微服务嘛,必将成为函数即服务faas的踮脚石。
1. 计算机原本很简单,最初一个PHP就可以搞定前后端。。。
但是呢,后端怎么可以乱动?前端是可以乱动的!
毕竟用户体验是不断变化的,用户特效是不断变化的,但后台核心功能岂可胡来。。。
所以,在有限的后台服务上,我们可以自由组合出各种前端,并且分工更加明显。
这显然是好事。。。
2. 前后端分离是第一步,随着科技日益发展,后端功能也越堆越多。
部门之间业务更加集密,这时候跨部门的业务集成是非常有必要的了。
SOA的时候已经过去,REST的简单使服务变得如此便宜, oauth2协议也成了标配。。。
所以,不同部门已不再限技术 ,不再限平台,只需要接口的体系。
这也算是好事。。。
3. 各系统之间交互,必然有大量基础设施,这自然也形成了微服务体系标准。
比如验证功能,存储功能,调度功能大家都可以一起用,开开心心。。。
所以,微服务开始呼风唤雨。。。
但是呢,人们慢慢熟悉,慢慢发现,微服务深处,让人可怕。。。
4. 微服务哪里让人可怕了?简单的地方隐藏了无数复杂。。。
比如我要做一个文件格式转码器,很自然可以做成一个微服务,大家一起开心使用。
一切看起来似乎很美好,但是如果你有10个服务,有个服务挂掉了呢?B服务依赖A服务呢?
我靠,什么服务降级?什么熔断机制?什么服务注册?什么配置中心?什么什么,请问,我是在写代码吗?
我的功能本身可以是一个插件JAR包,得到前台请求,运行JAR包里面的功能就可以了,
什么事情都没有,一台服务挂了,另一个来嘛。
所有请求处理都从代码插件包里加载响应,没有额外进程额外开销,没服务你怎么出问题怎么监控!。。。就应该这么简单啊!
5. 微服务有错吗?
微服务有错吗?
微服务从思维上来说,是正确无疑的,服务确实应该被 拆解成可维护可组合的过程。
微服务从技术上来说,就错到离谱了!
服务从本质上来说是分离的,越分离越复杂越难管理,
连接他们需要大量的调试与接线,运维他们需要大量的监控!
等等,可组合?插件是可以组合的,所以插件机制应得得非常广泛。
那么能不能微服务也能像插件一样自由组合呢?
不行,服务本质是来说是分离的,除非,我们无服务!
6.无服务是个什么鬼? 函数即服务!
既然需要组合,那么我们选择像插件一样去响应式加载功能,而不是作为一个独立的服务!
需要了就加载,服务状态各种异常需要监控,函数加载总不会有问题吧,毕竟函数是无状态的?
这次不行,下次重新来,一点问题都没有!
所以,有了函数即服务faas,我们可以像插件一样动态去扩展组合功能,而没有微服务的复杂度!因为我们是无状态的!
听你说得挺简单,那你做给我们瞧瞧 !
本来就很简单嘛。。。
为了体现它的伟大性,我们得用正式的函数式编程语言haskell进行讲解,其它的一样简单!
faas平台挺多,这里选择oracle的fnproject讲解! 因为其它的还没玩过。。。
其它的选择, openwhisk, openfaas。。。
商业的amazon lambda对于我这种开源爱好者,就忽略了。。。
二. 开战函数式-faas on docker!
- 构建docker函数
- 启动fn服务器
- 创建docker函数trigger
- 测试检查
是不是很简单呀!直接接着干!
1. 构建docker 函数
目前docker具有较好的封装性,所以大部分平台采用docker来封装函数单元。
docker函数要做什么呢? 接受标准输入,输出标准输出!
是不是很熟悉,shell不就是这玩意,用shell来做docker函数也完全没问题呀!
就是这么简单!
那我们简单用haskell写一个对数据进行base64编码解码的小服务吧。输出输出都用JSON,与rest标准保持一致。
其它语言也一样简单,最终达到的效果就是:
[larluo@larluo-nixos:~/my-repo]$ echo -n '{"action":"encode","content":"larluo"}' | docker run -i my-base64:latest
{"result": "bGFybHVvCg=="}
a. 创建haskell项目my-base64
[larluo@larluo-nixos:~/my-repo]$ stack new my-base64
......
All done.
[larluo@larluo-nixos:~/my-repo]$ cd my-base64/ && rm package.yaml
[larluo@larluo-nixos:~/my-repo/my-base64]$ cat stack.yaml | grep -v ^# | grep -v ^$
resolver: lts-12.10
packages:
- .
allow-newer: true
nix:
enable: true
[larluo@larluo-nixos:~/my-repo/my-base64]$ cat my-base64.cabal | grep -v '^--'
name: my-base64
version: 0.1.0.0
description: Please see the README on GitHub at <https://github.com/githubuser/my-base64#readme>
homepage: https://github.com/githubuser/my-base64#readme
bug-reports: https://github.com/githubuser/my-base64/issues
author: Author name here
maintainer: example@example.com
copyright: 2018 Author name here
license: BSD3
license-file: LICENSE
build-type: Simple
cabal-version: >= 1.10
extra-source-files:
ChangeLog.md
README.md
source-repository head
type: git
location: https://github.com/githubuser/my-base64
executable my-base64-exe
main-is: Main.hs
other-modules:
Paths_my_base64
hs-source-dirs:
app
ghc-options: -threaded -rtsopts -with-rtsopts=-N
build-depends:
base >=4.7 && <5
, aeson
, bytestring
, base64-bytestring
default-language: Haskell2010
default-extensions:
OverloadedStrings
[larluo@larluo-nixos:~/my-repo/my-base64]$ cat app/Main.hs
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleContexts #-}
module Main where
import Data.Text (Text (..))
import Data.Text.Encoding (encodeUtf8, decodeUtf8)
import Data.Aeson (decodeStrict, FromJSON, encode)
import Data.Maybe (fromMaybe)
import GHC.Generics
import qualified Data.ByteString as B
import qualified Data.HashMap.Strict as HM
import qualified Data.ByteString.Base64 as B64
data Request = Request { action :: Text, content :: Text} deriving (Generic, Show)
instance FromJSON Request
invoke :: Maybe Text -> Maybe Text -> Either Text Text
invoke (Just "encode") (Just content) = Right . decodeUtf8 . B64.encode . encodeUtf8 $ content
invoke (Just "decode") (Just content) = Right . decodeUtf8 . B64.decodeLenient . encodeUtf8 $ content
invoke _ _ = Left "action is null!"
main :: IO ()
main = do
req <- B.getContents
let reqJson = decodeStrict req:: Maybe Request
resp = invoke (action <$> reqJson) (content <$> reqJson)
mkSuccess message = show . encode $
(HM.fromList[("status", "success"), ("result", message)]::HM.HashMap Text Text)
mkError message = show . encode $
(HM.fromList[("status", "error"), ("message", message)]::HM.HashMap Text Text)
in putStrLn $ (either mkError mkSuccess resp)
{--
:{
invoke (Just "decode") $
either (const Nothing) (Just . id) $
(invoke (Just "encode") (Just "larluo"))
:}
--}
image.png
image.png
b. 构建docker镜像my-base64:latest
[larluo@larluo-nixos:~/my-repo/my-base64]$ cabal2nix . > docker.nix
[larluo@larluo-nixos:~/my-repo/my-base64]$ cat docker.nix
{ mkDerivation, aeson, base, base64-bytestring, bytestring, stdenv
, text, unordered-containers
}:
let
my-base64=mkDerivation {
pname = "my-base64";
version = "0.1.0.0";
src = ./.;
isLibrary = false;
isExecutable = true;
executableHaskellDepends = [
aeson base base64-bytestring bytestring text unordered-containers
];
homepage = "https://github.com/githubuser/my-base64#readme";
license = stdenv.lib.licenses.bsd3;
enableSharedExecutables = false;
enableLibraryProfiling = false;
doHaddock = false;
postFixup = "rm -rf $out/lib $out/nix-support $out/share/doc";
} ;
in
dockerTools.buildImage {
name = "my-base64" ;
tag = "latest" ;
config = {
Cmd = [ "${my-base64}/bin/my-base64-exe" ] ;
} ;
}
image.png
image.png
image.png
c. 测试docker函数
image.png2. 启动fn服务器
fnproject github网址: https://github.com/fnproject/fn
下载地址: https://github.com/fnproject/cli/releases
[larluo@larluo-nixos:~/my-repo/my-base64]$ fn --version
fn version 0.5.8
image.png
3. 创建docker函数trigger
[larluo@larluo-nixos:~/my-repo/my-base64]$ fn create app my-fn
Successfully created app: my-fn
[larluo@larluo-nixos:~/my-repo/my-base64]$ fn create function my-fn base64 my-base64:latest
Successfully created function: base64 with my-base64:latest
[larluo@larluo-nixos:~/my-repo/my-base64]$ fn create trigger --source /base64 --type http my-fn base64 base64
Successfully created trigger: base64
[larluo@larluo-nixos:~/my-repo/my-base64]$ fn list triggers my-fn
FUNCTION NAME TYPE SOURCE ENDPOINT
base64 base64 http /base64 http://localhost:8080/t/my-fn/base64
4. 测试检查
image.png是不是太简单了太好用了!
网友评论