当前位置:网站首页>Micro, m3o micro service series (III)

Micro, m3o micro service series (III)

2022-07-19 04:03:00 Bai,

This article focuses on micro Technology

summary

Micro It is a cloud native development platform . It consists of The server 、 Command line interface and service framework form , Enables you to build 、 function 、 Manage and use microservices . It is considered to be very much like a language specification , And will develop over time .

install

The environment is go+linux
go You can refer to my https://blog.csdn.net/weixin_45843419/article/details/124243479
Better install it in advance protocol-buffers Series of products , such as protoc protoc-gen-go protoc-gen-grpc-go

go get github.com/golang/protobuf/protoc-gen-go
go get github.com/micro/micro/v3/cmd/protoc-gen-micro
(install It's OK )

perhaps
 Insert picture description here

On a host ( Local installation )

go The way

Note that micro No go-micro,go-micro Now only in Asim Under your personal account

go get github.com/micro/micro/v3
 perhaps 
go install github.com/micro/micro/[email protected]

docker

dockre pull micro/micro

binary

wget -q  https://raw.githubusercontent.com/micro/micro/master/scripts/install.sh -O - | /bin/bash

perhaps
 Insert picture description here

kubernetes

Use helm The way

helm repo add micro https://micro.github.io/helm
helm install micro micro/micro

 uninstall 
helm uninstall micro
helm repo remove micro

The server

Microserver is the runtime of distributed system in cloud and other fields . It works as a set of services 、 Command line and service framework provide building blocks for distributed system development . In the sense that each component operates independently of each other but works together as a system , The server is much like a distributed operating system . This combination enables us to even use the microservice architecture pattern for the platform .

features

The server provides the following functions as built-in primitives for service development .
Authentication
Configuration
PubSub Messaging
Event Streaming
Service Discovery
Service Networking
Key-Value Storage
HTTP API Gateway
gRPC Identity Proxy
Web Dashboard

usage

To start the server , Just run

[[email protected] ~]# micro server
2022-07-16 11:56:30  file=server/server.go:88 level=info Starting server
2022-07-16 11:56:30  file=server/server.go:116 level=info Registering registry
2022-07-16 11:56:30  file=server/server.go:116 level=info Registering broker
2022-07-16 11:56:30  file=server/server.go:116 level=info Registering network
2022-07-16 11:56:30  file=server/server.go:116 level=info Registering runtime
2022-07-16 11:56:30  file=server/server.go:116 level=info Registering config
2022-07-16 11:56:30  file=server/server.go:116 level=info Registering store
2022-07-16 11:56:30  file=server/server.go:116 level=info Registering events
2022-07-16 11:56:30  file=server/server.go:116 level=info Registering auth
2022-07-16 11:56:30  file=server/server.go:116 level=info Registering proxy
2022-07-16 11:56:30  file=server/server.go:116 level=info Registering api
2022-07-16 11:56:30  file=server/server.go:116 level=info Registering web
2022-07-16 11:56:30  file=server/server.go:206 level=info Starting server runtime

Start the whole system and services , Include :8080 Upper http api and :8081 Upper grpc agent

help

[[email protected] ~]# micro --help
NAME:
   micro - A framework for cloud native development

   Use `micro [command] --help` to see command specific help.

USAGE:
   micro [global options] command [command options] [arguments...]

VERSION:
   v3.11.0

COMMANDS:
   auth      Manage authentication, accounts and rules
   call      Call a service e.g micro call greeter Say.Hello '{"name": "John"}'
   cli       Run the interactive CLI
   config    Manage configuration values
   env       Get/set micro cli environment
   gen       Generate a micro related dependencies e.g protobuf
   get       Get resources from micro
   health    Get the service health
   init      Generate a profile for micro plugins
   kill      Kill a service: micro kill [source]
   login     Interactive login flow.
   logout    Logout.
   logs      Get logs for a service e.g. micro logs helloworld
   network   Manage the micro service network
   new       Create a service template
   run       Run a service: micro run [source]
   server    Run the micro server
   service   Run a micro service
   services  List services in the registry
   stats     Query the stats of specified service(s), e.g micro stats srv1 srv2 srv3
   status    Get the status of services
   store     Commands for accessing the store
   stream    Create a service stream e.g. micro stream foo Bar.Baz '{"key": "value"}'
   update    Update a service: micro update [source]
   user      Print the current logged in user
   web       Run the web dashboard
   help, h   Shows a list of commands or help for one command

GLOBAL OPTIONS:
   -c value                          Set the config file: Defaults to ~/.micro/config.json [$MICRO_CONFIG_FILE]
   --env value, -e value             Set the environment to operate in [$MICRO_ENV]
   --profile value                   Set the micro server profile: e.g. local or kubernetes [$MICRO_PROFILE]
   --namespace value                 Namespace the service is operating in (default: "micro") [$MICRO_NAMESPACE]
   --auth_address value              Comma-separated list of auth addresses [$MICRO_AUTH_ADDRESS]
   --auth_id value                   Account ID used for client authentication [$MICRO_AUTH_ID]
   --auth_secret value               Account secret used for client authentication [$MICRO_AUTH_SECRET]
   --auth_public_key value           Public key for JWT auth (base64 encoded PEM) [$MICRO_AUTH_PUBLIC_KEY]
   --auth_private_key value          Private key for JWT auth (base64 encoded PEM) [$MICRO_AUTH_PRIVATE_KEY]
   --registry_address value          Comma-separated list of registry addresses [$MICRO_REGISTRY_ADDRESS]
   --registry_tls_ca value           Certificate authority for TLS with registry [$MICRO_REGISTRY_TLS_CA]
   --registry_tls_cert value         Client cert for TLS with registry [$MICRO_REGISTRY_TLS_CERT]
   --registry_tls_key value          Client key for TLS with registry [$MICRO_REGISTRY_TLS_KEY]
   --broker_address value            Comma-separated list of broker addresses [$MICRO_BROKER_ADDRESS]
   --events_tls_ca value             Certificate authority for TLS with events [$MICRO_EVENTS_TLS_CA]
   --events_tls_cert value           Client cert for TLS with events [$MICRO_EVENTS_TLS_CERT]
   --events_tls_key value            Client key for TLS with events [$MICRO_EVENTS_TLS_KEY]
   --broker_tls_ca value             Certificate authority for TLS with broker [$MICRO_BROKER_TLS_CA]
   --broker_tls_cert value           Client cert for TLS with broker [$MICRO_BROKER_TLS_CERT]
   --broker_tls_key value            Client key for TLS with broker [$MICRO_BROKER_TLS_KEY]
   --store_address value             Comma-separated list of store addresses [$MICRO_STORE_ADDRESS]
   --proxy_address value             Proxy requests via the HTTP address specified [$MICRO_PROXY]
   --report_usage                    Report usage statistics (default: true) [$MICRO_REPORT_USAGE]
   --service_name value              Name of the micro service [$MICRO_SERVICE_NAME]
   --service_version value           Version of the micro service [$MICRO_SERVICE_VERSION]
   --service_address value           Address to run the service on [$MICRO_SERVICE_ADDRESS]
   --config_secret_key value         Key to use when encoding/decoding secret config values. Will be generated and saved to file if not provided. [$MICRO_CONFIG_SECRET_KEY]
   --tracing_reporter_address value  The host:port of the opentracing agent e.g. localhost:6831 [$MICRO_TRACING_REPORTER_ADDRESS]
   --help, -h                        show help (default: false)
   --version, -v                     print the version (default: false)

Basic commands

function helloworld And check its status

micro env	# should point to local
micro run github.com/micro/services/helloworld # run helloworld
micro status 	# wait for status running
micro services	# should display helloworld

Invoke the service and verify the output

$ micro helloworld --name=John
{
    
        "msg": "Hello John"
}

Delete service

micro kill helloworld

Command line

Command line interface is the main way to interact with microserver . It is a simple binary file , You can interact with simple commands or interactive prompts .CLI Take all commands as pairs Micro Server's RPC Call to proxy . In many built-in commands , It will perform formatting and extra syntax work .( After running a service , The service specific command will also be generated )

Built in commands

Built in commands are system or configuration level commands used to interact with the server or change user configuration . in the majority of cases , This is a syntax sugar for the convenience of users . This is a well-known subset of commands .

signup
login
run
update
kill
services
logs
status
env
user

signup

Registration is an attempt to query “ register ” To register a new account , This is environment specific , You need to run the registration service . By default , This does not exist locally , It is recommended that users use admin/micro Credentials to manage the system . then , You can choose to be in micro/proto Medium operation conforms to proto Own registration service or use micro auth create account

For those who want to run their own microservers for others and may charge for licensing software , Registration is considered a command .

login

Log in to authenticate the user and send The credentials Stored locally in .micro/tokens In file . This invokes the micro authentication service to authenticate users based on existing accounts stored in the system . Login requires entering the user name and password at the prompt .

[[email protected] .micro]# pwd
/root/.micro
[[email protected] .micro]# ls
config.json  config_secret_key  id_rsa  id_rsa.pub  server  tokens

Dynamic command

Direction Micro CLI When issuing a command micro command, If the command is not a built-in command ,Micro You will try to parse the command dynamically and call the running service ( In fact, it is to call a service ). Use micro registry command , Although the registry is local by default Micro Set the Core services , But it's time to registry Commands are not built-in .( It's service. , But this service corresponds to micro The command of is not a built-in command )

