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

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

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

扫描二维码登录本站

QQ登录

只需一步,快速开始

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

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

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

参加活动:0

组织活动:12

发表于 2018-8-27 15:35:54 | 显示全部楼层 |阅读模式 来自- 广东广州
本帖最后由 monicazhang 于 2018-8-27 15:53 编辑 & Q" v# C) L% x+ m. ]0 e/ k
2 J1 {$ w; [; S3 l! K+ N/ x0 v6 H# {
运维开发这个岗位与普通的业务开发不同,与日常的运维工作也不同。要求兼顾开发与运维两种能力。既要掌握不弱于业务开发的开发技术;又要负责SRE同学日常的运维能力;上线之前,还要像QA同学一样,对自己的服务进行测试和分级变更。
! G8 k. c" S4 F9 q4 n7 D
6 |3 @3 V3 z: E
多种能力的交叉,造就不一样的视角:这群人给自己起了一个很简约的名字:DevOps

! B7 C5 V/ f% I- E  j
1.png

* H! F( C( F5 |, p; s
DevOps
( X! |" V5 |! U* N/ E$ K0 G0 l, o  F( w

4 O# r/ K6 d3 m
按百度百科解释:DevOps是开发、技术运营和质量保障三者的交集。在我看来,DevOps其实只是一种方法论,从这种综合的视角出发,包含一些基本原则和实践方法,仅此而已。
7 G/ g8 |& W, D/ ^
2 M6 _- p/ S6 p0 Z# M& E0 U
DevOps从架构、开发、测试、发布、运维、变更整个流程来考量,从这种综合的视角出发,能将部门之间的沟通隔阂消灭于无形,会给我们公司和项目注入新的活力。

- ]8 b5 b" U3 b
: E$ F2 a9 K* F, D4 w
DevOps这个概念,本文暂不做讨论,本文内容只针对运维领域自动化平台开发的工作进行探讨。
2 F( t+ I+ O5 q: o; n
$ [; F, ?( o" Z

一、前言


- w5 |/ m" S4 ^' h; B2 q
运维开发的工作,所需能力的复杂,工作性质的交叉,自然会导致很多同学在其中会有些困扰。
9 ~% c" U8 v1 ~9 h) c% E1 [

( V" G% M" p) T& }* w
很多刚毕业的小同学,接到运维开发的offer的时候,很可能是一头雾水:“运维?开发?到底是运维还是开发?”

. B+ A) s- C+ p" v, N, c0 {& C# V/ Y

4 L1 J9 n4 q, r1 g; ]& I
有很多从业多年的同学,拼命的追求技术与对底层的探索,却忽略了产品层面的思考。

, z, z( j2 V2 h; j' ?9 U
. a: n. @1 W1 R1 @, F
还有很多整天忙忙碌碌的同学,在业务方各种零碎的需求中修修改改,消耗了大多数的时间,最终平台却变得千疮百孔。
8 F5 ]- s8 U4 `( M& P+ W

/ Z4 G0 m' K! q5 y; e+ E2 _2 {$ K) b9 h
本文,我将自己关于这些问题的思考分享给大家。

5 `8 K/ @1 U& ~) a, W5 C6 F

7 C2 r6 Z7 f# ~. q$ h, F
  C  o: i( h* X7 a: V3 {8 L! Y- U. I

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

4 p# }' N1 p' h, s# Q
既然我们是在做平台,那我们要了解的第一点就是:好的运维平台是什么样子的?

( ~% P  v; e5 n# K  t0 Y
/ x2 S: G3 b0 M2 O; ]& m! x5 l
如果让我们来从头设计一个平台,我们应该如何去考量?
! a0 Q/ y8 p) g! t

- m, A7 ?4 g4 x) t6 z! z) O- F
1、效率 & 成本的均衡, N* v0 L6 ?7 ?) ^9 t
' S+ U' u* Y. x
运维平台是服务于运维的。对运维来说,除了稳定性之外,最重要的无非就是效率与成本。如果我们的平台可以用更少量的时间或资源成本来提高更多的效率,那就是一个非常成功的平台了。

. D" R9 B9 Y$ F- n4 Y, J+ l6 M. c
- x6 L, v: ~; ^4 A
至于如何量化比较,就因系统而异了。
! {. v" [0 n9 Q+ ~: e
# t9 o8 E* Z3 a& g- e! g- l
2、体验 & 人性化
" Q" r# x' b. d" g( O* d
: m! O# a; b2 e  e- [$ v

7 R5 a- c* x0 I# O为什么我要把体验放在第二位?

, I" h, o( x! F# V

) D/ \7 s6 h: B, r0 q+ E
因为有太多的运维开发工程师,在开发的过程中,过多地注重系统的稳定性和性能,完全不把体验放在眼里了。
7 W: t. ]) T  i8 e6 q2 c1 p$ B
9 u: |9 p/ ]! R; s+ j8 o* w3 M
我想说的是,有时候,如果不关注用户体验,我们做了再好的功能,没有人用,那这个功能意义何在?用户价值与用户体验在某些情况下,是会画等号的。

- x  G" z0 J) X
  c$ `) ?- b1 ~! ]
3、优秀的系统架构

+ `& O( R* x5 z7 E4 ~" n$ O3 }; \! V
/ G, ?& t! E; x+ z% v
在业界,无论是运维系统也好,业务系统也好,优秀系统的架构都是大同小异的:

0 V1 ]" y' H6 m& r

6 \' H0 v4 V) x$ x0 _0 w
  • 稳定性:负载均衡、多活等。# z3 m8 r0 E$ m4 s2 a. w' P
    * |' l! z0 K0 C4 X# R

* W8 B) W1 j! l. w) `4 H7 x2 B% Y  D& [$ e+ e
  • 扩展性:每次增加功能,可以很小的开发成本实现,而不是每次都要重构。1 u: b, d* ^" h
- z/ o1 l& |) F/ r, |: [5 T

* F2 C$ [# B; p8 |7 b, @; Y
  • 伸缩性:没有核心的单点,大部分性能瓶颈,都可以通过横向扩展来解决。/ Z, l$ I; R6 ~$ E* q+ G

3 Z1 u3 w4 ]8 N+ F0 G% W8 z$ h+ K  ^" `6 k8 l
  • 自我保护:把可能会导致性能瓶颈的点都拆解开,用队列、限流等手段消除流量突增的高峰带来的危害,保护自身。/ u$ s. \) K) u

( d3 i  i' [/ ^! v0 t  o* y7 Y
! g7 x- }% M- H$ p# Z4 e
3 c6 Q5 r0 M' w. I3 M- {
  • 安全性:敏感服务加入权限与认证,Web服务避免常见的漏洞如SQL注入、XSS、CSRF等。做好操作记录方便后续审计,尽量不要出现短板。
    ! m2 O+ u. L9 q* a# P0 I
3 m: w8 E3 g; _/ j- r8 J
+ a/ s8 M2 s- K1 d

9 }% I% W5 C  s4 p7 B, K2 h
: |( _( n! p3 s
、如何运维自己开发的平台?
) z+ Y! s8 `+ W; m: V9 v, O
  W" e; h# e) b4 }# w. a
运维开发在大多数时候,要负责运维自己开发出来的系统,俗称吃自己的狗粮;而很多人跳槽之后,第一件事情,也是从运维别人的系统开始的。那我们如何运维好一个平台呢?
# O, ?$ r4 p# w/ {

0 G  R+ Z0 K/ _) V运维与开发的工作,思路其实不尽相同。虽然都是基于稳定性来考量,但可能要想的更多、更广,任何有可能影响到我们业务的稳定性的因素,都要考虑在内。

) u- F  e+ i0 h/ q
5 {+ E9 [; S+ q; w
用我的总监的一句话来讲,就是:我们运维同学与开发同学,最大的不同点,就是稳定性的意识。
0 h6 \5 v/ c( e# Z( ?+ Z4 T. X
. i  I: Y) F5 A$ [. C
1、架构上的稳定性
: q1 ^( m4 L: l9 y$ m
  e# h, l& w$ D+ s, w3 r

5 ?7 L/ r; s% t6 u! i  \3 i9 E
这个其实更多的是比如多活、负载均衡、流量调度、硬件冗余之类的考量:服务在实例挂掉的时候,如何不影响稳定性;专线断开的时候,如何仍然正常的提供服务等等。

% @: T1 }4 J& k' T
! w7 h" g9 }+ D
2、快速地发现问题
* X8 G2 x9 g. P* n9 V7 D9 ]7 E0 b
1 W+ j1 }8 ?$ `; v

1 k) y8 r" r+ A% L; F
无论我们的架构多么完善,也很难做到尽善尽美。那么在一些需要人为介入处理的故障中,快速地发现异常,能直接降低服务的不可用时长。因此,对于一般的服务,将报警配置地更完善是我们能快速定位异常的第一步。

- N  x" H5 f1 g5 t
# \. Y1 ^) a8 l) u, f2 L* X) }
还有,对于监控系统,自身的故障不能通过自身的监控来发现,最好还有一套独立的自监控。

3 I. s! U6 G% ]* H9 U" y- i) B

) a! a( Z$ c4 w+ j
3、应急预案&演练
! E0 i  m, r# X8 Z0 W& I* S- g
. j6 W/ S1 f8 v) M

/ F$ `! T! T( N) n! h; q9 C" z
在梳理一个服务的运维工作的时候,其实我们能很明确的感知到某个地方出问题需要人力介入。而除变更之外的一般的故障,我们都是可预见的。一旦真的出现这种问题,如果我们没有准备,即使知道如何去做,也可能会因为手忙脚乱而出错。
$ u9 Z' j* [6 U# t" M3 t
' J$ \* D" m, o  D
因此,设定一些可能发生情况的应急预案,定时演练,是一个可以在故障时快速恢复服务的手段。

# M; D3 Z3 s: S8 M  C$ q, X( |
, l0 u4 ]7 J3 l! e  Y$ g
4、自我保护. t# z; Z: u7 W; r0 K! a' ~
9 t/ J( @" k* C. M! P8 Z; b3 F. [
" r0 r0 t: K6 z& H7 F/ {. ^
一般的系统,都有上游,如何保证上游的数据异常对自身产生影响,也是很重要的一点。总结起来,总共有三类:
2 e2 ]1 d; r2 c3 `

( G1 p' H$ @2 Y7 d2 O4 r
  • 过载保护:上游流量太大,导致自身服务不堪负重。这种情况要根据场景不同,考虑加入消息队列,或者限流。5 Y# v( s0 D( l% L

    4 M/ D+ P5 m, h4 [; L

* j, n! S: z+ N- A0 r
  • 脏数据保护:上游来的数据,是否应该完全信任?是否有脏数据会来影响我内部数据的准确性?比如安全扫描的流量,很大程度上就会对很多系统产生脏数据。这种最好有过滤的规则的配置,能摘除这部分流量。! @* @4 Y) x# b1 Y* G3 D$ ~

    4 T7 y1 X8 X/ x+ L

" p! S0 m! r- g. D# Q+ Y

! ]1 F1 A3 h8 {) ~
  • 上游变更保护:上游的变更,需要及时知晓和跟进。如果上游不够规范,很可能会修改接口或者数据格式。即使上游规范,也要跟进上游变更容易造成的影响,人为确认没有问题。2 F9 Z3 s, j) V

    / i# M4 @5 x+ _) G. y- i

