GVKun编程网logo

docker 进程监控 Dumb-Init 进程信号处理 -- 转自 https://blog.csdn.net/tiger435/article/details/54971929

15

对于docker进程监控Dumb-Init进程信号处理--转自https://blog.csdn.net/tiger435/article/details/54971929感兴趣的读者,本文将会是一篇

对于docker 进程监控 Dumb-Init 进程信号处理 -- 转自 https://blog.csdn.net/tiger435/article/details/54971929感兴趣的读者,本文将会是一篇不错的选择,并为您提供关于BlazeDS介绍(http://blog.csdn.net/hgy82/article/details/5799272)、Consul+upsync+Nginx实现动态负载均衡 摘自https://blog.csdn.net/qq_29247945/article/details/80787014、dojo EnhancedGrid的两种实现方式对比,转载自http://blog.csdn.net/earthhour/article/details/17203515、golang中defer的详解 转自https://blog.csdn.net/skh2015java/article/details/77081250的有用信息。

本文目录一览:

docker 进程监控 Dumb-Init 进程信号处理 -- 转自 https://blog.csdn.net/tiger435/article/details/54971929

docker 进程监控 Dumb-Init 进程信号处理 -- 转自 https://blog.csdn.net/tiger435/article/details/54971929

随着 docker 及 Kubernetes 技术发展的越来越成熟稳定,越来越多的公司开始将 docker 用于生产环境的部署,相比起物理机上直接部署,多了一层 docker 容器的环境,这就带来一个问题:进程信号接收与处理。

相信有不少同学发现,在 docker 中捕获不到进程的结束信号,这就给我们的一些进程异常处理带来了麻烦,用 Supervisor 等进程管理工具也能够解决这一问题,不过太 “重” 了,在容器时代追求 “轻” 的我们是不能接受的,本文介绍一个超级小巧的容器初始化工具 - Dumb-Init。

1 特性描述
1.1 进程信号传递
站在容器的角度,由其运行的第一个程序的 PID 为 1,这个进程肩负着重要的使命:传递信号让子进程退出和等待子进程退出。对于第一点,如果 pid 为 1 的进程,无法向其子进程传递信号,可能导致容器发送 SIGTERM 信号之后,父进程等待子进程退出。此时,如果父进程不能将信号传递到子进程,则整个容器就将无法正常退出,除非向父进程发送 SIGKILL 信号,使其强行退出,这就会导致一些退出前的操作无法正常执行,例如关闭数据库连接、关闭输入输出流等。

1.2 僵尸进程处理
上边提到:PID 为 1 的进程的一个重要使命是等待子进程退出,如果一个进程中 A 运行了一个子进程 B,而这个子进程 B 又创建了一个子进程 C,若子进程 B 非正常退出(通过 SIGKILL 信号,并不会传递 SIGKILL 信号给进程 C),那么子进程 C 就会由进程 A 接管,一般情况下,我们在进程 A 中并不会处理对进程 C 的托管操作(进程 A 不会传递 SIGTERM 和 SIGKILL 信号给进程 C),结果就导致了进程 B 结束了,倒是并没有回收其子进程 C,子进程 C 就变成了僵尸进程。

1.3 进程信号模拟
父进程非正常退出(收到 SIGKILL 信号),若使用了 Supervisor 类工具,可以将 SIGKILL 信号传递给子进程,若子进程中想收到 SIGTERM 信号,就可以通过 dumb-init 来模拟。

2 安装 Dumb-init
2.1 deb 安装
RUN wget https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64.deb
RUN dpkg -i dumb-init_*.deb

2.2 二进制安装
RUN wget -O /usr/local/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v1.2.0/dumb-init_1.2.0_amd64
RUN chmod +x /usr/local/bin/dumb-init

2.3 PyPI 安装
pip install dumb-init
1
3 容器使用 Dumb-init
在 Dockerfile 中增加 entrypoint 固定使用 dumb-init 为容器运行的第一个进程。

# Runs "/usr/bin/dumb-init -- /my/script --with --args"
ENTRYPOINT ["/usr/bin/dumb-init", "--"]

# or if you use --rewrite or other cli flags
# SIGTERM (number 15) to SIGQUIT (number 3)
# ENTRYPOINT ["dumb-init", "--rewrite", "15:3", "--"]

CMD ["/my/script", "--with", "--args"]

例如:

ENTRYPOINT ["/usr/bin/dumb-init", "--"]
CMD ["/usr/local/bin/docker-entrypoint.sh"]
1
2
4 最佳实践
如上配置,/usr/bin/dumb-init 为 PID 为 1 的进程,/usr/local/bin/docker-entrypoint.sh 作为其子进程,可以正常收到进程信号。但是 /usr/local/bin/docker-entrypoint.sh 中如果再运行子进程,如运行一个 java 进程,那 java 进程中就获取不到进程信号,此时可以加一个 exec 来提升子进程到 PID 进程下。

例如 /usr/local/bin/docker-entrypoint.sh 中:

#!/bin/bash
echo "Hello world!"
java hello.jar
java 中无法获取进程信号,进程树如下:

/dumb-init
+--- /usr/bin/dumb-init
+--- /bin/bash
+--- java ...
dumb-init,1 -- /usr/local/bin/docker-entrypoint.sh
└─java,7 -Xmx64m -Xms16m -Xmn8m -Xss1m -XX:ReservedCodeCacheSize=5m -XX:NewRatio=3 -jar /usr/local/agent/agent-1.0.1.jar WEX5-JAVA-IDE
调整为:

#!/bin/bash
echo "Hello world!"
exec java hello.jar
java 中可以获取到进程信号,进程树如下:

/dumb-init
+--- /usr/bin/dumb-init
+--- /bin/bash
+--- java ...

