请选择 进入手机版 | 继续访问电脑版

IT运维管理,ITIL,ITSS,ITSM,ISO20000-ITIL先锋论坛

 找回密码
 微信、QQ、手机号一键注册

扫描二维码登录本站

QQ登录

只需一步,快速开始

艾拓先锋
搜索
查看: 313|回复: 0

DevOps老手如何同时抓好运维与开发?

[复制链接]
来自- 广东广州

参加活动:0

组织活动:12

发表于 2018-8-27 15:35:54 | 显示全部楼层 |阅读模式 来自- 广东广州
本帖最后由 monicazhang 于 2018-8-27 15:53 编辑
6 q& P4 B( U' T$ v' N8 T& i2 ?7 i7 X) S$ o& y% C
运维开发这个岗位与普通的业务开发不同,与日常的运维工作也不同。要求兼顾开发与运维两种能力。既要掌握不弱于业务开发的开发技术;又要负责SRE同学日常的运维能力;上线之前,还要像QA同学一样,对自己的服务进行测试和分级变更。
% ^- j7 z; K/ W4 j/ J5 ?  P# r2 D
3 X8 p1 ?- i% c: l- z% n
多种能力的交叉,造就不一样的视角:这群人给自己起了一个很简约的名字:DevOps

8 x$ U( `4 n% @( j' E
1.png

/ K$ Y5 j. i! v0 o
DevOps

! X: I3 {2 j3 m. z

) _% u, g* h9 B- `, `
按百度百科解释:DevOps是开发、技术运营和质量保障三者的交集。在我看来,DevOps其实只是一种方法论,从这种综合的视角出发,包含一些基本原则和实践方法,仅此而已。

. \- m: j* I) f& {
7 B# ~5 |9 B( L7 m5 O; g" h
DevOps从架构、开发、测试、发布、运维、变更整个流程来考量,从这种综合的视角出发,能将部门之间的沟通隔阂消灭于无形,会给我们公司和项目注入新的活力。
" X; \. Y- l7 G! k/ D7 |' S3 u0 ~
' T7 ^" z, \7 S- B' p/ F2 n) w
DevOps这个概念,本文暂不做讨论,本文内容只针对运维领域自动化平台开发的工作进行探讨。

, v5 r- ]; ]& G( ], O/ u

2 }% _" b: W& g* e2 U* G

一、前言


. }. h' z& \+ \) F  T. t" g1 h
运维开发的工作,所需能力的复杂,工作性质的交叉,自然会导致很多同学在其中会有些困扰。
$ Y& S/ M# g/ n9 {5 t4 E

! u% Q8 A& U, c$ _6 h
很多刚毕业的小同学,接到运维开发的offer的时候,很可能是一头雾水:“运维?开发?到底是运维还是开发?”

6 F& k+ B9 B8 K0 e& {
& U5 O9 m2 D7 j. f* p; \- O
有很多从业多年的同学,拼命的追求技术与对底层的探索,却忽略了产品层面的思考。

0 x: G+ v- Q3 g( b6 e7 B4 |
7 i% o( J6 @0 L9 ~4 F
还有很多整天忙忙碌碌的同学,在业务方各种零碎的需求中修修改改,消耗了大多数的时间,最终平台却变得千疮百孔。
( V" C% O  s6 ~- l, P9 U" S% `

& F+ e- g2 D' }$ R; D$ h6 E
本文,我将自己关于这些问题的思考分享给大家。

2 o" s5 s/ _( k# v5 @/ S8 S0 p
4 V) M! K, p; i* N& k
4 y" L9 |. ]) A$ ~

二、什么样的平台是好的运维平台?

5 n3 u/ X# j& A$ S& \# w3 k
既然我们是在做平台,那我们要了解的第一点就是:好的运维平台是什么样子的?

5 N4 S! Z5 X; x! O6 G0 E* b
3 Z$ p" G, `; a7 X9 g$ H
如果让我们来从头设计一个平台,我们应该如何去考量?
' j! \: p( w4 O
) b8 H- a3 i% b) D
1、效率 & 成本的均衡4 G4 X. S( ]4 Q

( l4 z0 F7 f4 ?+ w% G- ^运维平台是服务于运维的。对运维来说,除了稳定性之外,最重要的无非就是效率与成本。如果我们的平台可以用更少量的时间或资源成本来提高更多的效率,那就是一个非常成功的平台了。
8 B0 {$ n! q3 q% e9 d' ?1 ^) }/ i
$ e0 Y6 t  J% G9 Z- ^
至于如何量化比较,就因系统而异了。
2 k' E! s7 B3 ~5 B- D/ I; {

4 d. v# y4 j* [0 o, E
2、体验 & 人性化* F5 Z- @& u2 ?9 [6 Q5 I' G

4 B$ @# }+ P+ U' e' T3 S% p# u

: A$ c* Q& j1 j6 f为什么我要把体验放在第二位?

& h' I4 j5 j1 a' x3 n" ^( F. ]
6 O# r! i$ s& A' I
因为有太多的运维开发工程师,在开发的过程中,过多地注重系统的稳定性和性能,完全不把体验放在眼里了。
0 R. ]8 E5 I9 d

: b7 }5 R+ {7 o我想说的是,有时候,如果不关注用户体验,我们做了再好的功能,没有人用,那这个功能意义何在?用户价值与用户体验在某些情况下,是会画等号的。

; D) X0 c. j$ K! A) M
% e1 Z* F/ e9 v, D/ y2 _1 L" J& X
3、优秀的系统架构

" ?2 a& N1 L1 O3 C* r
2 n7 ^$ a) t8 X
在业界,无论是运维系统也好,业务系统也好,优秀系统的架构都是大同小异的:

8 ~7 A% C3 L% c$ n

% I0 _5 G  d5 M! m8 |
  • 稳定性:负载均衡、多活等。
    1 E! Q/ s" l5 b& d" ?$ m4 i: N
    ( x. M1 q# f3 M, ^

# Z2 B& d/ F# l' O3 {6 l! j; N3 v9 Y) Z" G0 r2 y6 W
  • 扩展性:每次增加功能,可以很小的开发成本实现,而不是每次都要重构。
    # s+ ~+ e1 D- e! ?  y5 r  Q; X
/ B) J7 S, i  _9 ^: ]% [- h
! l- g, j9 J3 R# J4 j& E
  • 伸缩性:没有核心的单点,大部分性能瓶颈,都可以通过横向扩展来解决。% {! `- I, x# x  O' A' [
+ h/ M6 f- P2 C6 u/ Z' Y" J
% s- Q/ {" _# R. G6 A
  • 自我保护:把可能会导致性能瓶颈的点都拆解开,用队列、限流等手段消除流量突增的高峰带来的危害,保护自身。
    ; X' P  R* ?# h& X( G& |/ d2 e
! _; U1 P" p- G5 J2 Z/ l6 _

! o, G$ f, b7 h+ G% C0 u4 H; ^' G" b; c$ h: m1 y
  • 安全性:敏感服务加入权限与认证,Web服务避免常见的漏洞如SQL注入、XSS、CSRF等。做好操作记录方便后续审计,尽量不要出现短板。2 r& w6 v1 Z$ f4 E) h9 Y6 W0 ^7 J
% d1 n; [6 t7 y, T) S! _

. L# j( T+ O  _. T3 V( s8 r- w- ?8 _* T
+ q. N& O; h" n) O* ~/ Q$ F3 V. O8 v6 A
、如何运维自己开发的平台?% S- D) a/ D2 V  Z' C
7 a; a) B3 w; ?4 q1 R8 ^
运维开发在大多数时候,要负责运维自己开发出来的系统,俗称吃自己的狗粮;而很多人跳槽之后,第一件事情,也是从运维别人的系统开始的。那我们如何运维好一个平台呢?

0 d& h) F6 G7 e1 O

% }" `' P4 ^. m' x( w运维与开发的工作,思路其实不尽相同。虽然都是基于稳定性来考量,但可能要想的更多、更广,任何有可能影响到我们业务的稳定性的因素,都要考虑在内。
1 ~4 ^+ O% |, R
  U) _7 ?% j. `1 t1 g6 U
用我的总监的一句话来讲,就是:我们运维同学与开发同学,最大的不同点,就是稳定性的意识。
: b! M& U/ u' o3 T- d' h
2 M( C  _+ q% g5 O" x) u% q% O
1、架构上的稳定性" s& x- w% W1 g' ?; F

# v3 s8 b1 T$ e$ y7 G" ?# ]

1 n' W% K; p! E; G
这个其实更多的是比如多活、负载均衡、流量调度、硬件冗余之类的考量:服务在实例挂掉的时候,如何不影响稳定性;专线断开的时候,如何仍然正常的提供服务等等。
8 c' V2 I8 w0 _* E! c
  m; C2 O. r! ]1 \4 ~; B9 ~2 |4 G
2、快速地发现问题5 H2 U# g8 m( X, e% [/ E
6 S$ w* T' |- k# {8 O% N
8 U: s* g% D4 t. W) X$ a& y9 ]
无论我们的架构多么完善,也很难做到尽善尽美。那么在一些需要人为介入处理的故障中,快速地发现异常,能直接降低服务的不可用时长。因此,对于一般的服务,将报警配置地更完善是我们能快速定位异常的第一步。
* p5 B9 d+ h$ Q5 b5 `5 |/ l: h

4 H: @! e* Q; d+ S) e9 G还有,对于监控系统,自身的故障不能通过自身的监控来发现,最好还有一套独立的自监控。
; \: Y+ G7 v$ r# E6 o3 E, {% z
% S* U# O! [! E+ \  q" J4 {) ?
3、应急预案&演练& z, ]1 N1 t. d2 P1 X3 ]
3 @5 P5 ~1 w2 g, y0 {, W, [: \! G# u; ~
0 o0 O$ M  S9 n
在梳理一个服务的运维工作的时候,其实我们能很明确的感知到某个地方出问题需要人力介入。而除变更之外的一般的故障,我们都是可预见的。一旦真的出现这种问题,如果我们没有准备,即使知道如何去做,也可能会因为手忙脚乱而出错。
2 `/ O6 x. R/ \$ g; z! d

- g, |! p$ Z  U! }6 c" M0 `因此,设定一些可能发生情况的应急预案,定时演练,是一个可以在故障时快速恢复服务的手段。

  t  V- N1 I* d) b% I: e! c
- e  h* o1 U/ o+ R+ f
4、自我保护( K, x) Z. F; U1 f& J- |0 R5 V
7 J% ^' c( g* p; D

6 Q3 s. T' l  c; h4 ^! e, w
一般的系统,都有上游,如何保证上游的数据异常对自身产生影响,也是很重要的一点。总结起来,总共有三类:

: g4 u4 P7 Q- x  f: ]7 n& Z
0 S; o! m6 ]" G5 Z' [8 `
  • 过载保护:上游流量太大,导致自身服务不堪负重。这种情况要根据场景不同,考虑加入消息队列,或者限流。) U+ X& K, w, ~
    " S7 h* D. j) s( E' W) g