Use –help sign , We can get information about the available subcommands and flags

[[email protected] .micro]# micro services
api
auth
broker
config
events
network
proxy
registry
runtime
store
web

[[email protected] .micro]# micro registry --help
NAME:
        micro registry

VERSION:
        latest

USAGE:
        micro registry [command]

COMMANDS:
        deregister
        getService
        listServices
        register
        watch

The commands listed are registry The endpoint of the service ( command )
To view the flags of subcommands ( Arguments to the command )

[[email protected] .micro]# micro registry getService --help
NAME:
        micro registry getService

USAGE:
        micro registry getService [flags]

FLAGS:
        --service string
        --options_ttl int64
        --options_domain string

If you are interested, please check registry Service source code , Look at it proto Definition of documents

message Options {
    
	int64 ttl = 1;
	string domain = 2;
}

message GetRequest {
    
	string service = 1;
	Options options = 2;
}

As the above definition tells us , request GetService Field of service On the top floor , Field ttl and domain be located options In structure . dynamic CLI The underlined flag name ( namely .options_domain) Map to the request field , Therefore, the following request JSON:

{
    
    "service": "serviceName",
    "options": {
    
        "domain": "domainExample"
    }
}

Equivalent to the following symbols :

micro registry getService --service=serviceName --options_domain=domainExample

User Config

Command line ~/.micro Local user configuration store in to store any form of state , For example, the saved environment 、 Token, etc . Unless otherwise stated , Otherwise, it will always try to read the user's configuration from here . At present, we will all To configure Stored in a file config.json, And any authentication token Store in a tokens In file .

config.json:

{
    "env":"local","local":{
    "current-user":"admin"},"micro":{
    "auth":{
    "local":{
    "expiry":"","refresh-token":"","token":""},"platform":{
    "expiry":"","refresh-token":"","token":""}}}}

env

Micro Joint and multi environment models are considered in the construction . Our development is usually done locally 、 Staging and production are mapped , therefore Micro Take this forward-looking view , And established the concept of environment , These environments are completely isolated microenvironments , Can pass CLI Interact with it .

see env

[[email protected] .micro]# micro env
* local      127.0.0.1:8081    Local running Micro Server
  platform   proxy.m3o.com     Cloud hosted Micro Platform

There are two built-in environments (local Default ) and m3o Specific products ; platform . These exist for convenience and development speed . You can create other environments micro env add [name] [host:port]. The default environment address is **:8081** Micro agent of .(grpc)

add to env

This command micro env --help Provides a summary of usage . Here is an example of how to add an environment .

[[email protected] .micro]# micro env --help
NAME:
   micro env - Get/set micro cli environment

USAGE:
   micro env command [command options] [arguments...]

COMMANDS:
   get      Get the currently selected environment
   set      Set the environment to use for subsequent commands e.g. micro env set dev
   add      Add a new environment e.g. micro env add foo 127.0.0.1:8081
   del      Delete an environment from your list e.g. micro env del foo
   help, h  Shows a list of commands or help for one command

OPTIONS:
   --help, -h  show help (default: false)

[[email protected] .micro]# micro env add foobar example.com
[[email protected] .micro]# micro env
  foobar     example.com
* local      127.0.0.1:8081    Local running Micro Server
  platform   proxy.m3o.com     Cloud hosted Micro Platform

Set up env

[[email protected] .micro]# micro env set foobar
[[email protected] .micro]# micro env
* foobar     example.com
  local      127.0.0.1:8081    Local running Micro Server
  platform   proxy.m3o.com     Cloud hosted Micro Platform

Log in to the environment

Each environment is actually an independent deployment , Have your own authentication 、 Storage, etc . So every environment needs to register and login . At this point we have to be in example Use micro login. If you do not have environmental credentials , You must ask the administrator .( Sign in paltform In the same way )

service

Micro Built as a distributed operating system utilizing the microservice architecture pattern .

Micro Server List of services provided . Each service is considered as a building block primitive for platform and distributed system development . For each proto Interfaces can be found in micro/proto/auth:https://github.com/micro/micro/blob/master/proto/auth/auth.proto Find ,Go library 、 Client and server implementations can be implemented in micro/service/auth:https://github.com/micro/micro/tree/master/service/auth Find .

micro All the source code of :https://github.com/micro/micro

micro/proto/auth/auth.proto


syntax = "proto3";

package auth;

option go_package = "github.com/micro/micro/v3/proto/auth;auth";

service Auth {
    
	rpc Generate(GenerateRequest) returns (GenerateResponse) {
    };
	rpc Inspect(InspectRequest) returns (InspectResponse) {
    };		
	rpc Token(TokenRequest) returns (TokenResponse) {
    };
}

service Accounts {
    
	rpc List(ListAccountsRequest) returns (ListAccountsResponse) {
    };
	rpc Delete(DeleteAccountRequest) returns (DeleteAccountResponse) {
    };
	rpc ChangeSecret(ChangeSecretRequest) returns (ChangeSecretResponse) {
    };
}

service Rules {
    
	rpc Create(CreateRequest) returns (CreateResponse) {
    };
	rpc Delete(DeleteRequest) returns (DeleteResponse) {
    };
	rpc List(ListRequest) returns (ListResponse) {
    };
}

message ListAccountsRequest {
    
	Options options = 1;
}

message ListAccountsResponse {
    
	repeated Account accounts = 1;
}

message DeleteAccountRequest {
    
	string id = 1;
	Options options = 2;
}

message DeleteAccountResponse {
    }

message Token {
    
	string access_token = 1;
	string refresh_token = 2;
	int64 created = 3;
	int64 expiry = 4;
}

message Account {
    
	string id = 1;
	string type = 2;
	map<string, string> metadata = 4;
	repeated string scopes = 5;
	string issuer = 6;
	string secret = 7;
	string name = 8;
}

message Resource{
    
	string name = 1;
	string type = 2;
	string endpoint = 3;
}

message GenerateRequest {
    
	string id = 1;
	map<string, string> metadata = 3;
	repeated string scopes = 4;
	string secret = 5;
	string type = 6;
	string provider = 7;
	Options options = 8;
	string name = 9;
}

message GenerateResponse {
    
	Account account = 1;
}

message GrantRequest {
    
	string scope = 1;
	Resource resource = 2;
	Options options = 3;
}

message GrantResponse {
    }

message RevokeRequest {
    
	string scope = 1;
	Resource resource = 2;
	Options options = 3;
}

message RevokeResponse {
    }

message InspectRequest {
    
	string token = 1;
	Options options = 2;
}

message InspectResponse {
    
	Account account = 1;
}

message TokenRequest {
    
	string id = 1;
	string secret = 2;
	string refresh_token = 3;
	int64 token_expiry = 4;
	Options options = 5;
}

message TokenResponse {
    
	Token token = 1;
}

enum Access {
    
	UNKNOWN = 0;
	GRANTED = 1;
	DENIED = 2;
}

message Rule {
    
	string id = 1;
	string scope = 2;
	Resource resource = 3;
	Access access = 4;
	int32 priority = 5;
}

message Options {
    
	string namespace = 1;
}

message CreateRequest {
    
	Rule rule = 1;
	Options options = 2;
}

message CreateResponse {
    }

message DeleteRequest {
    
	string id = 1;
	Options options = 2;
}

message DeleteResponse {
    }

message ListRequest {
    
	Options options = 2;
}

message ListResponse {
    
	repeated Rule rules = 1;
}

message ChangeSecretRequest{
    
	string id = 1;
	string old_secret = 2;
	string new_secret = 3;
	Options options = 4;
}

message ChangeSecretResponse{
    }

API

API Service is a http API gateway , It acts as a public entry point and will http/json Convert to RPC.( Originally, it was only accepted rpc, But in today's communications http Or most , So make a API Gateway support http, I believe that the future will move towards definition API Standard protocol protocol buffer and grpc The era of communication )

Concept

tiny API It is a common entry point for all external access services , For the front end 、 Use of mobile devices .API Accept http/json Request and use path based routing to resolve back-end services . It will request Convert to gRPC And forward it appropriately . The idea here is to focus on back-end microservices , And put all the content together as a single front-end API.( use gin+vue To understand the front-end and back-end api that will do )

usage

By default local Environment ,API The address is 127.0.0.1:8080. Every running service can pass this API call .(8080 yes http)

[[email protected] services]# curl http://127.0.0.1:8080
{
    "version": "v3.11.0"}

Call the registry service , And use the listing function of the registry :

[[email protected] services]# curl http://127.0.0.1:8080/registry/listServices
{
    "id":"registry.Registry.ListServices","code":401,"detail":"an account is required","status":"Unauthorized"}

The format is

curl http://127.0.0.1:8080/[servicename]/[endpointName]

Parameters can be passed as query parameters

[[email protected] services]# curl http://127.0.0.1:8080/helloworld/call?name=yy
{
    "message":"Hello yy"}

or JSON Text :

[[email protected] services]# curl -XPOST --header "Content-Type: application/json" -d '{"name":"yy"}' http://127.0.0.1:8080/helloworld/call
{
    "message":"Hello yy"}

( Note that sometimes the service just starts ,curl Not so fast to visit , Need to wait )

To call API Specifies the namespace when ,Micro-Namespace You can use headers (http Head):

curl -H "Micro-Namespace: foobar" http://127.0.0.1:8080/helloworld/call?name=yy

To invoke a non-public service or endpoint,Authorization You can use headers :

MICRO_API_TOKEN=`micro user token`
curl -H "Authorization: Bearer $MICRO_API_TOKEN" http://127.0.0.1:8080/helloworld/call?name=yy

authentication

auth Services provide authentication and authorization .

summary

auth Service storage account and access rules . It's for Micro All authentication and authorization in the runtime provide a single source of facts . Every service and user needs an account to operate . When the runtime starts the service , An account will be generated for it . Microload rules are the core services and services that run regularly , And manage access to its resources according to each request .

usage

about CLI Order help , Please use micro auth --helpauth Subcommand help , for example micro auth create --help.

Sign in

To log in to the server , Just do the following

$ micro login
Enter username: admin
Enter password: 
Successfully logged in.

The password is micro
Default to local micro server.

The rules

Rules determine the resources that users can access . The default rules are as follows :

[[email protected] services]# micro auth list rules
ID              Scope                   Access          Resource                Priority
default         <public>                GRANTED         *:*:*                   0

This rule , Output default All services in can be called

If we want to prevent unauthorized users from calling our services , We can create the following rules

# This command creates a rule that enables only logged in users to call the micro server
micro auth create rule  --access=granted --scope='*' --resource="*:*:*" onlyloggedin
# Create the rule which allows us to login
micro auth create rule --access=granted --resource="service:auth:*" auth-public

service Type of service , selected auth service , All the orders under it 

And delete the default . ad locum , The scope is the same as we used to execute a When you see * The scope of is obviously different :micro auth list rules

[[email protected] services]# micro auth list rules
ID                      Scope                   Access          Resource                Priority
auth-public             <public>                GRANTED         service:auth:*          0
onlyloggedin            *                       GRANTED         *:*:*                   0
default                 <public>                GRANTED         *:*:*                   0

Delete the default rule :

# This command deletes the 'default' rule - the rule which enables anyone to call the 'micro server'.
$ micro auth delete rule default
Rule deleted

Try it again curl Our service :

[[email protected] services]# curl 127.0.0.1:8080/helloworld/call?name=Alice
{
    "id":"helloworld","code":401,"detail":"Unauthorized call made to helloworld:Helloworld.Call","status":"Unauthorized"}

onlyloggedin The rules are in effect . We can still use tokens to invoke services , Verify authorization :

$ token=$(micro user token)
# Locally:
[[email protected] services]# curl --header "Authorization: Bearer $token" 127.0.0.1:8080/helloworld/call?name=yy
{
    "message":"Hello yy"}

--header Information such as verification is usually written in the request header 

( Please note that , The life cycle of the token is limited , therefore $ token=$(micro user token) The bank must be republished from time to time , Or you must use the command inline .)

Account

Auth The concept of service support account . Used to access the micro server The default account for is the administrator account .

[[email protected] services]# micro auth list accounts
ID              Name            Scopes          Metadata
admin           admin           admin           created=1657689442

We can create accounts for teammates and colleagues micro auth create account

[[email protected] services]# micro auth create account --scopes=admin yy
Account created: {
    "id":"yy","type":"user","issuer":"micro","metadata":{
    "created":"1657958447"},"scopes":["admin"],"secret":"cbbe8671-2988-409e-a438-cc15f7799e3c","name":"yy"}

The newly created account can micro login By using id And password cbbe8671-2988-409e-a438-cc15f7799e3c To use .

Broker

A broker is a message broker that asynchronously publishes and subscribes to messages .

summary

The agent for pubsub Messaging provides a simple abstraction . It focuses on the simple semantics of send and discard asynchronous communication . The goal here is to provide a pattern for asynchronous notification , Some updates or events have occurred , But you don't need persistence . Clients and servers build the ability to publish on one side and subscribe on the other . The agent does not provide message sorting guarantee .

Although services are usually called by name , But messaging focuses on topics that can have multiple publishers and subscribers . The proxy is on the client side of the service / Abstract in the server , This includes message encoding / decode , So you don't have to spend all your time marshalling .

Customer

The client contains Publish Get the original message 、 The method of coding it and publishing it to the agent on a given topic . It gets metadata from the client context , And include them as headers of messages containing content types , So that subscribers know how to deal with it .

The server

The server supports a Subscribe Method , This method allows you to register the handler as if it were a request . In this way , We can mirror the behavior of the handler and deserialize the message when consumed from the agent . In this model , The server handles the connection with the agent 、 subscribe 、 Consume and perform your subscriber functions .

usage

Publisher:

bytes, err := json.Marshal(&Healthcheck{
    
	Healthy: true,
	Service: "foo",
})
if err != nil {
    
	return err
}

return broker.Publish("health", &broker.Message{
    Body: bytes})

Subscriber:

handler := func(msg *broker.Message) error {
    
	var hc Healthcheck
	if err := json.Unmarshal(msg.Body, &hc); err != nil {
    
		return err
	}
	
	if hc.Healthy {
    
		logger.Infof("Service %v is healthy", hc.Service)
	} else {
    
		logger.Infof("Service %v is not healthy", hc.Service)
	}

	return nil
}

sub, err := broker.Subscribe("health", handler)
if err != nil {
    
	return err
}

config( To configure )

config Services provide dynamic configuration for services
Config It can be stored and loaded separately into the application itself , Used to configure business logic 、api Key, etc . We read and write these as key value pairs , Also support JSON Nesting of values .config The interface also supports storage by defining the key as an option when writing a value secret.

usage

Suppose we have a service call helloworld, We want to read the configuration data . First , We have to use cli Insert the data . Configuration data can be organized in different “ route ” Next . It is a good convention to save all configuration data belonging to the service under the top-level path segment matching the service name :

[[email protected] services]# micro config set helloworld.somekey hello
[[email protected] services]# micro config get helloworld.somekey
hello
[[email protected] services]# micro config get helloworld
{
    "somekey":"hello"}

You can also save another key and use the dot symbol to read all values at once :

[[email protected] services]# micro config set helloworld.someotherkey 'Hi there!'
[[email protected] services]# micro config get helloworld
{
    "somekey":"hello","someotherkey":"Hi there!"}

It can be seen that ,config( By default ) Store the configuration data as JSON. We can save any type :

[[email protected] services]# micro config set helloworld.someboolkey true
[[email protected] services]# micro config get helloworld
{
    "someboolkey":true,"somekey":"hello","someotherkey":"Hi there!"}

Explore the advantages of dot symbols :

[[email protected] services]# micro config set helloworld.keywithsubs.subkey1 'So easy!'
[[email protected] services]# micro config get helloworld
{
    "keywithsubs":{
    "subkey1":"So easy!"},"someboolkey":true,"somekey":"hello","someotherkey":"Hi there!"}
[[email protected] services]# micro config del helloworld.someotherkey
[[email protected] services]# micro config get helloworld
{
    "keywithsubs":{
    "subkey1":"So easy!"},"someboolkey":true,"somekey":"hello"}

You can not only delete leaf level keys , You can also delete the top key :

[[email protected] services]# micro config del helloworld.keywithsubs
[[email protected] services]# micro config get helloworld
{
    "someboolkey":true,"somekey":"hello"}

secret

config In many fields of knowledge , Often accompanied by this one secret, Simply speaking, it is a clear text , An encryption ,secret More secure , Prevent leakage

[[email protected] services]# micro config set --secret helloworld.hushkey "Very secret stuff"
[[email protected] services]# micro config get helloworld.hushkey
[secret]
[[email protected] services]# micro config get --secret helloworld.hushkey
Very secret stuff
[[email protected] services]# micro config get helloworld
{
    "hushkey":"[secret]","someboolkey":true,"somekey":"hello"}
[[email protected] services]# micro config get --secret helloworld
{
    "hushkey":"Very secret stuff","someboolkey":true,"somekey":"hello"}

even to the extent that bool Or digital values can also be saved as secrets ,[secret] Unless solution ​​ The secret , Otherwise they will be displayed as string constants :

[[email protected] services]# micro config set --secret helloworld.hush_number_key 42
[[email protected] services]# micro config get helloworld
{
    "hush_number_key":"[secret]","hushkey":"[secret]","someboolkey":true,"somekey":"hello"}
[[email protected] services]# micro config get --secret helloworld
{
    "hush_number_key":42,"hushkey":"Very secret stuff","someboolkey":true,"somekey":"hello"}

Service Framework

Setting configuration values is as simple as accessing from a service

package main

import (
	"fmt"
	"time"

	"github.com/micro/micro/v3/service"
	"github.com/micro/micro/v3/service/config"
)

type keyConfig struct {
    
	Subkey  string `json:"subkey"`
	Subkey1 int    `json:"subkey1"`
}

type conf struct {
    
	Key keyConfig `json:"key"`
}

func main() {
    
	go func() {
    
		for {
    
			time.Sleep(time.Second)
			val, err := config.Get("key.subkey")
			fmt.Println("Value of key.subkey: ", val.String(""), err)

			val, err = config.Get("key", config.Secret(true))
			if err != nil {
    
				fmt.Println(err)
			}
			c := conf{
    }
			err = val.Scan(&c.Key)
			fmt.Println("Value of key.subkey1: ", c.Key.Subkey1, err)
		}
	}()

	// run the service
	service.Run()
}

The above service will print every second key.subkey Sum value .key.subkey By passing in config.Secret(true) Options , We tell config Decrypt for us secret value , Be similar to –secretCLI sign .

config Interfaces not only specify Get Set and Delete Access value , Also specify some convenient functions in the interface Value.

It is worth noting that ,String Int And other methods will try their best to force the type , namely . If the saved value is a string ,Int Will try to parse it . however , This does not apply to those used in the background Scan Method ,json.Unmarshal We all know that we will fail in case of type mismatch .

Get In all cases , Should return a non nil Value, So even Get There is an error ,Value.Int() Other operations should not panic .

Advanced concepts

Merge configuration values

When using CLI Save a valid JSON Mapped string , It will be extended to save as the correct mapping structure , Instead of strings , namely

[[email protected] test]# micro config set helloworld '{"a":"val1","b":"val2"}'
[[email protected] test]# micro config get helloworld
{
    "a":"val1","b":"val2","hush_number_key":"[secret]","hushkey":"[secret]","someboolkey":true,"somekey":"hello"}
[[email protected] test]# micro config get helloworld.a
val1
type conf struct {
    
	A string `json:"a"`
	B string `json:"b"`
}

c1 := conf{
    "val1", "val2"}
config.Set("key", c1)

v, _ := config.Get("key")
c2 := &conf{
    }
v.Scan(c2)
// c1 and c2 should be equal

 Or use the following example 

$ micro config del helloworld
$ micro config set helloworld '{"a":1}'
$ micro config get helloworld
{
    "a":1}
$ micro config set helloworld '{"b":2}'
$ micro config get helloworld
{
    "a":1,"b":2}

micro server Encryption key

By default , If not specified ,micro server The encryption key will be generated and saved to ~/.micro/config_secret_key. This applies to local zero dependency usage , But it is not applicable to production .
To specify the key for the microserver , Environment variables must be specified MICRO_CONFIG_SECRET_KEY Or flag key config_secret_key

error

errors Packages are most common HTTP The status code provides the error type , for example BadRequest、InternalServerError etc. . Suggest to RPC Use one of these errors when the handler returns an error . If any other type of error is returned , Consider it InternalServerError.

Micro API Will detect these error types , And will use them to determine the response status code . for example , If your handler returns errors.BadRequest,API Will return 400 The status code . If no error is returned ,API The default will be returned 200 Status code .

Error codes are also used when processing retries . If your service returns 500 (InternalServerError) or 408 (Timeout), Then the client will retry the request . Other status codes are treated as client errors , Won't try again .

usage

import (
	"github.com/micro/micro/v3/service/errors"
)

func (u *Users) Read(ctx context.Context, req *pb.ReadRequest, rsp *pb.ReadResponse) error {
    
	if len(req.Id) == 0 {
    
		return errors.BadRequest("users.Read.MissingID", "Missing ID")
	}

	...
}

Activities

Event service is a service for event flow and persistent storage of events .

summary

Event flow and pubsub Messaging differs in that it provides an orderly flow of events , It can be consumed or replayed from any given point in the past . If you use Kafka Experience , Then you will know that it is basically a distributed log , It allows you to read files from different offsets and stream them .

Event services and interfaces provide event flow abstractions for writing and reading events and consuming from any given offset . It also supports proper acknowledgement and error handling .

The difference between event and proxy is that it provides a fixed event type , You can fill in the details and handle the decoding of the message body by yourself . Events can have a large payload , So don't want to decode unnecessarily , You may just want to hand over to the location of the storage system .

function

events The package has two parts :Stream and Store.Stream For publishing and consuming messages on a given topic . for example , In the chat application , A user will post messages , And another user will subscribe . If you need to retrieve messages later , You can use Subscribe Function and pass Offset Option to replay them , Or use Read The function lists them .

func Publish(topic string, msg interface{}, opts …PublishOption) error
Publish The function has two required parameters : Topics and messages . The theme is the channel you post the event to , For chat applications , This will be chat ID. Messages are any structure , For example, messages sent to chat . When the subscriber receives the event , They will be able to ungroup this object .Publish There are two supported options ,WithMetadata Used to pass keys / It's worth it ,WithTimestamp Used to override the default timestamp of the event .

func Consume(topic string, opts ...ConsumeOption) (<-chan Event, error)
Consume  The function is used to consume events . For chat applications , The client will chat  ID  Deliver as a theme , Any event published to the stream will be sent to the event channel .Event  There is one  Unmarshal  function , Can be used to access message payload , As shown below :

for {
    
	evChan, err := events.Consume(chatID)
	if err != nil {
    
		logger.Error("Error subscribing to topic %v: %v", chatID, err)
		return err
	}
	for {
    
		ev, ok := <- evChan
		if !ok {
    
			break
		}
		var msg Message
		if err :=ev.Unmarshal(&msg); err != nil {
    
			logger.Errorf("Error unmarshaling event %v: %v", ev.ID, err)
			return err
		}
		logger.Infof("Received message: %v", msg.Subject)
	}
}

The Internet

Network is a service to service network used to request agents

summary

Network provides services for service network abstraction , Including agents 、 Authentication 、 Tenant isolation , And use the existing service discovery and routing system . The goal here is not to provide a service grid , Instead, it provides a higher-level routing control plane , Access can be managed based on existing systems . The network requires every service to point to it , Make a clear choice for routing .

Under the cover cilium、envoy And other service grid tools can be used to provide a highly elastic grid .

Registration

The registry is the service directory and endpoint resource manager

summary

The service registry is for all services and their API Provide a single source of facts . All services at startup will register their names in the registration service 、 edition 、 Address and endpoint . then , They will re register regularly to “ heartbeat ”, Otherwise, according to the predefined 90 second TTL Be overdue .

The goal of the registry is to allow users to explore API And the service .

The simplest form of access is the commands listed below for services .

micro services

usage

Get the information about the service returned by the service endpoint , Including the response parameters of the endpoint :

$ micro registry getService --service=helloworld
{
    
	"services": [
		{
    
			"name": "helloworld",
			"version": "latest",
			"metadata": {
    
				"domain": "micro"
			},
			"endpoints": [
				{
    
					"name": "Helloworld.Call",
					"request": {
    
						"name": "CallRequest",
						"type": "CallRequest",
						"values": [
							{
    
								"name": "name",
								"type": "string",
								"values": []
							}
						]
					},
					"response": {
    
						"name": "CallResponse",
						"type": "CallResponse",
						"values": [
							{
    
								"name": "message",
								"type": "string",
								"values": []
							}
						]
					},
					"metadata": {
    }
				},
				{
    
					"name": "Helloworld.Stream",
					"request": {
    
						"name": "Context",
						"type": "Context",
						"values": []
					},
					"response": {
    
						"name": "Stream",
						"type": "Stream",
						"values": []
					},
					"metadata": {
    
						"stream": "true"
					}
				}
			],
			"nodes": [
				{
    
					"id": "helloworld-3a0d02be-f98e-4d9d-a8fa-24e942580848",
					"address": "192.168.43.193:34321",
					"port": "0",
					"metadata": {
    
						"broker": "service",
						"protocol": "grpc",
						"registry": "service",
						"server": "grpc",
						"transport": "grpc"
					}
				}
			],
			"options": {
    
				"ttl": "0",
				"domain": ""
			}
		}
	]
}

function

summary

The runtime service is responsible for running 、 Update and delete binaries or containers ( Depends on the platform - For example, local binary files 、k8s Upper pod etc. ) And its log .

Operation service

The micro run The command tells the runtime to run the service . The following are all valid examples :

micro run github.com/micro/services/helloworld
micro run .  # deploy local folder to your local micro server
micro run ../path/to/folder # deploy local folder to your local micro server
micro run helloworld # deploy latest version, translates to micro run github.com/micro/services/helloworld or your custom base url
micro run [email protected] # deploy certain version
micro run [email protected]  # deploy certain branch
micro run --name helloworld .

Specify the service name

The service name is derived from the directory name of the application . If you want to overwrite it , Please specify –name sign .

micro run --name helloworld github.com/myorg/helloworld/server

Run local folder

If the first parameter is an existing local folder , namely

micro run ./foobar

then CLI Upload this folder to the runtime , Run this folder at run time .

Run one git Source

If micro run The first parameter points to a git The repository ( Whether in the GitHub、GitLab、Bitbucket Or any other provider ), Then the address will be sent to the runtime , The runtime downloads the code and runs it .

The use of reference

@ The reference is part of the first parameter passed after the run flag . It can be the branch name ( No reference means version latest be equal to git In terms of master) Or submit hash .

After passing in the branch name , The latest submission of the running code .

List runtime objects

The micro status The command lists everything that runs in the runtime :

$ micro status
NAME		VERSION	SOURCE					STATUS	BUILD	UPDATED		METADATA
helloworld	latest	github.com/micro/services/helloworld	running	n/a	20h43m45s ago	owner=admin, group=micro

If there is an error , Then the output includes errors . image micro kill,micro logs Orders like that ,micro update Accept the returned name micro status As the first parameter ( Instead of possibly different service names ).

Update service

The micro update The command causes the runtime to pull the latest commit in the branch and restart the service .

For native code , It does not require a runtime name ( from return micro status), It's a local path . For submitting hash deployment , It just restarts the service .

Example :micro update helloworld, micro update [email protected], micro update [email protected], micro update ./helloworld

Delete service

The micro kill Command to delete the runtime object from the runtime . It accepts by . Return the name of micro status.

Example :micro kill helloworld

journal

The micro logs The command displays the log of the runtime object . It accepts by . Return the name of micro status.

The -f Flags make the command stream record continuously .

Example :micro logs helloworld, micro logs -f helloworld

store

Key value storage supporting key sorting can be used to build complex applications . Because its function set is very limited , Key value storage can usually be easily and reliably extended , It is usually linear with the number of nodes added .

This scalability comes at the cost of the inconvenience and mental overhead of writing business logic . Use cases that are important for linear scalability , This trade-off is preferred .

Press ID Inquire about

Press ID Reading is a typical work of key value storage . Store data to enable this ID Just like in any other database :

# entries designed for querying "users by id"
KEY         VALUE
id1         {
    "id":"id1", "name":"Jane", "class":"firstGrade",   "avgScore": 98}
id2         {
    "id":"id2", "name":"Alice","class":"secondGrade",  "avgScore": 92}
id3         {
    "id":"id3", "name":"Joe",  "class":"secondGrade"   "avgScore": 89}
id4         {
    "id":"id4", "name":"Betty","class":"thirdGrade"    "avgScore": 94}
import "github.com/micro/micro/v3/service/store"

records, err := store.Read("id1")
if err != nil {
    
	fmt.Println("Error reading from store: ", err)
}
fmt.Println(records[0].Value)
// Will output {
    "id":"id1", "name":"Jane", "class":"firstGrade",   "avgScore": 98}

Given this data structure , We can do two queries :
1. Read the given key ( obtain “id1”, obtain “id2”)
2. If the bonds are ordered , We can ask after a key X Entries ( stay “id2” And then get 3 Entries )

Finding values in an ordered set is probably the simplest task we can ask the database . The problem with the above data structure is , inquiry “ Press “id2” It is not very useful to find the key in the following order . To enable other types of queries , Data must be saved using different keys .

Consider the query , We can copy the data to another table named after the query we want to execute :

Query by equal field values

# entries designed for querying "users by class"
KEY             VALUE
firstGrade/id1  {
    "id":"id1", "name":"Jane", "class":"firstGrade",   "avgScore": 98}
secondGrade/id2 {
    "id":"id2", "name":"Alice","class":"secondGrade",  "avgScore": 92}
secondGrade/id3 {
    "id":"id3", "name":"Joe",  "class":"secondGrade"   "avgScore": 89}
thirdGrade/id4  {
    "id":"id4", "name":"Betty","class":"thirdGrade"    "avgScore": 94}
import "github.com/micro/micro/v3/service/store"

records, err := store.Read("", store.Prefix("secondGrade"))
if err != nil {
    
	fmt.Println("Error reading from store: ", err)
}
fmt.Println(records[0].Value)
// Will output
// secondGrade/id2 {
    "id":"id2", "name":"Alice","class":"secondGrade",  "avgScore": 92}
// secondGrade/id3 {
    "id":"id3", "name":"Joe",  "class":"secondGrade"   "avgScore": 89}

Because the key is ordered , So the return is very simple , Let's say “ All second graders ”. The key value storage support of key value sorting is similar to “ Key start / The key has a prefix ” Query for . For second graders , List all to “ Key start secondGrade” Records of will be returned to all second graders .

This query is basically a field equals to, Because we basically did a field class == secondGrade. however , If we model the data appropriately , We can also use the ordered property of keys to perform value comparison queries , namely field avgScores is less than 90 etc. :field AvgScores is between 90 and 95

Query field value range

# entries designed for querying "users by avgScore"
KEY         VALUE
089/id3     {
    "id":"id3", "name":"Joe",  "class":"secondGrade"   "avgScore": 89}
092/id2     {
    "id":"id2", "name":"Alice","class":"secondGrade",  "avgScore": 92}
094/id4     {
    "id":"id4", "name":"Betty","class":"thirdGrade"    "avgScore": 94}
098/id1     {
    "id":"id1", "name":"Jane", "class":"firstGrade",   "avgScore": 98}

It's worth remembering , Key is a string , And they are arranged in dictionary order . For this reason , When processing number values , We must ensure that they are properly preset to the same length .

Table usage

Microservices can only access one Store surface . This means that all keys are in the same namespace and may conflict . A very useful pattern is to separate items according to the expected query pattern , It's the one above “users by id” and users by class records:

KEY         VALUE
# entries designed for querying "users by id"
usersById/id1         		{
    "id":"id1", "name":"Jane", "class":"firstGrade",   "avgScore": 98}
usersById/id2         		{
    "id":"id2", "name":"Alice","class":"secondGrade",  "avgScore": 92}
usersById/id3         		{
    "id":"id3", "name":"Joe",  "class":"secondGrade"   "avgScore": 89}
usersById/id4         		{
    "id":"id4", "name":"Betty","class":"thirdGrade"    "avgScore": 94}
# entries designed for querying "users by class"
usersByClass/firstGrade/id1  {
    "id":"id1", "name":"Jane", "class":"firstGrade",   "avgScore": 98}
usersByClass/secondGrade/id2 {
    "id":"id2", "name":"Alice","class":"secondGrade",  "avgScore": 92}
usersByClass/secondGrade/id3 {
    "id":"id3", "name":"Joe",  "class":"secondGrade"   "avgScore": 89}
usersByClass/thirdGrade/id4  {
    "id":"id4", "name":"Betty","class":"thirdGrade"    "avgScore": 94}

It's different go The example becomes :

import "github.com/micro/micro/v3/service/store"

const idPrefix = "usersById/"

records, err := store.Read(idPrefix + "id1")
if err != nil {
    
	fmt.Println("Error reading from store: ", err)
}
fmt.Println(records[0].Value)
// Will output {
    "id":"id1", "name":"Jane", "class":"firstGrade",   "avgScore": 98}