BlazeDS介绍(http://blog.csdn.net/hgy82/article/details/5799272)

BlazeDS介绍(http://blog.csdn.net/hgy82/article/details/5799272)

   最近, 公司又整了一套FLEX的框架, 没想到几年后又捡起了FLEX,不过现在已经是4.0了, 今天又学习了一下BlazeDS,   所兴将好的介绍记录下来. 最简单的理解是:它就是一个处理系统间消息格式化的...具体的看下面介绍.

 

    在日常的RIA开发中,Flex或者基于纯Actionscript3的RIA应用非常普遍。 在客户端与服务端的交互中,大家用的比较多的几种方式是:纯文本内容,XML,JSON等。 不过,随着Adobe将AMF协议开源,越来越多的人开始使用基于AMF协议的实现来与服务器交互数据。 而BlazeDS是Adobe发布的一个开源AMF协议服务器端Java实现. 通过BlazeDS,你可以开发基于Flex,Actionscript3的客户端应用程序,并且使用AMF(Advanced Message Format)与服务器交互数据。本文是这个系列教程中的第一篇,目的是介绍AMF协议。

    AMF协议是Adobe开发的一种消息交换协议,其优点包括

  1. 更小的数据传输量
    由于AMF协议采用了二进制的编码方式,省去了很多控制符。比如在XML中,我们传输一段数据,需要把许多XML标签都传输过去,类似于<item></item>此类的控制符没有太大的实际意义,但是很大程度上增加了数据传输量。
    AMF协议则省去了大部分的可见控制符,采用二进制编排方式,效率极高。另外,由于同时也对数据进行了压缩,因此同样的数据,可以极大节省带宽。如果你的服务器每天的流量在1百万以上的访问,这些节省的流量则是相当客观的
  2. 更安全的数据传输
    在基于二进制编码的前提下,数据被编码传输。虽然不能满足加密数据的需要,但是,可以避免其他人直接查看数据内容。
  3. 对程序员更友好的数据接口
    AMF本质上也是一种远程方法调用的支持协议,其可以将服务器端或者客户端的对象序列化,当数据被传输到目的端时,重新反序列化成目的端的内存中的对象
    大家在进行XML操作的时候,会花费很多精力处理XML的编码与读取。比如在服务器,大家需要将数据从数据库或者内存中的某处取出,对其进行一定的数据编码,生产一个XML文档。发送到客户端,在客户端,则需要将XML解析,将其中的数据还原到内存中。 这个过程在使用AMF协议的时候,就被省略了。AMF协议可以很好的支持J2ee开发中的VO模式。
  4. 数据的传输稳健性更高
    这也许不是AMF协议自身的功能,而是要归功于Flash Player.由于我们使用AMF协议的时候,一般都是使用基于Flash客户端。我们在开发过程中测试传送100万条数据。如果使用浏览器的Javascript引擎接受,不管使用任何编码协议,I.E浏览器几乎是要崩溃的,Firefox则是运行极为缓慢。而在使用AMF协议传输到Flash播放器中传输这些数据,对于客户端的影响则是要小很多的。最起码程序还能正常响应.

在开发Flex应用程序的时候,根据后端服务器使用的不同情况,目前可以支持AMF的编程语言有.Net,Java,PHP,Ruby on Rail,python,curl,ColdFusion 等.

我们这次主要介绍的是BlazeDS,基于Java的一个AMF实现。也是Adobe 官方给出的一个开源实现。
源码SVN:
http://opensource.adobe.com/svn/opensource/blazeds/
下载带Tomcat服务器的整合包,解压后可以直接运行,体验例子:
http://flexorg.wip3.adobe.com/blazeds/3.0.x/milestone/3978/blazeds-turnkey-3.2.0.3978.zip
下载部署包,仅仅源码所必须的内容:
http://flexorg.wip3.adobe.com/blazeds/3.0.x/milestone/3978/blazeds-bin-3.2.0.3978.zip

在对其文件结构和配置进行介绍前,我先介绍一下BlazeDS的结构。 这个图翻译自Adobe的BlazeDS官方文档

在BlazeDS中,其结构被设计为多层的传递式构建。

端点(Endpoint) (在MessagebrokerServlet中实现)

我们一般可以看到,BlazeDS暴露的Endpoint有几种

  1. 提供远程方法调用的
    这种endpoint是最常见的一种endpoint,其默认形式是 /messagebroker/amf 或者如果通过https协议访问则是/messagebroker/amfsecure
  2. 提供普通http服务端
    普通HTTP服务其是就是我们最常见的一些以xml形式或者逗号分割符的形式返回纯文本内容的形式。这里不加详细分析 其默认访问形式  /messagebroker/http 或者 /messagebroker/httpsecure
  3. 提供消息流的
    所谓消息流其实是Steaming,他的含义通过标准的HTTP协议,提供防火墙穿透力很强的时信息服务。其实现原理是客户端发出一个HTTP请求,服务器会将这个http请求放入休眠状 态。由于http协议的特性,一个请求如果没有返回,则这个请求的TCP/IP连接是保持的。 当服务器端有消息的时候,他会激活这个睡眠的线程请求,让其返回。客户端收到这个返回后,会重新发出一个新的请求,用于取出服务器上的消息。然后重复等 待。这个endpoint的形式一般为 /messagebroker/streamingamf
  4. 提供服务器polling的.
    polling也就是我们所说的刷服务器法。 每隔一定的时间间隔,刷新服务器去获取新的消息更新。这个方法跟steaming方式的不同在于,其效率比steaming低,而且他没有steaming提供的消息即时性好.

服务(Services)

我们看到,一个来自客户端的请求,通过MessagebrokerServlet捕获后,根据请求服务种类,转交给不同服务。

这里有

  1. 远程方法调用服务
    远程方法调用也就是我们最常用的一种服务调用方式,其作用是在Flex客户端调用服务器上的某个方法,取得其返回结果。
  2. 代理服务
    代理服务应该用在某些特殊场合,比如客户端需要调用企业内部的某个服务器上的webservice,而客户端又处于企业防火墙外部,这种情况下,通过 BlazeDS的代理服务,可以让客户端通过BlazeDS服务器(位于企业防火墙之内而又暴露了对外访问的服务器),去访问防火墙内部的某个服务。 另外,当遇到某些服务需要跨域策略文件(crossdomain,xml)的时候,可以通过代理来实现。
  3. 消息服务
    消息服务主要是为Flex客户端提供一个健壮的消息服务接口,你可以通过JMS适配器直接和一些企业级的消息服务器直接连接。

目标(Destination)

目标其实是一个请求的目标:

对于常用的远程方法调用来说,其目标(destination)就是某个特定的java服务,或者某个特定的配置好的java类

对于代理目标来说,则是定义好的代理种类,比如说普通HTTP代理还是基于WebService的代理

对于消息目标来说,则是某个特定的消息服务种类。

适配器(Adapter)

适配器的作用是提供多种实现来提供某种特定的服务

对于远程调用来说,BlazeDS提供了一个默认的JavaAdapter.这个适配器允许你调用服务器上的一个java类,

    实际上,还有EJBAdapter,他可以让你的远程调用服务调用一个EJB的方法。       

对于代理服务来说 不同的 适配器意味着你可以访问不同种类的代理资源,这里的例子是基于普通HTTP的代理以及基于SOAP的代理

对于消息服务来说,如果提供JMS适配器,则能让你连接到标准的JMS服务器来交换消息。如果提供一个Actionscript适配器,则可以让你在你的Flex客户端之间交换信息。

Consul+upsync+Nginx实现动态负载均衡 摘自https://blog.csdn.net/qq_29247945/article/details/80787014

Consul+upsync+Nginx实现动态负载均衡 摘自https://blog.csdn.net/qq_29247945/article/details/80787014

传统感念:每次修改完nginx配置文件,要重启nginx

动态感念:每次修改完nginx配置信息,不需要重启,nginx实时读取配置信息。

Nginx: 反向代理和负载均衡

Consul:是用go编写(谷歌),实现对动态负载均衡注册与发现功能

SpringCloud支持  Zookeeper、Eureka、Consul服务注册与发现。

服务注册:服务实现者可以通过HTTP API或DNS方式,将服务注册到Consul。

服务发现:服务消费者可以通过HTTP API或DNS方式,从Consul获取服务的IP和PORT。

故障检测:支持如TCP、HTTP等方式的健康检查机制,从而当服务有故障时自动摘除。

K/V存储:使用K/V存储实现动态配置中心,其使用HTTP长轮询实现变更触发和配置更改。

多数据中心:支持多数据中心,可以按照数据中心注册和发现服务,即支持只消费本地机房服务,使用多数据中心集群还可以避免单数据中心的单点故障。

Raft算法:Consul使用Raft算法实现集群数据一致性。

upsync:Nginx动态获取最新upStream(Upsync是新浪微博开源的基于Nginx实现动态配置的三方模块。Nginx-Upsync-Module的功能是拉取Consul的后端server的列表,并动态更新Nginx的路由信息。此模块不依赖于任何第三方模块。Consul作为Nginx的DB,利用Consul的KV服务,每个Nginx Work进程独立的去拉取各个upstream的配置,并更新各自的路由。)


实现动态负载均衡原理:

1、搭建ConsulServer专门存放负载均衡注册配置信息

2、Nginx间隔时间动态获取最新的ConsulServer配置信息

 

注意事项:Nginx1.9

Consul环境搭建:

1、下载consul_0.7.5_linux_amd64.zip

wgethttps://releases.hashicorp.com/consul/0.7.5/consul_0.7.5_linux_amd64.zip

 

2、解压consul_0.7.5_linux_amd64.zip

unzip consul_0.7.5_linux_amd64.zip

如果解压出现该错误

-bash: unzip: 未找到命令

解决办法

yum -yinstall unzip

3、

执行以下 ./consul 出现以下信息就说明安装成功

 

4、启动consul

我的linux ip地址为:10.11.3.161

./consul agent -dev -ui -node=consul-dev -client=10.11.3.161

如果出现

问题,解决方案:如果出现该问题说明你的ip(111.231.55.111)是公网ip,不能用公网ip,要用内网ip。

 

出现这些情况,则说明启动成功了。

5、关闭防火墙  

firewall-cmd --zone=public --add-port=8500/tcp --permanent

systemctl stop firewalld.service

6、浏览器访问111.22.55.111:8500

 

则说明consul安装完成。

二、安装Nginx

1、下载Nginx

wget http://nginx.org/download/nginx-1.9.10.tar.gz

2、解压Nginx

tar -zxvfnginx-1.9.10.tar.gz

3、配置Nginx

groupadd nginx

useradd -g nginx -s /sbin/nologin nginx

mkdir -p /var/tmp/nginx/client/

mkdir -p /usr/local/nginx

配置结束后,要先进行三、安装nginx-upsync-module,然后再进行第4、编译nginx

(三、安装nginx-upsync-module

        1、下载nginx-upsync-module

    wget https://github.com/weibocom/nginx-upsync-module/archive/master.zip

    下载下来的是master.zip

    2、解压nginx-upsync-module(master.zip)

    unzip master.zip

    如果解压出现该错误

    -bash: unzip: 未找到命令

    解决办法

    yum -yinstall unzip    

)

4、编译Nginx

 

./configure   --prefix=/usr/local/nginx   --user=nginx   --group=nginx   --with-http_ssl_module   --with-http_flv_module   --with-http_stub_status_module   --with-http_gzip_static_module   --with-http_realip_module   --http-client-body-temp-path=/var/tmp/nginx/client/   --http-proxy-temp-path=/var/tmp/nginx/proxy/  --http-fastcgi-temp-path=/var/tmp/nginx/fcgi/  --http-uwsgi-temp-path=/var/tmp/nginx/uwsgi   --http-scgi-temp-path=/var/tmp/nginx/scgi   --with-pcre--add-module=../nginx-upsync-module-master

出现

则说明编译成功。

make && make install

编译的是报错

./configure: error: SSL modules require the OpenSSL library.

解决办法

yum -y install opensslopenssl-devel

5、Upstream动态配置

##动态去consul 获取注册的真实反向代理地址

   upstream abing{

        server 127.0.0.1:11111;

upsync192.168.212.134:8500/v1/kv/upstreams/itmayieduupsync_timeout=6mupsync_interval=500ms upsync_type=consul strong_dependency=off;

upsync_dump_path  /usr/local/nginx/conf/servers/servers_test.conf;

    }

 

    server {

        listen       80;

server_name  localhost;

 

        location / {

proxy_passhttp://abing;

###nginx与上游服务器(真实访问的服务器)超时时间后端服务器连接的超时时间_发起握手等候响应超时时间

                                          proxy_connect_timeout1s;

                                          ###nginx发送给上游服务器(真实访问的服务器)超时时间

proxy_send_timeout1s;

                                          ###nginx接受上游服务器(真实访问的服务器)超时时间

proxy_read_timeout1s;

        index  index.html index.htm;

        }

    }
6、创建upsync_dump_path

mkdir /usr/local/nginx/conf/servers/

upsync_dump_path指定从consul拉取的上游服务器后持久化到的位置,这样即使consul服务器出问题了,本地还有一个备份。

7、启动consul
临时关闭防火墙systemctl stopfirewalld

我的linuxIp地址192.168.212.131

./consul agent -dev -ui -node=consul-dev -client=192.168.212.131

8、添加nginxUpstream服务

1.使用linux命令方式发送put请求

curl-X PUT http://192.168.212.134:8500/v1/kv/upstreams/itmayiedu/192.168.212.1:8081

curl-X PUT http://192.168.212.134:8500/v1/kv/upstreams/itmayiedu/192.168.212.1:8081

 2.使用postmen 发送put请求

http://192.168.212.134:8500/v1/kv/upstreams/itmayiedu/192.168.212.1:8081

http://192.168.212.134:8500/v1/kv/upstreams/itmayiedu/192.168.212.1:8081

 负载均衡信息参数

{"weight":1,"max_fails":2, "fail_timeout":10, "down":0}

9、启动Nginx

启动:
cd /usr/local/nginx/sbin
./nginx
nginx服务启动后默认的进程号会放在/usr/local/nginx/logs/nginx.pid文件
cat nginx.pid 查看进程号

关闭:
kill -TERM pid  快速停止服务
kill -QUIT pid  平缓停止服务
kill -9 pid     强制停止服务

重启:
cd /usr/local/nginx
./nginx -HUP pid

./nginx -s reload


/usr/local/webserver/nginx/sbin/nginx -s reload # 重新载入配置文件
/usr/local/webserver/nginx/sbin/nginx -s reopen # 重启 Nginx
/usr/local/webserver/nginx/sbin/nginx -s stop # 停止 Nginx

./nginx -v  显示nginx的版本号
./nginx -V  显示nginx的版本号和编译信息
./nginx -t  检查nginx配置文件的正确性
./nginx -t  检查nginx配置文件的正确定及配置文件的详细配置内容
./nginx -s  向主进程发送信号,如:./nginx -s reload 配置文件变化后重新加载配置文件并重启nginx服务
./nginx -p  设置nginx的安装路径
./nginx -c  设置nginx配置文件的路径
---------------------
作者:阿兵的小屋
来源:CSDN
原文:https://blog.csdn.net/qq_29247945/article/details/80787014
版权声明:本文为博主原创文章,转载请附上博文链接!

dojo EnhancedGrid的两种实现方式对比,转载自http://blog.csdn.net/earthhour/article/details/17203515

dojo EnhancedGrid的两种实现方式对比,转载自http://blog.csdn.net/earthhour/article/details/17203515


后台测试数据初始化:

[java] view plain copy
  1. staticList<User>arrD=newArrayList<User>();
  2. static{
  3. for(inti=0;i<51;i++){
  4. Useru=newUser();
  5. u.setId(i);
  6. u.setName("test"+i);
  7. if(i%2==0){
  8. u.setDesc("devadminuser");
  9. u.setLoginNum(10);
  10. }else{
  11. u.setDesc("devoperuser");
  12. u.setLoginNum(20);
  13. }
  14. arrD.add(u);
  15. }
后台rest服务:

golang中defer的详解 转自https://blog.csdn.net/skh2015java/article/details/77081250

golang中defer的详解 转自https://blog.csdn.net/skh2015java/article/details/77081250

Go里的defer很有用,尤其在很多执行模块化操作时,初始化时给各个需要执行的模块传入参数,但是这些参数有些事在模块执行过程中才赋值的。

这时候有了defer就不会把代码写的很凌乱。

 

 

Go的defer语句用来调度一个函数调用(被延期的函数),使其在执行defer的函数即将返回之前才被运行,被延期执行的函数,它的参数(包括接受者)实在defer执行的时候被求值的,而不是在调用执行的时候。也就是说被延期执行的函数的参数是按正常顺序被求值的。

    defer会按逆序执行

    defer是Go语言提供的关键字,常用来释放资源,会在函数返回之前进行调用。如果有多个defer表达式,调用顺序类似于栈,越后面的defer表达式越先被调用。defer 函数调用的执行时机是外层函数设置返回值之后, 并且在即将返回之前。

 

例1:

 

func main() {
         for i:=0 ;i<5;i++{
              defer fmt.Printf("%d",i)
              fmt.Println("bbbbb")
         }
         fmt.Println("aaaaa")
}

 

执行结果:

bbbbb

bbbbb

bbbbb

bbbbb

bbbbb

aaaaa

43210

 

例2:

func trace(s string) string {
       fmt.Println("entering:",s)
       return s
}

func un(s string) {
       fmt.Println("leaving:",s)
}

func a() {
       defer un(trace("a"))
       fmt.Println("in a")
}

func b() {
       defer un(trace("b"))
       fmt.Println("in b")
       a()
}

 

func main() {
       b()
}

 

 

执行结果如下:

entering: b

in b

entering: a

in a

leaving: a

leaving: b

 

 

 例3

func f1() (result int) {
       defer func() {
              result++
       }()
       return 0
}

func f2() (r int) {
       t := 5
       defer func() {
              t = t+5
       }()
       return t
}


func f3() (t int) {
       t = 5
       defer func() {
              t = t+5
       }()
       return t
}


func f4() (r int) {
       defer func(r int) {
              r = r + 5
       }(r)
       return 1
}

 

要使用defer不踩坑,最重要的一点就是明白,return xxx不是一条原子指令

 

函数返回的过程是这样子的:先给返回值赋值,然后调用defer表达式,最后才是返回到调用函数中。

defer表达式可能会在设置函数返回值之后,在返回到调用函数之前,修改返回值,使最终的函数返回值与你想象的不一致。

 

可以将return xxx改成

返回值=xxx

调用defer函数

空的return

 

 

 

例3可以改写成这样

func f11() (result int) {
       result = 0   //先给返回值赋值
       func(){               //再执行defer 函数
              result++
       }()
       return                //最后返回
}

func f22() (r int) {
       t := 5
       r = t //赋值指令
       func(){   //defer 函数被插入到赋值与返回之间执行,这个例子中返回值r没有被修改
              t = t+5
       }
       return   //返回
}

func f33() (t int) {
       t = 5    //赋值指令
       func(){
              t = t+5  //然后执行defer函数,t值被修改
       }
       return
}

func f44() (r int) {
       r = 1    //给返回值赋值
       func(r int){   //这里的r传值进去的,是原来r的copy,不会改变要返回的那个r值
              r = r+5
       }(r)
       return
}

 

参考:《Effective Go》、《深入解析go内核实现》

今天关于docker 进程监控 Dumb-Init 进程信号处理 -- 转自 https://blog.csdn.net/tiger435/article/details/54971929的分享就到这里,希望大家有所收获,若想了解更多关于BlazeDS介绍(http://blog.csdn.net/hgy82/article/details/5799272)、Consul+upsync+Nginx实现动态负载均衡 摘自https://blog.csdn.net/qq_29247945/article/details/80787014、dojo EnhancedGrid的两种实现方式对比,转载自http://blog.csdn.net/earthhour/article/details/17203515、golang中defer的详解 转自https://blog.csdn.net/skh2015java/article/details/77081250等相关知识,可以在本站进行查询。

本文标签: