概述什么是 JobJob 入门示例Job 的 specPod Template并发问题其他属性
概述
Job 是主要的 Kubernetes 原生 Workload 资源之一,是在 Kubernetes 之上运行批处理任务最简单的方式,在 AI 模型训练等场景下最基础的实现版本就是拉起一个 Job 来完成一次训练任务,然后才是各种自定义 “Job” 实现进阶处理,比如分布式训练需要一个 “Job” 同时拉起多个 Pod,但是每个 Pod 的启动参数会有差异。所以深入理解 Job 的功能和实现细节是进一步开发自定义 “Job” 类型工作负载的基础。今天开始我们计划分成几讲来从 Job 的特性介绍、源码分析等方面深度剖析 Job 资源和其背后的 Job 控制器。
《Kubernetes Job Controller 原理和源码分析》分为三讲:
- 《Kubernetes Job Controller 原理和源码分析(一)》 - 详细介绍 Job 的用法和支持的特性
- 《Kubernetes Job Controller 原理和源码分析(二)》 - 源码分析第一部分,从控制器入口一直到所有 EventHandler 的具体实现,也就是“调谐任务”进入 workqueue 之前的全部逻辑
- 《Kubernetes Job Controller 原理和源码分析(三)》 - 源码分析第二部分,从 workqueue 消费“调谐任务”,具体的调谐过程实现等代码逻辑
什么是 Job
我们创建一个 Job 后,Job 控制器会拉起一个或多个 Pod 开始运行,直到成功退出的 Pod 达到了指定数量。Job 运行过程中可以被挂起,挂起操作会直接删掉正在运行中的 Pod;另外 Job 被删除时对应的 Pod 也会全部被删掉,这个特性和其他控制器是一致的。
一个最常见的 Job 使用方式是通过 Job 拉起一个 Pod,确保这个 Pod 成功执行一次。如果唯一的 Pod 因为某种原因执行失败了,这时候 Job 会重新拉起一个 Pod,继续尝试完成“成功一次”的目标。当然 Job 支持并发拉起多个 Pod。
Job 入门示例
借用官网计算圆周率的例子:
1apiVersion: batch/v1
2kind: Job
3metadata:
4 name: pi
5spec:
6 template:
7 spec:
8 containers:
9 - name: pi
10 image: perl
11 command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
12 restartPolicy: Never
13 backoffLimit: 4
Apply 这个 yaml 文件就能床架一个 Job,看下相关信息:
- 刚创建时查看 Job 状态
1# kubectl get job
2NAME COMPLETIONS DURATION AGE
3pi 0/1 3s 3s
- 接着查看对应的 pod 状态
1# kubectl get pod --selector=job-name=pi
2NAME READY STATUS RESTARTS AGE
3pi--1-25l8f 0/1 ContainerCreating 0 8s
4
5# kubectl get pod --selector=job-name=pi
6NAME READY STATUS RESTARTS AGE
7pi--1-25l8f 1/1 Running 0 12s
8
9# kubectl get pod --selector=job-name=pi
10NAME READY STATUS RESTARTS AGE
11pi--1-25l8f 0/1 Completed 0 21s
- Describe 查看 job 详细信息
1kubectl describe job pi
2Name: pi
3Namespace: default
4Selector: controller-uid=47c8b54a-76e9-4259-b900-750df8a88dd2
5Labels: controller-uid=47c8b54a-76e9-4259-b900-750df8a88dd2
6 job-name=pi
7Annotations: <none>
8Parallelism: 1
9Completions: 1
10Completion Mode: NonIndexed
11Start Time: Mon, 18 Oct 2021 15:55:02 +0800
12Completed At: Mon, 18 Oct 2021 15:55:23 +0800
13Duration: 21s
14Pods Statuses: 0 Running / 1 Succeeded / 0 Failed
15Pod Template:
16 Labels: controller-uid=47c8b54a-76e9-4259-b900-750df8a88dd2
17 job-name=pi
18 Containers:
19 pi:
20 Image: perl
21 Port: <none>
22 Host Port: <none>
23 Command:
24 perl
25 -Mbignum=bpi
26 -wle
27 print bpi(2000)
28 Environment: <none>
29 Mounts: <none>
30 Volumes: <none>
31Events:
32 Type Reason Age From Message
33 ---- ------ ---- ---- -------
34 Normal SuccessfulCreate 5m59s job-controller Created pod: pi--1-25l8f
35 Normal Completed 5m39s job-controller Job completed
看这里的输出信息时,我们带一点“源码”的视角去思考一下,一行行看下来可以发现很多 Job controller 的工作痕迹,比如自动配置了 label、selector 等属性,记录了 Job 下 pods 的当前状态,工作耗时,起止时间等等信息。另外有两个 Event,分别是 Pod 成功创建和 Job 完成结束时的事件。后面刷源码时这里的所有逻辑我们都可以一一发现。
这时当然也可以通过日志查看圆周率计算结果:
- 查看计算结果
1# kubectl logs `kubectl get pod --selector=job-name=pi | grep -v NAME | awk '{print $1}'`
23.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533818279682303019520353018529689957736225994138912497217752834791315155748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035637076601047101819429555961989467678374494482553797747268471040475346462080466842590694912933136770289891521047521620569660240580381501935112533824300355876402474964732639141992726042699227967823547816360093417216412199245863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818347977535663698074265425278625518184175746728909777727938000816470600161452491921732172147723501414419735685481613611573525521334757418494684385233239073941433345477624168625189835694855620992192221842725502542568876717904946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886269456042419652850222106611863067442786220391949450471237137869609563643719172874677646575739624138908658326459958133904780275901
Job 的 spec
我们在定义一个资源的时候,除了明确的 apiVersion
和 kind
两个部分,剩下能自己发挥的就是 metadata
和 spec
,其中 metadata 主要是“名字”类的配置,影响行为的都在 spec 中,我们看下 Job 资源的 spec 支持哪些属性配置。
Pod Template
.spec
中唯一必须配置的是 .spec.template
,这个 template 是 pod template,也就是类似这样的格式:
1metadata:
2 name: hello
3spec:
4 template:
5 spec:
6 containers:
7 - name: hello
8 image: busybox
9 command: ['sh', '-c', 'echo "Hello, Kubernetes!" && sleep 3600']
10 restartPolicy: OnFailure
注意这整段是一个简单的 pod template,我们通过 kubectl explain job.spec.template
命令可以清晰地看到这段配置和 job.spec 的关系:
1# kubectl explain job.spec.template
2KIND: Job
3VERSION: batch/v1
4
5RESOURCE: template <Object>
6
7DESCRIPTION:
8 Describes the pod that will be created when executing a job. More info:
9 https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/
10
11 PodTemplateSpec describes the data a pod should have when created from a
12 template
13
14FIELDS:
15 metadata <Object>
16 Standard object's metadata. More info:
17 https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
18
19 spec <Object>
20 Specification of the desired behavior of the pod. More info:
21 https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
22
也就是说 job.spec.template
下面保存的是完整的 pod.metadata
和 pod.spec
,也就是包含一个 pod 能改变的所有属性。
这里有两个注意点:
- 不要轻易设置
.spec.selector
,我们在前面的例子中可以看到 Job 控制器会自动添加类似这样的 selector:controller-uid=47c8b54a-76e9-4259-b900-750df8a88dd2,这个 selector 可以保证唯一性且已经满足几乎全部的场景需求。如果自己添加一个 selector 但是不小心引入了重名等问题,会导致 job 控制器发生操作到其他控制器管理的 pod 等不必要的错误。 - Pod 的
RestartPolicy
只能设置成 Never 和 OnFailure,这个也很明显,要是设置成 Always 就死循环了。
并发问题
Job 从并发角度可以分成三类:
- 无并发:
- 同一时间只启动一个 Pod,这个 Pod 失败了才会启动另外一个新的 Pod;
- 有一个 Pod 成功结束时整个 Job 结束;
- 这时候
.spec.completions
和.spec.parallelism
不需要设置,也就是生效的默认值:1 - 指定完成数量:
- 配置
.spec.completions
为正整数; - 成功结束的 Pod 数量达到 completions 指定的数量时,Job 结束;
- 可以指定
.spec.completionMode=Indexed
,这时候 Pod name 会有编号,从 0 开始;反之默认情况下,比如前面不指定时 Pod 名叫 pi--1-25l8f,我们并发创建多个也是 pi--1-xxxxx 的命名风格,中间的数字一直是1;另外这个.spec.completionMode=Indexed
配置还有几点行为是会给 pod 加上类似batch.kubernetes.io/job-completion-index
格式的 annotation 和JOB_COMPLETION_INDEX=job-completion-index
的环境变量; - 配置了
.spec.completions
后,可以选择性配置.spec.parallelism
来控制并发度;比如 completions 为 10,parallelism 为 3,那么 Job 控制器就会在达到 10 个 Pod 成功前,尽量保持并发度为 3 去拉起 Pod; - 工作队列:
- 不指定
.spec.completions
,配置.spec.parallelism
为一个非负整数(配置为0相当于挂起); - 可以通过 MQ 等方式管理工作队列,每个 Pod 独立工作,能够判断整个任务是否完成,如果一个 Pod 成功退出,则表示整个任务结束了,这时候不会再创建新的 Pod,整个 Job 也就结束了;
其他属性
除了上面提到的 template
、completions
、parallelism
、completionMode
和 selector
外,Job.spec 还有5个可以配置的属性(不同版本有细微区别,我的环境是 v1.22.0):
- activeDeadlineSeconds 指定这个 Job 的最长允许耗时,挂起状态会暂停该计时器;
- backoffLimit 重试次数,超过了之后 Job 被设置为 failed,默认值是 6,也就是 Pod 失败后可以重试 6 次;
- manualSelector 配置开启自定义 selector 功能,绝大多数情况下不需要,也不要去配置;这是一个 bool 值,也就是设置为 true 后才能通过 selector 来覆盖默认的行为;
- suspend 配置挂起一个 Job,挂起操作会直接删除所有运行中的 Pod,并且重置 Job 的 StartTime,暂停 ActiveDeadlineSeconds 计时器;
- ttlSecondsAfterFinished 需要开启 TTLAfterFinished 特性才能生效,在 alpha 阶段;效果是当一个 Job 结束(成功或失败)后,过了该参数指定的时间后,Job 会被清理掉。如果设置为0就是立刻清理,默认情况下 Job 执行结束后会保留在环境里,直到手动删除。
概述什么是 JobJob 入门示例Job 的 specPod Template并发问题其他属性
概述
Job 是主要的 Kubernetes 原生 Workload 资源之一,是在 Kubernetes 之上运行批处理任务最简单的方式,在 AI 模型训练等场景下最基础的实现版本就是拉起一个 Job 来完成一次训练任务,然后才是各种自定义 “Job” 实现进阶处理,比如分布式训练需要一个 “Job” 同时拉起多个 Pod,但是每个 Pod 的启动参数会有差异。所以深入理解 Job 的功能和实现细节是进一步开发自定义 “Job” 类型工作负载的基础。今天开始我们计划分成几讲来从 Job 的特性介绍、源码分析等方面深度剖析 Job 资源和其背后的 Job 控制器。
《Kubernetes Job Controller 原理和源码分析》分为三讲:
- 《Kubernetes Job Controller 原理和源码分析(一)》 - 详细介绍 Job 的用法和支持的特性
- 《Kubernetes Job Controller 原理和源码分析(二)》 - 源码分析第一部分,从控制器入口一直到所有 EventHandler 的具体实现,也就是“调谐任务”进入 workqueue 之前的全部逻辑
- 《Kubernetes Job Controller 原理和源码分析(三)》 - 源码分析第二部分,从 workqueue 消费“调谐任务”,具体的调谐过程实现等代码逻辑
什么是 Job
我们创建一个 Job 后,Job 控制器会拉起一个或多个 Pod 开始运行,直到成功退出的 Pod 达到了指定数量。Job 运行过程中可以被挂起,挂起操作会直接删掉正在运行中的 Pod;另外 Job 被删除时对应的 Pod 也会全部被删掉,这个特性和其他控制器是一致的。
一个最常见的 Job 使用方式是通过 Job 拉起一个 Pod,确保这个 Pod 成功执行一次。如果唯一的 Pod 因为某种原因执行失败了,这时候 Job 会重新拉起一个 Pod,继续尝试完成“成功一次”的目标。当然 Job 支持并发拉起多个 Pod。
Job 入门示例
借用官网计算圆周率的例子:
1apiVersion: batch/v1
2kind: Job
3metadata:
4 name: pi
5spec:
6 template:
7 spec:
8 containers:
9 - name: pi
10 image: perl
11 command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
12 restartPolicy: Never
13 backoffLimit: 4
Apply 这个 yaml 文件就能床架一个 Job,看下相关信息:
- 刚创建时查看 Job 状态
1# kubectl get job
2NAME COMPLETIONS DURATION AGE
3pi 0/1 3s 3s
- 接着查看对应的 pod 状态
1# kubectl get pod --selector=job-name=pi
2NAME READY STATUS RESTARTS AGE
3pi--1-25l8f 0/1 ContainerCreating 0 8s
4
5# kubectl get pod --selector=job-name=pi
6NAME READY STATUS RESTARTS AGE
7pi--1-25l8f 1/1 Running 0 12s
8
9# kubectl get pod --selector=job-name=pi
10NAME READY STATUS RESTARTS AGE
11pi--1-25l8f 0/1 Completed 0 21s
- Describe 查看 job 详细信息
1kubectl describe job pi
2Name: pi
3Namespace: default
4Selector: controller-uid=47c8b54a-76e9-4259-b900-750df8a88dd2
5Labels: controller-uid=47c8b54a-76e9-4259-b900-750df8a88dd2
6 job-name=pi
7Annotations: <none>
8Parallelism: 1
9Completions: 1
10Completion Mode: NonIndexed
11Start Time: Mon, 18 Oct 2021 15:55:02 +0800
12Completed At: Mon, 18 Oct 2021 15:55:23 +0800
13Duration: 21s
14Pods Statuses: 0 Running / 1 Succeeded / 0 Failed
15Pod Template:
16 Labels: controller-uid=47c8b54a-76e9-4259-b900-750df8a88dd2
17 job-name=pi
18 Containers:
19 pi:
20 Image: perl
21 Port: <none>
22 Host Port: <none>
23 Command:
24 perl
25 -Mbignum=bpi
26 -wle
27 print bpi(2000)
28 Environment: <none>
29 Mounts: <none>
30 Volumes: <none>
31Events:
32 Type Reason Age From Message
33 ---- ------ ---- ---- -------
34 Normal SuccessfulCreate 5m59s job-controller Created pod: pi--1-25l8f
35 Normal Completed 5m39s job-controller Job completed
看这里的输出信息时,我们带一点“源码”的视角去思考一下,一行行看下来可以发现很多 Job controller 的工作痕迹,比如自动配置了 label、selector 等属性,记录了 Job 下 pods 的当前状态,工作耗时,起止时间等等信息。另外有两个 Event,分别是 Pod 成功创建和 Job 完成结束时的事件。后面刷源码时这里的所有逻辑我们都可以一一发现。
这时当然也可以通过日志查看圆周率计算结果:
- 查看计算结果
1# kubectl logs `kubectl get pod --selector=job-name=pi | grep -v NAME | awk '{print $1}'`
23.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989380952572010654858632788659361533818279682303019520353018529689957736225994138912497217752834791315155748572424541506959508295331168617278558890750983817546374649393192550604009277016711390098488240128583616035637076601047101819429555961989467678374494482553797747268471040475346462080466842590694912933136770289891521047521620569660240580381501935112533824300355876402474964732639141992726042699227967823547816360093417216412199245863150302861829745557067498385054945885869269956909272107975093029553211653449872027559602364806654991198818347977535663698074265425278625518184175746728909777727938000816470600161452491921732172147723501414419735685481613611573525521334757418494684385233239073941433345477624168625189835694855620992192221842725502542568876717904946016534668049886272327917860857843838279679766814541009538837863609506800642251252051173929848960841284886269456042419652850222106611863067442786220391949450471237137869609563643719172874677646575739624138908658326459958133904780275901
Job 的 spec
我们在定义一个资源的时候,除了明确的 apiVersion
和 kind
两个部分,剩下能自己发挥的就是 metadata
和 spec
,其中 metadata 主要是“名字”类的配置,影响行为的都在 spec 中,我们看下 Job 资源的 spec 支持哪些属性配置。
Pod Template
.spec
中唯一必须配置的是 .spec.template
,这个 template 是 pod template,也就是类似这样的格式:
1metadata:
2 name: hello
3spec:
4 template:
5 spec:
6 containers:
7 - name: hello
8 image: busybox
9 command: ['sh', '-c', 'echo "Hello, Kubernetes!" && sleep 3600']
10 restartPolicy: OnFailure
注意这整段是一个简单的 pod template,我们通过 kubectl explain job.spec.template
命令可以清晰地看到这段配置和 job.spec 的关系:
1# kubectl explain job.spec.template
2KIND: Job
3VERSION: batch/v1
4
5RESOURCE: template <Object>
6
7DESCRIPTION:
8 Describes the pod that will be created when executing a job. More info:
9 https://kubernetes.io/docs/concepts/workloads/controllers/jobs-run-to-completion/
10
11 PodTemplateSpec describes the data a pod should have when created from a
12 template
13
14FIELDS:
15 metadata <Object>
16 Standard object's metadata. More info:
17 https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
18
19 spec <Object>
20 Specification of the desired behavior of the pod. More info:
21 https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#spec-and-status
22
也就是说 job.spec.template
下面保存的是完整的 pod.metadata
和 pod.spec
,也就是包含一个 pod 能改变的所有属性。
这里有两个注意点:
- 不要轻易设置
.spec.selector
,我们在前面的例子中可以看到 Job 控制器会自动添加类似这样的 selector:controller-uid=47c8b54a-76e9-4259-b900-750df8a88dd2,这个 selector 可以保证唯一性且已经满足几乎全部的场景需求。如果自己添加一个 selector 但是不小心引入了重名等问题,会导致 job 控制器发生操作到其他控制器管理的 pod 等不必要的错误。 - Pod 的
RestartPolicy
只能设置成 Never 和 OnFailure,这个也很明显,要是设置成 Always 就死循环了。
并发问题
Job 从并发角度可以分成三类:
- 无并发:
- 同一时间只启动一个 Pod,这个 Pod 失败了才会启动另外一个新的 Pod;
- 有一个 Pod 成功结束时整个 Job 结束;
- 这时候
.spec.completions
和.spec.parallelism
不需要设置,也就是生效的默认值:1 - 指定完成数量:
- 配置
.spec.completions
为正整数; - 成功结束的 Pod 数量达到 completions 指定的数量时,Job 结束;
- 可以指定
.spec.completionMode=Indexed
,这时候 Pod name 会有编号,从 0 开始;反之默认情况下,比如前面不指定时 Pod 名叫 pi--1-25l8f,我们并发创建多个也是 pi--1-xxxxx 的命名风格,中间的数字一直是1;另外这个.spec.completionMode=Indexed
配置还有几点行为是会给 pod 加上类似batch.kubernetes.io/job-completion-index
格式的 annotation 和JOB_COMPLETION_INDEX=job-completion-index
的环境变量; - 配置了
.spec.completions
后,可以选择性配置.spec.parallelism
来控制并发度;比如 completions 为 10,parallelism 为 3,那么 Job 控制器就会在达到 10 个 Pod 成功前,尽量保持并发度为 3 去拉起 Pod; - 工作队列:
- 不指定
.spec.completions
,配置.spec.parallelism
为一个非负整数(配置为0相当于挂起); - 可以通过 MQ 等方式管理工作队列,每个 Pod 独立工作,能够判断整个任务是否完成,如果一个 Pod 成功退出,则表示整个任务结束了,这时候不会再创建新的 Pod,整个 Job 也就结束了;
其他属性
除了上面提到的 template
、completions
、parallelism
、completionMode
和 selector
外,Job.spec 还有5个可以配置的属性(不同版本有细微区别,我的环境是 v1.22.0):
- activeDeadlineSeconds 指定这个 Job 的最长允许耗时,挂起状态会暂停该计时器;
- backoffLimit 重试次数,超过了之后 Job 被设置为 failed,默认值是 6,也就是 Pod 失败后可以重试 6 次;
- manualSelector 配置开启自定义 selector 功能,绝大多数情况下不需要,也不要去配置;这是一个 bool 值,也就是设置为 true 后才能通过 selector 来覆盖默认的行为;
- suspend 配置挂起一个 Job,挂起操作会直接删除所有运行中的 Pod,并且重置 Job 的 StartTime,暂停 ActiveDeadlineSeconds 计时器;
- ttlSecondsAfterFinished 需要开启 TTLAfterFinished 特性才能生效,在 alpha 阶段;效果是当一个 Job 结束(成功或失败)后,过了该参数指定的时间后,Job 会被清理掉。如果设置为0就是立刻清理,默认情况下 Job 执行结束后会保留在环境里,直到手动删除。
Kubernetes Job Controller 原理和源码分析(一)的更多相关文章
-
Java并发编程(七)ConcurrentLinkedQueue的实现原理和源码分析
相关文章 Java并发编程(一)线程定义.状态和属性 Java并发编程(二)同步 Java并发编程(三)volatile域 Java并发编程(四)Java内存模型 Java并发编程(五)Concurr ...
-
Java1.7 HashMap 实现原理和源码分析
HashMap 源码分析是面试中常考的一项,下面一篇文章讲得很好,特地转载过来. 本文转自:https://www.cnblogs.com/chengxiao/p/6059914.html 参考博客: ...
-
深入ReentrantLock的实现原理和源码分析
ReentrantLock是Java并发包中提供的一个可重入的互斥锁.ReentrantLock和synchronized在基本用法,行为语义上都是类似的,同样都具有可重入性.只不过相比原生的Sync ...
-
☕【Java深层系列】「并发编程系列」让我们一起探索一下CyclicBarrier的技术原理和源码分析
CyclicBarrier和CountDownLatch CyclicBarrier和CountDownLatch 都位于java.util.concurrent这个包下,其工作原理的核心要点: Cy ...
-
Alibaba-技术专区-RocketMQ 延迟消息实现原理和源码分析
痛点背景 业务场景 假设有这么一个需求,用户下单后如果30分钟未支付,则该订单需要被关闭.你会怎么做? 之前方案 最简单的做法,可以服务端启动个定时器,隔个几秒扫描数据库中待支付的订单,如果(当前时间 ...
-
Express工作原理和源码分析一:创建路由
Express是一基于Node的一个框架,用来快速创建Web服务的一个工具,为什么要使用Express呢,因为创建Web服务如果从Node开始有很多繁琐的工作要做,而Express为你解放了很多工作, ...
-
Android AsyncTask运作原理和源码分析
自10年大量看源码后,很少看了,抽时间把最新的源码看看! public abstract class AsyncTask<Params, Progress, Result> { p ...
-
Quartz学习--二 Hello Quartz! 和源码分析
Quartz学习--二 Hello Quartz! 和源码分析 三. Hello Quartz! 我会跟着 第一章 6.2 的图来 进行同步代码编写 简单入门示例: 创建一个新的java普通工程 ...
-
Dubbo原理和源码解析之服务引用
一.框架设计 在官方<Dubbo 开发指南>框架设计部分,给出了引用服务时序图: 另外,在官方<Dubbo 用户指南>集群容错部分,给出了服务引用的各功能组件关系图: 本文将根 ...
随机推荐
-
Windows命令点滴
1.删除windows服务项目: C:\服务器软件\Redis>sc delete Redis6379 [SC] DeleteService 成功 2.用于私网的IP地址段: 10.0.0.0/ ...
-
C++中三种new的用法
转载自:http://news.ccidnet.com/art/32855/20100713/2114025_1.html 作者: mt 1 new operator,也叫new表达式:new表达式比 ...
-
paper 7:支持向量机系列四:Outliers —— 介绍支持向量机使用松弛变量处理 outliers 方法。
在最开始讨论支持向量机的时候,我们就假定,数据是线性可分的,亦即我们可以找到一个可行的超平面将数据完全分开.后来为了处理非线性数据,使用 Kernel 方法对原来的线性 SVM 进行了推广,使得非线性 ...
-
HackerRank ";Kundu and Tree"; !!
Learnt from here: http://www.cnblogs.com/lautsie/p/3798165.html Idea is: we union all pure black edg ...
-
Ionic 安装部署
Ionic 安装部署 准备工作 下载安装Node.js, JDK,Apache Ant,Android SDK:编辑器用WebStorm node jdk ant 均需要加进 环境变量path中 An ...
-
Quiz 6b Question 8————An Introduction to Interactive Programming in Python
Question 8 We can use loops to simulate natural processes over time. Write a program that calcula ...
-
获取时间SQL函数语句
1.获取时间 获取当天的数据 where DATEDIFF (DD, 数据库中时间的字段 ,GETDATE())=0 查询24小时内的 where DATEDIFF (HH, 数据库中时间的字段 ...
-
Layer 中自定义属性的动画
原文:http://objccn.io/issue-12-2/ Layer 中自定义属性的动画 默认情况下,CALayer 及其子类的绝大部分标准属性都可以执行动画,无论是添加一个 CAAni ...
-
DDL、DML和DCL的区别与理解
DML.DDL.DCL区别 . 总体解释: DML(data manipulation language): 它们是SELECT.UPDATE.INSERT.DELETE,就象它的名字一样,这4条命令 ...
-
2019-04-24-day039-数据库的增查
内容回顾 多积累使用工具的经验 尽量多练习 1.多练几种类型 2.不要照着写好的sql敲,要自己组织语言 内容回顾 存储引擎 innodb : 外键 行级锁(并发修改) 事务(客户管理系统) myis ...