自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

硬核!如何在容器中做時(shí)間漫游者

存儲(chǔ) 存儲(chǔ)軟件
分布式數(shù)據(jù)庫要實(shí)現(xiàn)全局一致性快照,很多方案使用時(shí)間做邏輯時(shí)鐘,所以需要解決不同節(jié)點(diǎn)之間時(shí)鐘一致的問題。

[[402031]]

本文轉(zhuǎn)載自微信公眾號(hào)「董澤潤的技術(shù)筆記」,作者董澤潤。轉(zhuǎn)載本文請(qǐng)聯(lián)系董澤潤的技術(shù)筆記公眾號(hào)。

題目稍有些標(biāo)題黨,最近公司想用 chaos-mesh 對(duì) k8s 做混沌測試,開始做前期的調(diào)研,發(fā)現(xiàn) pingcap[1] 對(duì)時(shí)間的注入非常硬核,而且最終方案居然是實(shí)習(xí)生構(gòu)思出來的 ^^ 感謝 pingcap 貢獻(xiàn)的項(xiàng)目

TL;DR: 通過劫持 vdso, 將時(shí)間函數(shù)跳轉(zhuǎn)到 hack 過的匯編指令來實(shí)現(xiàn) time skew. 原理不難懂,但細(xì)節(jié)超多,參考官方文檔[2]

為什么需要 time skew

可以參考 Chaos Mesh - 讓時(shí)間在容器中自由搖擺[3], 簡單來說就是:

分布式數(shù)據(jù)庫要實(shí)現(xiàn)全局一致性快照,很多方案使用時(shí)間做邏輯時(shí)鐘,所以需要解決不同節(jié)點(diǎn)之間時(shí)鐘一致的問題。但往往物理節(jié)點(diǎn)上的物理時(shí)間總是會(huì)出現(xiàn)偏差,不管是使用 NPT 服務(wù)同步也好,或者其他方法總是沒辦法完全避免出現(xiàn)誤差,這時(shí)候如果我們的應(yīng)用不能夠很好的處理這樣的情況的話,就可能造成無法預(yù)知的錯(cuò)誤。

其實(shí)這很符合工程設(shè)計(jì)哲學(xué):design for failure, 任何一個(gè)硬件或是軟件都會(huì)有錯(cuò)誤(fault),系統(tǒng)如何在不影響對(duì)外提供服務(wù)的前提下,如何處理這些故障,就是我們常說的 fault tolerance

但是對(duì)于非金融業(yè)務(wù)來說,時(shí)間偏移一點(diǎn)影響并不大,相比其它 chaos, time的場景還是受限一些

如何注入

從實(shí)體機(jī)的經(jīng)驗(yàn)來看,所謂的混沌測試都比較直觀的,比如用 tc 做網(wǎng)絡(luò)的丟包,限速來模擬網(wǎng)絡(luò)故障,使用 stress 模擬 cpu 壓力。但是在容器中做如何模擬 time skew 呢?

如果直接使用 linux date 命令修改,會(huì)影響到宿主機(jī)上其它所有容器。有沒有方法能只影響某個(gè)容器?

之前發(fā)過一篇文章 時(shí)鐘源為什么會(huì)影響性能[4], 從中可以看到,go 調(diào)用系統(tǒng)時(shí)間函數(shù)時(shí),會(huì)先調(diào)用 vdso 的代碼,如果時(shí)鐘源符合條件,直接在用戶空間完成,并不會(huì)進(jìn)入內(nèi)核空間,所以針對(duì)這一現(xiàn)象,syscall 劫持的方法就不能使用了

那么是否可以直接修改 vdso 段代碼呢?

查看 vdso

  1. # cat /proc/1970/maps 
  2. ...... 
  3. 7ffe8478a000-7ffe847ab000 rw-p 00000000 00:00 0                          [stack] 
  4. 7ffe847bb000-7ffe847be000 r--p 00000000 00:00 0                          [vvar] 
  5. 7ffe847be000-7ffe847bf000 r-xp 00000000 00:00 0                          [vdso] 
  6. ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall] 