# [. P3 f2 L% [! Q" F3 B
) s/ \0 ^8 I( P( o4 i+ R( L
' }% k$ T; d- W" ^
5、容量规划
& B. T5 Q( o+ ]# \) ?# i

2 c0 z9 |5 E* `+ }
随着系统负载的升高,系统的服务能力并不是线性下降的。当负载到达临界线的时候,一个逐渐变慢的系统最终会停止一切服务。因此,要在系统瓶颈到来之前,预估未来一段时间内服务的量级,在量级到来之前,做好应对措施。DevOps
" E/ |% ~8 Z- ~) V- G

+ H& x: z, Y1 A& q笔者公司目前有一个Topic,就是全链路压测。运维团队与所有业务团队一起建设,压测常态化,每时每刻对系统全链路各个环节的瓶颈都了如指掌。其实也是在做这件事情。
$ a: Z% \- u  K
$ _1 g! l! Y' Z8 d
6、变更管理
1 `+ P9 i4 I8 T" y
: n9 E4 D6 t9 ~$ x! P% |2 P
, y3 A( H, y8 r9 f1 J5 {/ y: b6 ^
SRE的经验告诉我们,大概70%的生产事故都是由某种部署的变更而触发。因此要管理好我们的变更的机制:

2 x% n; l% t0 ?  O4 b- |
3 A6 t6 f# U* r6 e; w. f0 G9 J' {
  • 采用分级发布机制:先pre、再小流量、再中流量、再全量。' P; e! P& z; z" H! H
    & ~: n  k1 \; Q/ \

( `+ N1 U) ]# X) x+ v
  • 制定全面CheckList:保证变更部分所有功能都有测试可以覆盖,能快速发现问题,第一时间回滚。) Z1 I7 Q# U' p! n

    ( R3 V2 Y2 ~: g/ v0 \

( c9 q  z& D: o( q6 ^& H

3 c, W3 a( g  m1 _7 b1 C- Y, j, I

( @4 W  b+ h+ `6 W' f) U$ J
  • 出现问题,先回滚,再定位:这个不用多说,先止损,再慢慢查问题。3 _0 N9 C" S, L( f2 y1 O. Y
    $ T' I7 L# C. K2 q: S6 ]# I5 Q! j
! q- ?% e" e3 G& j7 x& H* @7 n9 }

% I6 O$ i9 G! Y/ `4 a

* G% s9 C% n8 H5 {; b1 n

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


1 v9 \# e( u! [6 Z. `

6 W1 [& l* s- x# x
运维开发的定位,注定要比业务开发承担更多的责任。因为这群人除了是自己的RD,还要自己做自己的PM、OP、QA。

, Z/ @: ^0 e; S; d7 _4 A0 O& {

( l" _# ]8 v" T& l0 ~因此,我们要考量的,还有产品和需求层面的东西:

1 _. z/ F9 z* ?5 D
% Z  t; h6 U2 g. a1 j) T- W  e8 o
1、需求管理' y* X# _/ P5 g/ F5 L& ^6 C
9 Z& p2 _' J1 \8 m3 {

+ H  h+ n3 v7 ^$ P* {4 w+ N9 K
作为开发,尤其是没有正经PM的开发,管理好需求可以让我们把精力放在最重要的地方,解放我们的精力、提高产出。

8 r! t$ O; ~; s( Q! g% h; x: Y, r+ ~
$ C: A* \. J* X4 W6 j* |
  • 流程闭环:从用户每次提一个需求开始,一直到这个需求跟进结束,或者需求被讨论后打回,都要有一个详细的流程管理工具,笔者公司用的是JIRA。有了这个工具,就可以很好的看到需求的状态,便于跟进和统计,真正解放我们的笔记本。

    ; k: F( k& _) e2 V

4 F+ G- C( Q4 @- V( j
, W7 c) V. O* r
  • 把控好优先级:根据项目的定位,来划分需求的优先级。比如,对于一个运维平台项目,一般来讲用户比较固定,针对的是一群高玩SRE,那优先级考量是:稳定性 > 性能 > 功能 > 体验。
    $ s6 ^5 E" ]* u, k

- Q3 Z2 i" [/ L' f2 y5 M/ S
  • 对于优先级的考量,要经常与自己的上级沟通。由于观点和视野的不同,个人考虑的优先级会与小组或者部门的优先级有所偏离,此时与上级及时的沟通,可以将个人的目标与团队的目标对齐,争取产出最大化。
    ' Z7 I+ k3 {% S/ B+ n
    : H$ W5 q+ v  P' A
9 U8 {* M; j" J4 r/ _+ u, c
! ]7 ?1 C  r# a% r
  • 产品视角 & 抽象能力:我们管理好了需求,确认好了优先级,是不是按照我们的优先级埋头苦干就行了呢?答案当然是否定的。视角、见解不同的用户们提出一堆细碎的需求,如果我们从头来实现一遍,并不能真正让这些用户满意,却只会让系统越来越烂。/ a5 F# g9 r4 P) E) B* U
    + q4 `* a8 K0 {$ X5 _$ n5 @

, B6 `: M' |& @
  • 笔者之前就经手维护过这样的系统,勤劳的工程师兢兢业业,满足了一个又一个的需求,各种各样的高级功能。后来,却由于系统过于复杂,导致最基本、最常用的功能都要找半天。最终不得不重构。: o' u+ E, {3 b. ]0 E2 K+ k

    . o) {2 H3 Y* h6 V- Y5 {
$ A: P9 e  U1 T4 m
. a6 a7 _9 V) `
  • 因此,去深度思考用户真正需要的是什么东西,而不是被业务推着走。将用户细碎的需求,真正抽象成平台要建设的一个一个的功能。
    + P+ ~( E3 R" i0 p( O6 a
    : S0 F, W& w+ V3 H5 g. m, i

6 t4 P( `: Y# E1 J% f
6 r) H2 P4 p% F
  • 经常思考一下:用户虽然提了这个需求,但是他真正的痛点在哪里;多个类似需求之间会不会有什么共通点;是否可以抽象出一个公用的模型,用一个功能来满足多个需求。
      V* p. C3 i5 e8 m8 e' O
    & C& y. ~2 H# I4 r% g
% D+ D2 m& O. A: k/ T5 @$ l
2、量化6 X8 g- B9 t2 }8 g7 F; I$ d

5 I% e: G6 K* R3 }+ ]4 o9 {

9 q! X- P5 ?. Z0 JIf You Can’t Measure It,You Can’t Improve It。量化是优化的前提。
# {, q/ K2 t9 ^" ]- @. y3 i7 s4 ~
( n* U( s' h" B5 d( t
量化有很多方面,比如说量级、延迟、成本,都可以量化。把所有的点量化完之后,我们做事情就不会蒙着头乱撞,所做的事情、所维护的服务,也不再是一个黑盒。我们可以对它的上下游关系、自身的稳定性作出宏观、统筹的分析。进一步的压测及SLA均要依赖量化。
/ c1 d( z0 V5 u+ G2 e5 q

. T1 }4 t8 D) d5 }7 {5 n0 r5 g
3、制定SLA5 L5 B: r2 s9 ?% [# f; Y
0 q+ D5 e6 d- Y9 m" |9 {' }
* W* `! G$ X; B, Z
简言之,SLA就是在一定的限制条件下我们服务可以保证的质量;是服务的维护者完全的了解了自己的系统,对系统的瓶颈有了深刻的理解之后,所给出的服务质量的保证;同时也是我们服务自身能力的一种说明。

# ~, W2 e* D  L3 f+ E
# h" z3 W: T% n& x* j& ]) M
一个系统性能再好,也总会有瓶颈。而把瓶颈和风险让用户知晓,是我们的义务。对服务的维护者来说,在提供服务之时,约定好服务的SLA,既能从一定程度上规范使用者的行为,也能在出现问题的时候保护自己。

% `+ \# I; F9 K9 w) u0 Z: O

/ |. G) j, N+ n- P' v: ^
- x: I3 h  i9 l. n0 c

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

5 K2 w- k. }# e0 S( Q& G


  J7 B0 A* T0 d% _6 ~% D
1、制定规范,并让规范在平台落地& g+ H2 A7 a* U2 o; P3 P; U
* I1 c: F  Z0 X. P# m% \
4 Z; |6 T- G7 a, T+ Q' l
规范的制定是一个比较宏观的事情,一般情况是由稳定性负责部门向全公司整体给出的建议。约束的可能是全公司的变更的规则、以及平台的使用方式等。
& @( H% S( K5 g" ^; e' r

2 ~7 l+ d4 ]- R$ m: M& R, H% x规范的落地,不能仅仅依靠各方业务的自觉性,也要在平台做好限制与引导。
0 @2 h) `  L. t7 w0 S  @9 `4 x

; A% M& X- V; `1 |5 S我们做平台,最终产出的仍然应该是业务的价值:比如效率的提高、成本的降低、稳定性的提高等。规则在平台的落地,可以产生直接的业务价值。

& [/ V- O1 G2 N1 g( {/ r

( v, P( c$ i+ T8 a" G具体的实施方式可以考虑限制和引导两种手段:
9 a! R6 K) Q; X$ y; {

9 I( B. O0 L; m" }; p" P
  • 限制:上线窗口的规范,非上线窗口必须走紧急流程由部门一级管理者审批;监控单台机器上报指标数的quota,都是使用的限制的手段。

    % v  c6 L$ Y, u/ A/ z4 M0 L

9 I* J1 c: R# @# C/ D& Z
' b0 s7 R" v( G  B4 g1 @
  • 引导:通过一些方式,让用户自觉的依照我们的规则来执行。可以使用奖励、通报的一些方式。比如笔者公司的变更信用分、监控健康分都是此类手段。
    5 ]: B7 z7 K) |. J, U8 P$ E5 a

. `: o2 M- R9 c' Z9 y4 H3 ?" r
2、协调开发与答疑
" z5 N- U) U/ s2 H. r, m4 i. u
3 P# _. M4 a) ]; Y' T8 y# F5 b
8 G7 w, a; ~; \3 u4 u
运维开发的同学们,除了要做自己的PM和QA之外,有趣的是,还要担任自己的客服。

$ x8 [* V9 [" O# n8 I9 r9 `' W
- j& Z' d% ?6 V
日常工作中,经典的答疑主要分为两类:使用方式、对平台的质疑。

0 A+ \0 A, J1 [7 k& \0 Q+ p
2 T) U" D! t  L+ p
使用方式的日常咨询,首先可以完善用户手册,把所有的使用方式和常见Q&A都写好。其次可以考虑机器人答疑,目前笔者负责的系统都接入了机器人自动答疑,把一些常见的问题以及文档都加入到知识库里,基本问题都可以解答出来。

" H" X7 T7 [" T4 ?/ Y. U
& S" b6 B4 E/ y  \( n3 f
除了日常使用的答疑之外,也会有很多的“高玩”来Challenge我们的系统。这些人基本分为两类:
# S, m) s( g" w& f
, W, a0 M6 V! x6 h' g
  • 一类是对运维平台有深度思考的人,Chanllenge的同时会带来很多建设性的意见和建议;

    $ ?  R8 a! a( V* c1 D# j
    ; `3 a" D; a3 A+ w" [

1 h  n  e/ J: C" ^4 u
  • 另一类就是单纯的小白用户,对系统思考不太深入,喜欢无脑Chanllenge。
    . r4 g9 u- Z- G! ]5 I# d: D# D" g

" a0 C8 O8 a) a3 A9 S, A  l+ E) m
我们也要同时思考如何与这类用户说明,提高小白用户的体验。

& G" g' m2 y; H' ]7 F
) B6 `6 M3 C! ^( l
因此,给出服务的SLA、做好服务的自监控、将所有内部状态通过自监控暴露给开发者,而不让自己的服务变成一个黑盒,是我们作为DevOps的基本素质。
) R* b3 v5 C/ u5 p' U1 {' c0 @% p

' y, t5 l' z9 y0 N; B# |
3 }  k5 f4 w6 I" a, u# W* G

六、后记

$ L9 g8 w$ k# F) l
" j; ]5 \) ]* r  {. B* t
时光荏苒,倏忽之间,我已从一个小小的实习生,成长到现在勉强可以独当一面的样子。这些年来,我一直在自动化运维平台开发领域耕耘。从刚开始重构服务树、权限系统模型、堡垒机登录;到后来的流量调度、监控系统报警与存储的深度建设,有很多个人的感悟与成长,梳理了一下,分享给大家。

5 L& ]9 G# b; K

) \7 h5 ~& _: z3 f最后附上笔者思考本文时的脑图:
  O/ {0 `" b9 ]  M/ ~+ |* {0 ~
8 z- K( t% \4 N
2.png
& F; ?7 L, a, x. j
' H# |7 w/ s' g( a/ }) P
8 }6 Q; k* F% T& z- a
+ m3 V9 e* }; z5 P. j
原创:高家升

+ U4 p7 b8 l. n; N* S4 R# {5 W3 E; d! C( I$ C) ^* d! T& _+ v

本版积分规则

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

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

Baidu

GMT+8, 2019-1-23 22:17 , Processed in 0.294876 second(s), 32 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

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