6 @8 \0 t( A5 N" y$ e2 R. W/ k& a
  • 脏数据保护:上游来的数据,是否应该完全信任?是否有脏数据会来影响我内部数据的准确性?比如安全扫描的流量,很大程度上就会对很多系统产生脏数据。这种最好有过滤的规则的配置,能摘除这部分流量。9 A/ n4 T+ V+ V; r+ {7 m+ ?( B( `. t: ?

    " N. W; p  P: n, V/ h, O$ U& G. ?
- Z2 P8 S$ l$ y% b8 b7 O
/ u, Q# ?9 ]- H, Y, ~
  • 上游变更保护:上游的变更,需要及时知晓和跟进。如果上游不够规范,很可能会修改接口或者数据格式。即使上游规范,也要跟进上游变更容易造成的影响,人为确认没有问题。& K& P' o; m7 n# }4 S3 \* L3 Q
    / k0 r- g0 P) r( x+ d8 q" |
( L& @/ e2 t$ |+ d7 S

# d( h. `5 y; M' |. O/ F

2 |/ H* b4 p* |
5、容量规划
- h' n5 r% D1 ?0 a  A' k

, u/ F# W9 f/ b/ X, H, u
随着系统负载的升高,系统的服务能力并不是线性下降的。当负载到达临界线的时候,一个逐渐变慢的系统最终会停止一切服务。因此,要在系统瓶颈到来之前,预估未来一段时间内服务的量级,在量级到来之前,做好应对措施。DevOps
# q" q7 M" L5 V. @+ L' x
- B! n0 O& ^' b2 [; x: F+ D9 o
笔者公司目前有一个Topic,就是全链路压测。运维团队与所有业务团队一起建设,压测常态化,每时每刻对系统全链路各个环节的瓶颈都了如指掌。其实也是在做这件事情。
3 S0 V- Z. w- I5 e- X
6 Q3 t1 `6 a& x- X1 X- l
6、变更管理
/ W7 B" e+ \( Q. Z9 j. n2 L) S! |+ [9 y6 e3 u$ Q

7 v$ S" u+ n9 k( S7 \9 v4 S; ?
SRE的经验告诉我们,大概70%的生产事故都是由某种部署的变更而触发。因此要管理好我们的变更的机制:

4 R  c- Q8 a9 @! v

+ e& k+ v8 l( N5 c1 O
  • 采用分级发布机制:先pre、再小流量、再中流量、再全量。
    0 ~% Y; N5 C/ [: U% P0 R# {, [
    % h/ x3 Y5 b3 ?' o
! f( t6 L, e4 q6 O6 N* h
  • 制定全面CheckList:保证变更部分所有功能都有测试可以覆盖,能快速发现问题,第一时间回滚。8 _' i9 s9 ?3 x! {& k0 `

    - A4 o" r* ?2 r9 c

; \- R, V* ]5 u; }
; S% M1 ^$ {. v6 S1 x' F/ K. r
0 r* h* P- M  z* q- d8 V1 c, P
  • 出现问题,先回滚,再定位:这个不用多说,先止损,再慢慢查问题。$ Y, e( E) L, `; Z! V6 A# ?# l
    8 P/ Q+ P$ Q8 p+ F% D3 l

2 |" C- E+ j( f; p& z

+ i3 w% W+ X* x( d

% \. ], G- H- I0 o: C4 U

四、除了开发与运维,我们还要做什么?

, ~/ b" c; X* |3 T

# m: S" `; |* w+ d
运维开发的定位,注定要比业务开发承担更多的责任。因为这群人除了是自己的RD,还要自己做自己的PM、OP、QA。

/ u" k0 i5 b2 D" X

3 v, E1 Q3 I( L1 u6 x8 ]因此,我们要考量的,还有产品和需求层面的东西:

; t3 }: a  M  ]+ |7 H1 t
6 m% O+ Q1 V' D; x$ J
1、需求管理
# k! F! Y( q" Z9 J# x6 N$ ?5 F% H2 ?
4 \+ m- G  N1 h
作为开发,尤其是没有正经PM的开发,管理好需求可以让我们把精力放在最重要的地方,解放我们的精力、提高产出。
7 I2 o1 U4 p5 J) E/ u
$ v" ?, o9 G, M* L6 a
  • 流程闭环:从用户每次提一个需求开始,一直到这个需求跟进结束,或者需求被讨论后打回,都要有一个详细的流程管理工具,笔者公司用的是JIRA。有了这个工具,就可以很好的看到需求的状态,便于跟进和统计,真正解放我们的笔记本。

    * z" w. [2 u4 R) p9 t. h' D# o