可以看到 vdso 代碼段的起始邏輯地址,同時(shí)注意權(quán)限位是 r-xp, 這就意味著用戶態(tài)的進(jìn)程是無法直接修改該內(nèi)容。

真的就沒辦法了嘛?有的,ptrace[5] 法力無邊

The ptrace() system call provides a means by which one process (the "tracer") may observe and control the execution of another process (the "tracee"), and examine and change the tracee's memory and registers. It is primarily used to implement breakpoint debugging and system call tracing.

ptrace 提供了一種修改和觀察其它進(jìn)程的手段,包括修改內(nèi)存值和寄存器,巧了這些 chaos-mesh 都用到了。如何實(shí)現(xiàn) go 調(diào)試器[6] 這篇文章也講了 ptrace 的用途,很棒的文章。

整體實(shí)現(xiàn)

這就是簡單的流程圖,主要代碼都是 time_linux_amd64.go[7], 當(dāng)前僅支持 linux amd64 平臺(tái),不支持 Windows/MacOS

  1. // ModifyTime modifies time of target process 
  2. func ModifyTime(pid int, deltaSec int64, deltaNsec int64, clockIdsMask uint64) error { 
  3.   ...... 
  4.  runtime.LockOSThread() // 將當(dāng)前 goroutine 綁定底層線程 
  5.  defer func() { 
  6.   runtime.UnlockOSThread() 
  7.  }() 
  8.  
  9.  program, err := ptrace.Trace(pid) // ptrace 獲得 program 
  10.  if err != nil { 
  11.   return err 
  12.  } 
  13.  defer func() { 
  14.   err = program.Detach() 
  15.   if err != nil { 
  16.    log.Error(err, "fail to detach program""pid", program.Pid()) 
  17.   } 
  18.  }() 
  19.  
  20.  var vdsoEntry *mapreader.Entry // 遍歷 entry 找到 vdso 
  21.  for index := range program.Entries { 
  22.   // reverse loop is faster 
  23.   e := program.Entries[len(program.Entries)-index-1] 
  24.   if e.Path == "[vdso]" { 
  25.    vdsoEntry = &e 
  26.    break 
  27.   } 
  28.  } 
  29.  if vdsoEntry == nil { 
  30.   return errors.New("cannot find [vdso] entry"
  31.  } 
  32.  
  33.  // minus tailing variable part 
  34.  // 24 = 3 * 8 because we have three variables 
  35.  constImageLen := len(fakeImage) - 24 
  36.  var fakeEntry *mapreader.Entry 
  37.  
  38.  // find injected image to avoid redundant inject (which will lead to memory leak) 
  39.  for _, e := range program.Entries { 
  40.   e := e 
  41.  
  42.   image, err := program.ReadSlice(e.StartAddress, uint64(constImageLen)) 
  43.   if err != nil { 
  44.    continue 
  45.   } 
  46.  
  47.   if bytes.Equal(*image, fakeImage[0:constImageLen]) { 
  48.    fakeEntry = &e // 遍歷找到 fake Image Entry,不能重復(fù)生成 
  49.    log.Info("found injected image""addr", fakeEntry.StartAddress) 
  50.    break 
  51.   } 
  52.  } 
  53.  if fakeEntry == nil { // 如果 fakeEntry 不存在,用 Mmap 分配內(nèi)存,內(nèi)容是 fakeImage 匯編指令 
  54.   fakeEntry, err = program.MmapSlice(fakeImage) 
  55.   if err != nil { 
  56.    return err 
  57.   } 
  58.  } 
  59.  fakeAddr := fakeEntry.StartAddress 
  60.  
  61.  // 139 is the index of CLOCK_IDS_MASK in fakeImage 寫 clockidsmask 
  62.  err = program.WriteUint64ToAddr(fakeAddr+139, clockIdsMask) 
  63.  if err != nil { 
  64.   return err 
  65.  } 
  66.  
  67.  // 147 is the index of TV_SEC_DELTA in fakeImage 寫偏移量秒 
  68.  err = program.WriteUint64ToAddr(fakeAddr+147, uint64(deltaSec)) 
  69.  if err != nil { 
  70.   return err 
  71.  } 
  72.  
  73.  // 155 is the index of TV_NSEC_DELTA in fakeImage 寫偏移量納秒 
  74.  err = program.WriteUint64ToAddr(fakeAddr+155, uint64(deltaNsec)) 
  75.  if err != nil { 
  76.   return err 
  77.  } 
  78.   // 找到 clock_gettime 在 vdso 中的位置 
  79.  originAddr, err := program.FindSymbolInEntry("clock_gettime", vdsoEntry) 
  80.  if err != nil { 
  81.   return err 
  82.  } 
  83.   // originAddr 位置 hijack, 寫上 jump 指令,跳轉(zhuǎn)到 fakeImage 
  84.  err = program.JumpToFakeFunc(originAddr, fakeAddr) 
  85.  return err 

代碼寫上了注釋,分別對(duì)應(yīng)上面的流程圖。下面分解來看。

1. Ptrace

  1. type TracedProgram struct { 
  2.  pid     int 
  3.  tids    []int 
  4.  Entries []mapreader.Entry 
  5.  
  6.  backupRegs *syscall.PtraceRegs 
  7.  backupCode []byte 

TracedProgram 結(jié)構(gòu)體比較簡單,pid 是待注入 chaos 的進(jìn)程 id, 同時(shí) tids 保存所有的線程 id, Entries 是進(jìn)程邏輯地址空間,

Trace 函數(shù)在代碼 ptrace_linux_amd64.go[8] 中

通過讀取 /proc/{pid}/task 獲取進(jìn)程的所有線程,然后分別對(duì)所有線程執(zhí)行 linux ptrace 調(diào)用。然后生成 Entries, 什么是 Entry 呢?就是上文提到的 /proc/{pid}/maps 內(nèi)容

  1. ...... 
  2. 7ffe8478a000-7ffe847ab000 rw-p 00000000 00:00 0                          [stack] 
  3. 7ffe847bb000-7ffe847be000 r--p 00000000 00:00 0                          [vvar] 
  4. 7ffe847be000-7ffe847bf000 r-xp 00000000 00:00 0                          [vdso] 
  5. ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall] 

2. Mmap FakeImage

查找 vdso[9], 如何失敗,直接退出。一般 vdso 都在最后,所以從尾開始遍歷

同時(shí)還要查找 fakeEntry, 如果存在,直接復(fù)用。否則會(huì)造成內(nèi)存泄漏,當(dāng)然了,一直創(chuàng)建新的 fakeEntry .....

  1. // MmapSlice mmaps a slice and return it's addr 
  2. func (p *TracedProgram) MmapSlice(slice []byte) (*mapreader.Entry, error) { 
  3.  size := uint64(len(slice)) 
  4.  
  5.  addr, err := p.Mmap(size, 0) 
  6.  if err != nil { 
  7.   return nil, errors.WithStack(err) 
  8.  } 
  9.  
  10.  err = p.WriteSlice(addr, slice) 
  11.  if err != nil { 
  12.   return nil, errors.WithStack(err) 
  13.  } 
  14.  
  15.  return &mapreader.Entry{ 
  16.   StartAddress: addr, 
  17.   EndAddress:   addr + size
  18.   Privilege:    "rwxp"
  19.   PaddingSize:  0, 
  20.   Path:         ""
  21.  }, nil 

注意,這不是簡單的調(diào)用 Mmap Syscall !!! ptrace.Syscall[12] 是利用 ptrace 控制進(jìn)程,讓目標(biāo)進(jìn)程單步執(zhí)行 syscall

  1. // Syscall runs a syscall at main thread of process 
  2. func (p *TracedProgram) Syscall(number uint64, args ...uint64) (uint64, error) { 
  3.  err := p.Protect() // 保存目標(biāo)進(jìn)程的寄存器 
  4.  if err != nil { 
  5.   return 0, err 
  6.  } 
  7.  
  8.  var regs syscall.PtraceRegs 
  9.  
  10.  err = syscall.PtraceGetRegs(p.pid, &regs) 
  11.  if err != nil { 
  12.   return 0, err 
  13.  } 
  14.  regs.Rax = number // 設(shè)置操作 syscall number, 填充其它參數(shù) 
  15.  for index, arg := range args { 
  16.   // All these registers are hard coded for x86 platform 
  17.   if index == 0 { 
  18.    regs.Rdi = arg 
  19.   } else if index == 1 { 
  20.    regs.Rsi = arg 
  21.   } else if index == 2 { 
  22.    regs.Rdx = arg 
  23.   } else if index == 3 { 
  24.    regs.R10 = arg 
  25.   } else if index == 4 { 
  26.    regs.R8 = arg 
  27.   } else if index == 5 { 
  28.    regs.R9 = arg 
  29.   } else { 
  30.    return 0, fmt.Errorf("too many arguments for a syscall"
  31.   } 
  32.  } 
  33.  err = syscall.PtraceSetRegs(p.pid, &regs) 
  34.  if err != nil { 
  35.   return 0, err 
  36.  } 
  37.  
  38.  ip := make([]byte, ptrSize) 
  39.  
  40.  // We only support x86-64 platform now, so using hard coded `LittleEndian` here is ok. 設(shè)置 rip 寄存器 
  41.  binary.LittleEndian.PutUint16(ip, 0x050f) 
  42.  _, err = syscall.PtracePokeData(p.pid, uintptr(p.backupRegs.Rip), ip) 
  43.  if err != nil { 
  44.   return 0, err 
  45.  } 
  46.  
  47.  err = p.Step() // 單步執(zhí)行 
  48.  if err != nil { 
  49.   return 0, err 
  50.  } 
  51.  
  52.  err = syscall.PtraceGetRegs(p.pid, &regs) 
  53.  if err != nil { 
  54.   return 0, err 
  55.  } 
  56.  
  57.  return regs.Rax, p.Restore() // 獲取返回值,并且恢復(fù)寄存器 

參考代碼的注釋,搞過嵌入式的肯定熟悉:保存寄存器現(xiàn)場,設(shè)置新的寄存器值為 syscall number 以及參數(shù),最后設(shè)置指令寄存器 rip 單步執(zhí)行,就完成了讓目標(biāo)進(jìn)程執(zhí)行 mmap 的操作,最后也要恢復(fù)寄存器,還原現(xiàn)場。

這里為什么 rip 寄存器要設(shè)置成 0x050f 呢???其實(shí)這是 syscall 的操作碼

另外 p.WriteSlice 是使用 syscall process_vm_writev 將數(shù)據(jù)寫入目標(biāo)進(jìn)程的內(nèi)存邏輯地址空間。

3. FindSymbolInEntry

  1. ~# file /tmp/vdso.so 
  2. /tmp/vdso.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=17d65245b85cd032de7ab130d053551fb0bd284a, stripped 
  3. ~# objdump -T /tmp/vdso.so 
  4.  
  5. /tmp/vdso.so:     file format elf64-x86-64 
  6.  
  7. DYNAMIC SYMBOL TABLE
  8. 0000000000000950  w   DF .text 00000000000000a1  LINUX_2.6   clock_gettime 
  9. 00000000000008a0 g    DF .text 0000000000000083  LINUX_2.6   __vdso_gettimeofday 
  10. 0000000000000a00  w   DF .text 000000000000000a  LINUX_2.6   clock_getres 
  11. 0000000000000a00 g    DF .text 000000000000000a  LINUX_2.6   __vdso_clock_getres 
  12. 00000000000008a0  w   DF .text 0000000000000083  LINUX_2.6   gettimeofday 
  13. 0000000000000930 g    DF .text 0000000000000015  LINUX_2.6   __vdso_time 
  14. 0000000000000930  w   DF .text 0000000000000015  LINUX_2.6   time 
  15. 0000000000000950 g    DF .text 00000000000000a1  LINUX_2.6   __vdso_clock_gettime 
  16. 0000000000000000 g    DO *ABS* 0000000000000000  LINUX_2.6   LINUX_2.6 
  17. 0000000000000a10 g    DF .text 000000000000002a  LINUX_2.6   __vdso_getcpu 
  18. 0000000000000a10  w   DF .text 000000000000002a  LINUX_2.6   getcpu 

FindSymbolInEntry 函數(shù)很簡單,就是要找到 clock_gettime 在 vdso 中的地址,參考我之前的文章,上面是 dump 出來的符號(hào)表

4. JumpToFakeFunc

  1. // JumpToFakeFunc writes jmp instruction to jump to fake function 
  2. func (p *TracedProgram) JumpToFakeFunc(originAddr uint64, targetAddr uint64) error { 
  3.  instructions := make([]byte, 16) 
  4.  
  5.  // mov rax, targetAddr; 
  6.  // jmp rax ; 
  7.  instructions[0] = 0x48 
  8.  instructions[1] = 0xb8 
  9.  binary.LittleEndian.PutUint64(instructions[2:10], targetAddr) 
  10.  instructions[10] = 0xff 
  11.  instructions[11] = 0xe0 
  12.  
  13.  return p.PtraceWriteSlice(originAddr, instructions) 

JumpToFakeFunc[13], 修改 vdso 符號(hào)表中的匯編代碼,使所有調(diào)用 clock_gettime 的都跳轉(zhuǎn)到我們 fakeEntry 的地址,劫持 vdso

FakeImage

  1. var fakeImage = []byte{ 
  2.  0xb8, 0xe4, 0x00, 0x00, 0x00, //mov    $0xe4,%eax 
  3.  0x0f, 0x05, //syscall 
  4.  0xba, 0x01, 0x00, 0x00, 0x00, //mov    $0x1,%edx 
  5.  0x89, 0xf9, //mov    %edi,%ecx 
  6.  0xd3, 0xe2, //shl    %cl,%edx 
  7.  0x48, 0x8d, 0x0d, 0x74, 0x00, 0x00, 0x00, //lea    0x74(%rip),%rcx        # <CLOCK_IDS_MASK> 
  8.  0x48, 0x63, 0xd2, //movslq %edx,%rdx 
  9.  0x48, 0x85, 0x11, //test   %rdx,(%rcx) 
  10.  0x74, 0x6b, //je     108a <clock_gettime+0x8a> 
  11.  0x48, 0x8d, 0x15, 0x6d, 0x00, 0x00, 0x00, //lea    0x6d(%rip),%rdx        # <TV_SEC_DELTA> 
  12.  0x4c, 0x8b, 0x46, 0x08, //mov    0x8(%rsi),%r8 
  13.  0x48, 0x8b, 0x0a, //mov    (%rdx),%rcx 
  14.  0x48, 0x8d, 0x15, 0x67, 0x00, 0x00, 0x00, //lea    0x67(%rip),%rdx        # <TV_NSEC_DELTA> 
  15.  0x48, 0x8b, 0x3a, //mov    (%rdx),%rdi 
  16.  0x4a, 0x8d, 0x14, 0x07, //lea    (%rdi,%r8,1),%rdx 
  17.  0x48, 0x81, 0xfa, 0x00, 0xca, 0x9a, 0x3b, //cmp    $0x3b9aca00,%rdx 
  18.  0x7e, 0x1c, //jle    <clock_gettime+0x60> 
  19.  0x0f, 0x1f, 0x40, 0x00, //nopl   0x0(%rax) 
  20.  0x48, 0x81, 0xef, 0x00, 0xca, 0x9a, 0x3b, //sub    $0x3b9aca00,%rdi 
  21.  0x48, 0x83, 0xc1, 0x01, //add    $0x1,%rcx 
  22.  0x49, 0x8d, 0x14, 0x38, //lea    (%r8,%rdi,1),%rdx 
  23.  0x48, 0x81, 0xfa, 0x00, 0xca, 0x9a, 0x3b, //cmp    $0x3b9aca00,%rdx 
  24.  0x7f, 0xe8, //jg     <clock_gettime+0x48> 
  25.  0x48, 0x85, 0xd2, //test   %rdx,%rdx 
  26.  0x79, 0x1e, //jns    <clock_gettime+0x83> 
  27.  0x4a, 0x8d, 0xbc, 0x07, 0x00, 0xca, 0x9a, //lea    0x3b9aca00(%rdi,%r8,1),%rdi 
  28.  0x3b,             // 
  29.  0x0f, 0x1f, 0x00, //nopl   (%rax) 
  30.  0x48, 0x89, 0xfa, //mov    %rdi,%rdx 
  31.  0x48, 0x83, 0xe9, 0x01, //sub    $0x1,%rcx 
  32.  0x48, 0x81, 0xc7, 0x00, 0xca, 0x9a, 0x3b, //add    $0x3b9aca00,%rdi 
  33.  0x48, 0x85, 0xd2, //test   %rdx,%rdx 
  34.  0x78, 0xed, //js     <clock_gettime+0x70> 
  35.  0x48, 0x01, 0x0e, //add    %rcx,(%rsi) 
  36.  0x48, 0x89, 0x56, 0x08, //mov    %rdx,0x8(%rsi) 
  37.  0xc3, //retq 
  38.  // constant 
  39.  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //CLOCK_IDS_MASK 
  40.  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //TV_SEC_DELTA 
  41.  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //TV_NSEC_DELTA 

fakeImage 最后三個(gè)參數(shù)是偏移量,以及傳遞的 CLOCK_IDS_MASK, 這些匯編是什么意思呢???

查看匯編操作碼[14],0xe4 是系統(tǒng)調(diào)用 clock_gettime 的操作碼,后續(xù)都是對(duì)結(jié)果進(jìn)行注入,要么增要么減,制造偏移量 time skew

測試案例

  1. # git clone https://github.com/chaos-mesh/chaos-mesh 
  2. # cd chaos-mesh; make watchmaker 

首先下載 chaos-mesh, 然后編譯 watchmaker, 這是一個(gè)方便注入的小工具。

  1. package main 
  2.  
  3. import ( 
  4.         "fmt" 
  5.         "time" 
  6.  
  7. func main() { 
  8.         fmt.Println("start print time"
  9.         for { 
  10.                 fmt.Printf("now %v\n"time.Now()) 
  11.                 time.Sleep(time.Second * 20) 
  12.         } 

上面是測試的代碼,每隔 20 打印當(dāng)前時(shí)間,編譯執(zhí)行,同時(shí)用 watchmaker 注入 time skew

  1. # ./watchmaker -pid 1970 -sec_delta -300 

隔一段時(shí)間間后,再次執(zhí)行停止執(zhí)行注入

  1. # ./watchmaker -pid 1970 -sec_delta 0 
  1. # ./test 
  2. start print time 
  3. now 2021-05-26 03:31:46.701902309 +0000 UTC m=+0.000131483 
  4. now 2021-05-26 03:32:06.702230391 +0000 UTC m=+20.000459585 
  5. now 2021-05-26 03:32:26.702406569 +0000 UTC m=+40.000635793 
  6. now 2021-05-26 03:27:46.702688433 +0000 UTC m=+60.000918297 
  7. ^@now 2021-05-26 03:28:06.702914898 +0000 UTC m=+80.001145022 
  8. now 2021-05-26 03:28:26.703120914 +0000 UTC m=+100.001350878 
  9. now 2021-05-26 03:28:46.703398463 +0000 UTC m=+120.001628357 
  10. ^@now 2021-05-26 03:29:06.703707514 +0000 UTC m=+140.001937468 
  11. now 2021-05-26 03:29:26.704025346 +0000 UTC m=+160.002255480 
  12. now 2021-05-26 03:29:46.704302832 +0000 UTC m=+180.002532766 
  13. ^@now 2021-05-26 03:35:06.704505387 +0000 UTC m=+200.002735491 
  14.  
  15. now 2021-05-26 03:35:26.704931111 +0000 UTC m=+220.003161235 

上面是代碼執(zhí)行的輸出,可以看到 03:32:26 之后時(shí)間變成了 03:27:46, 停止注入后恢復(fù)

Limits

當(dāng)前的實(shí)現(xiàn),停止注入,并不會(huì)還原 vdso 代碼,也就是說 fakeEntry 會(huì)一直存在,每次 clock_gettime 都會(huì)跳轉(zhuǎn),只不過偏移量為 0 而己

由于以上原因的存在,注入及注入之后的 clock_gettime 都是走的 syscall 系統(tǒng)調(diào)用,性能很慢,敏感業(yè)務(wù)需要重啟,細(xì)節(jié)可以參考我之前的文章《時(shí)鐘源為什么會(huì)影響性能》

當(dāng)前注入,只能針對(duì)容器里的主進(jìn)程,那些 fork 出來,派生出來的無做做到注入

以上限制有沒有優(yōu)化空間呢?當(dāng)然有,問題都是用來解決的嘛~

小結(jié)

這次分享就這些,以后面還會(huì)分享更多的內(nèi)容,如果感興趣,可以關(guān)注并點(diǎn)擊左下角的分享轉(zhuǎn)發(fā)哦(:

參考資料

[1]Chaos Mesh - 讓時(shí)間在容器中自由搖擺: https://www.jianshu.com/p/6425050591b7,

[2]官方文檔: https://chaos-mesh.org/docs/chaos_experiments/timechaos_experiment/#limitation,

[3]讓時(shí)間在容器中自由搖擺: https://www.jianshu.com/p/6425050591b7,

[4]時(shí)鐘源為什么會(huì)影響性能: https://mp.weixin.qq.com/s/06SDQLzDprJf2AEaDnX-QQ,

[5]ptrace: https://man7.org/linux/man-pages/man2/ptrace.2.html,

[6]如何實(shí)現(xiàn) go 調(diào)試器: https://studygolang.com/articles/12804,

[7]time_linux_amd64.go: https://github.com/chaos-mesh/chaos-mesh/blob/master/pkg/time/time_linux_amd64.go#L72,

[8]ptrace_linux_amd64.go: https://github.com/chaos-mesh/chaos-mesh/blob/master/pkg/ptrace/ptrace_linux_amd64.go#L87,

[9]time_linux_amd64.go#L102 vdso: https://github.com/chaos-mesh/chaos-mesh/blob/master/pkg/time/time_linux_amd64.go#L102,

[10]program.MmapSlice: https://github.com/chaos-mesh/chaos-mesh/blob/master/pkg/time/time_linux_amd64.go#L132,

[11]FakeImage: https://github.com/chaos-mesh/chaos-mesh/blob/master/pkg/time/time_linux_amd64.go#L28,

[12]ptrace.Syscall: https://github.com/chaos-mesh/chaos-mesh/blob/master/pkg/ptrace/ptrace_linux_amd64.go#L251,

[13]JumpToFakeFunc: https://github.com/chaos-mesh/chaos-mesh/blob/master/pkg/ptrace/ptrace_linux_amd64.go#L480,

[14]匯編操作碼: https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md,

 

責(zé)任編輯:武曉燕 來源: 董澤潤的技術(shù)筆記
相關(guān)推薦

2021-09-03 09:06:42

代碼時(shí)間開發(fā)

2022-06-27 05:48:24

Kubernetes容器

2011-04-11 14:45:15

Oracle表系統(tǒng)時(shí)間

2015-08-07 10:10:18

LinuxDocker容器

2018-07-02 06:33:25

物聯(lián)網(wǎng)手機(jī)漫游網(wǎng)絡(luò)

2021-04-02 14:23:12

WiFi網(wǎng)絡(luò)技術(shù)

2021-03-31 21:20:15

WiFi網(wǎng)絡(luò)漫游

2020-09-19 18:03:42

Docker

2018-11-05 14:53:14

Go函數(shù)代碼

2018-07-02 09:00:27

Linux特定時(shí)間運(yùn)行命令

2017-09-18 10:05:15

WindowsLinux容器

2023-06-26 23:39:35

5G運(yùn)營商

2015-05-12 10:03:55

OpenStack環(huán)境容器編排Docker

2022-01-05 18:19:30

容器鏡像Golang

2022-04-20 11:40:51

元宇宙區(qū)塊鏈代幣

2024-11-20 16:09:04

API開源Bruno

2011-08-01 16:59:27

活動(dòng)目錄域控制器

2013-09-27 10:51:00

Github

2019-08-13 16:10:38

UbuntuLinux時(shí)間同步

2018-01-03 22:20:23

移動(dòng)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)