import "github.com/micro/micro/v3/service/store"

const classPrefix = "usersByClass/"

records, err := store.Read("", store.Prefix(classPrefix + "secondGrade"))
if err != nil {
    
	fmt.Println("Error reading from store: ", err)
}
fmt.Println(records[0].Value)
// Will output
// secondGrade/id2 {
    "id":"id2", "name":"Alice","class":"secondGrade",  "avgScore": 92}
// secondGrade/id3 {
    "id":"id3", "name":"Joe",  "class":"secondGrade"   "avgScore": 89}

Metadata

Metadata / Headers can be passed through RPC Context passing in call . Context / Metadata packages allow services to get and set metadata in context .Micro API The request header is added to the context , for example , If you're right “localhost:8080/users/List” Of API Set “Foobar” header , Then the user service can access this value , As shown below :

import (
	"context"
	"github.com/micro/micro/v3/service/context/metadata"
)

...

func (u *Users) List(ctx context.Context, req *pb.ListRequest, rsp *pb.ListResponse) error {
    
	val, ok := metadata.Get(ctx, "Foobar")
	if !ok {
    
		return fmt.Errorf("Missing Foobar header")
	}

	fmt.Println("Foobar header was set to: %v", val)
	return nil
}
 Again , The client can use  metadata.Set  Function sets metadata in context , As shown below :

func (u *Users) List(ctx context.Context, req *pb.ListRequest, rsp *pb.ListResponse) error {
    
	newCtx := metadata.Set(ctx, "Foobar", "mycustomval")
	fRsp, err := u.foosrv.Call(newCtx, &foosrv.Request{
    })
	...
}

Network dashboard

stay localhost:8082 Of Web View and query services in the browser .Web The dashboard is a simple layer at the top of the system , For visualizing services and their endpoints . Besides , It also generates dynamic forms for easy query .

plug-in unit

Micro It's based on Go Pluggable architecture of interface type . Plug ins can exchange the underlying infrastructure .

summary

Micro It's pluggable , This means that the implementation of each module can be replaced according to requirements . Plug ins should be applied to microservers rather than directly to services , This is done so that the underlying infrastructure can be changed , And the code required for your service is changed to zero .

An example of a pluggable interface is a store . Local micro File storage will be used to persist data , It's great , Because it requires zero dependency , And still provide persistence between restarts . Run in the test suite micro when , It can be swapped to a more suitable memory cache , Because it provides consistency between operations . In production , It can be replaced with a separate infrastructure as needed , for example cockroachdb or etcd.

Let's give you an example , Our service wants to load data from the store . Our service will call store.Read(userPrefix + userID) Load values , Behind the scenes, this will perform a RPC To storage services , This in turn calls configuring for the server store.Read The current DefaultStore Realization .

brief introduction

The configuration file is used to configure multiple plug-ins at a time .Micro Some configuration files are included out of the box , for example “local”、“kubernetes” and “test”. These configuration files can be found in Find profile/profile.go. You can use env var take micro Configure to use one of these configuration files MICRO_PROFILE, for example :MICRO_PROFILE=test micro server. The default configuration file used is “ Local ”.

Write personal data

The configuration file should be created as a package in the configuration file directory . Let's create profile/staging/staging.go. The following example shows how to override Local The default storage of configuration files is realized by using memory :

// Package staging configures micro for a staging environment
package staging

import (
	"github.com/urfave/cli/v2"

	"github.com/micro/micro/v3/profile"
	"github.com/micro/micro/v3/service/store"
	"github.com/micro/micro/v3/service/store/memory"
)

func init() {
    
	profile.Register("staging", staging)
}

var staging = &profile.Profile{
    
	Name: "staging",
	Setup: func(ctx *cli.Context) error {
    
		profile.Local.Setup(ctx)
		store.DefaultStore = memory.NewStore()
		return nil
	},
}
pushd profile/staging
go mod init github.com/micro/micro/profile/staging
go mod tidy
popd

Use a custom profile
You can load a custom configuration file with several commands , First add the replacement to your go mod, Indicates that it should look for your custom profile in the profile directory :

go mod edit -replace github.com/micro/micro/profile/staging/v3=./profile/staging
go mod tidy

The second command creates a profile.go File to import your configuration file . When importing your profile , Will call staging.go As defined in init() function , Register your profile .

micro init --profile=staging --output=profile.go

Now you can use this profile to start the server :

MICRO_PROFILE=staging go run . server
原网站

版权声明
本文为[Bai,]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/200/202207170241285044.html