, m- \+ U. `6 ]2 A* @5 j
* H* ~$ [6 A, k  N
  • 把控好优先级:根据项目的定位,来划分需求的优先级。比如,对于一个运维平台项目,一般来讲用户比较固定,针对的是一群高玩SRE,那优先级考量是:稳定性 > 性能 > 功能 > 体验。
    8 Z5 v) L: E4 n" m- e, V( l0 P8 a

! \. G4 [6 b# a) h- R7 n! F
  • 对于优先级的考量,要经常与自己的上级沟通。由于观点和视野的不同,个人考虑的优先级会与小组或者部门的优先级有所偏离,此时与上级及时的沟通,可以将个人的目标与团队的目标对齐,争取产出最大化。- C- b" }; P$ i" W

      f& U* f# }1 Y5 ?+ K* a
" r7 v* v8 F. n' \# v7 q% F. y  [
8 u2 q+ X" f- f" S
  • 产品视角 & 抽象能力:我们管理好了需求,确认好了优先级,是不是按照我们的优先级埋头苦干就行了呢?答案当然是否定的。视角、见解不同的用户们提出一堆细碎的需求,如果我们从头来实现一遍,并不能真正让这些用户满意,却只会让系统越来越烂。
    % H3 C( R# e2 l/ t( A0 S

    % E2 O: E! ~  K; R# Q0 k9 ^( N
  U% T) |! \3 n9 r
  • 笔者之前就经手维护过这样的系统,勤劳的工程师兢兢业业,满足了一个又一个的需求,各种各样的高级功能。后来,却由于系统过于复杂,导致最基本、最常用的功能都要找半天。最终不得不重构。
    + L/ }  ?' g# K

    ( \; d* m* H6 ]
5 L1 U7 D; v* f9 }# r' ^# j

4 q' j  d+ k& @' {& \
  • 因此,去深度思考用户真正需要的是什么东西,而不是被业务推着走。将用户细碎的需求,真正抽象成平台要建设的一个一个的功能。6 Y1 I& B2 {* f$ M8 S! _: n

    : x8 o# W* T( `
4 W: I. \3 i  x: Q: W5 s4 p

& I9 H9 |, j" c" P. o
  • 经常思考一下:用户虽然提了这个需求,但是他真正的痛点在哪里;多个类似需求之间会不会有什么共通点;是否可以抽象出一个公用的模型,用一个功能来满足多个需求。

    , z/ k" l- i* r

    $ ]$ ~+ `. F; j9 S2 B+ T

. `" l2 C5 `% b: m
2、量化
* ~' u+ w$ ~( M
8 F( @1 ?8 F0 Y: V+ G2 M
7 H/ R. B0 `8 x( h4 M0 t
If You Can’t Measure It,You Can’t Improve It。量化是优化的前提。

: w. e) g/ s6 m0 ~% p

+ d& Q% W6 A  k( N5 }) }量化有很多方面,比如说量级、延迟、成本,都可以量化。把所有的点量化完之后,我们做事情就不会蒙着头乱撞,所做的事情、所维护的服务,也不再是一个黑盒。我们可以对它的上下游关系、自身的稳定性作出宏观、统筹的分析。进一步的压测及SLA均要依赖量化。
1 i9 X, j/ b1 i; s0 p' r% w$ x3 [
! Q8 o3 Y) M, [8 g' Z" O
3、制定SLA: G* ^/ a9 h5 r! q8 j

9 F4 L, U3 w. t& t, ^
+ U2 o3 ]2 z9 Q: V7 M
简言之,SLA就是在一定的限制条件下我们服务可以保证的质量;是服务的维护者完全的了解了自己的系统,对系统的瓶颈有了深刻的理解之后,所给出的服务质量的保证;同时也是我们服务自身能力的一种说明。

; ]; P; P  P) m3 s0 u) G

3 K1 J$ v5 F; t+ a/ o一个系统性能再好,也总会有瓶颈。而把瓶颈和风险让用户知晓,是我们的义务。对服务的维护者来说,在提供服务之时,约定好服务的SLA,既能从一定程度上规范使用者的行为,也能在出现问题的时候保护自己。
, R. t/ G: d  s2 \% O

  d* j% ~( c6 E  @2 N

8 l5 m$ P  T* q

五、除了做这些,我们还要思考什么?


8 Z$ ]7 W- i. f3 K: u2 t* f. `8 g( q

) G; p8 E/ J5 T
1、制定规范,并让规范在平台落地- \! J, \: D3 j) t0 x& \% V7 x
, h& `( u6 t- H0 W6 o
* x9 T0 K/ q( e
规范的制定是一个比较宏观的事情,一般情况是由稳定性负责部门向全公司整体给出的建议。约束的可能是全公司的变更的规则、以及平台的使用方式等。

& C* z& I8 a+ s% |+ a: b8 {6 u' U
. w* l7 H" J; c% F9 _6 ^2 ^- L! H
规范的落地,不能仅仅依靠各方业务的自觉性,也要在平台做好限制与引导。

* Z  t- k& }; Z2 X- z
% X) T0 i9 T" ?" w& N( e% z
我们做平台,最终产出的仍然应该是业务的价值:比如效率的提高、成本的降低、稳定性的提高等。规则在平台的落地,可以产生直接的业务价值。
6 k' c6 J+ H  L& N' ~& ]8 M

5 `& n/ Z! l7 x5 M" }( M7 v( {具体的实施方式可以考虑限制和引导两种手段:

* U3 O; u4 r4 l
; g( \: N- D( o: }) T/ t1 K
  • 限制:上线窗口的规范,非上线窗口必须走紧急流程由部门一级管理者审批;监控单台机器上报指标数的quota,都是使用的限制的手段。
    3 N, d- s6 D  q' |% `6 ?
' O  v: n# n  g5 C( W" y
; R& l1 @! g! K; ~; D: a
  • 引导:通过一些方式,让用户自觉的依照我们的规则来执行。可以使用奖励、通报的一些方式。比如笔者公司的变更信用分、监控健康分都是此类手段。
    ' _0 u9 v, {# L& V& K! x$ r

/ @0 v) g2 ]- a; X" o$ G4 x: K  F
2、协调开发与答疑
( j5 u; f" ]1 }' ?. Y( _. k2 _* S9 ?8 A7 t5 D, f

& b6 R  k: J  L, C2 ]  h+ \运维开发的同学们,除了要做自己的PM和QA之外,有趣的是,还要担任自己的客服。
" |8 r. t7 O+ s. M$ T! U

, }$ g; Q5 h. A8 K2 U, V5 {( p日常工作中,经典的答疑主要分为两类:使用方式、对平台的质疑。

/ ~; V0 |/ R: d" q  x, f
( ~& A# p; p( z
使用方式的日常咨询,首先可以完善用户手册,把所有的使用方式和常见Q&A都写好。其次可以考虑机器人答疑,目前笔者负责的系统都接入了机器人自动答疑,把一些常见的问题以及文档都加入到知识库里,基本问题都可以解答出来。

; V% l8 L* n0 T# N9 g6 U
, N; c% k' n/ q$ l" I
除了日常使用的答疑之外,也会有很多的“高玩”来Challenge我们的系统。这些人基本分为两类:
2 q$ L4 X; [2 n. t+ O; W1 F8 a* A3 X
- E' i2 k7 r9 m: h- r- C
  • 一类是对运维平台有深度思考的人,Chanllenge的同时会带来很多建设性的意见和建议;

    6 J" F; T3 ^- l
    , @* r* H- _2 A4 p6 s, E
8 |* ^2 U! o6 d5 i. x) o  W
  • 另一类就是单纯的小白用户,对系统思考不太深入,喜欢无脑Chanllenge。
    7 P8 G. v! X" f" A) Q
9 l5 \- ?2 Z% u$ j: ]
我们也要同时思考如何与这类用户说明,提高小白用户的体验。

- D" @* H/ [8 l- c0 c

8 |0 b( X- `$ h7 {) c! g" i( p因此,给出服务的SLA、做好服务的自监控、将所有内部状态通过自监控暴露给开发者,而不让自己的服务变成一个黑盒,是我们作为DevOps的基本素质。

* G/ q+ @' Q$ v

& X0 J. u. N% m. C+ Y; j
  E. l/ N, m# m6 U" f+ ?' \' Q& r: u

六、后记

; N' C+ }% p: S2 I4 {7 Y5 X
6 [- R8 A: P; q
时光荏苒,倏忽之间,我已从一个小小的实习生,成长到现在勉强可以独当一面的样子。这些年来,我一直在自动化运维平台开发领域耕耘。从刚开始重构服务树、权限系统模型、堡垒机登录;到后来的流量调度、监控系统报警与存储的深度建设,有很多个人的感悟与成长,梳理了一下,分享给大家。

& _/ u, l6 U1 D  G0 R
3 v1 L* N/ @3 o7 E
最后附上笔者思考本文时的脑图:
5 V7 ^1 \, p0 s) ~" ?( s
7 u+ c' ?* |2 F4 h# W
2.png

7 ^+ M6 e' }0 q( B& {! \

  @9 B9 Y$ B5 m; f# d2 U

% M. x" J3 f' T- A1 Q' [: j
4 Q' v/ x5 Y( \
原创:高家升
3 b7 D. o2 U  U, E" N6 _
; n  {  }& D6 J

本版积分规则

选择云运维时代的王牌讲师-长河老师,助你轻松入门ITIL Foundation培训课程

QQ|小黑屋|手机版|Archiver|艾拓先锋网 ( 粤ICP备11099876号-1|网站地图

Baidu

GMT+8, 2019-3-20 03:29 , Processed in 0.218669 second(s), 32 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表