示例#1
0
//
// 确保Socket成功连接到后端服务器
//
func (bc *BackendConn) ensureConn() (transport thrift.TTransport, err error) {
	// 1. 创建连接(只要IP没有问题, err一般就是空)
	timeout := time.Second * 5
	if strings.Contains(bc.addr, ":") {
		transport, err = thrift.NewTSocketTimeout(bc.addr, timeout)
	} else {
		transport, err = rpc_utils.NewTUnixDomainTimeout(bc.addr, timeout)
	}
	log.Printf(Cyan("[%s]Create Socket To: %s"), bc.service, bc.addr)

	if err != nil {
		log.ErrorErrorf(err, "[%s]Create Socket Failed: %v, Addr: %s", err, bc.service, bc.addr)
		// 连接不上,失败
		return nil, err
	}

	// 2. 只要服务存在,一般不会出现err
	sleepInterval := 1
	err = transport.Open()
	for err != nil && !bc.IsMarkOffline.Get() {
		log.ErrorErrorf(err, "[%s]Socket Open Failed: %v, Addr: %s", bc.service, err, bc.addr)

		// Sleep: 1, 2, 4这几个间隔
		time.Sleep(time.Duration(sleepInterval) * time.Second)

		if sleepInterval < 4 {
			sleepInterval *= 2
		}
		err = transport.Open()
	}
	return transport, err
}
示例#2
0
//
// Client <---> Proxy[BackendConn] <---> RPC Server[包含LB]
// BackConn <====> RPC Server
// loopReader从RPC Server读取数据,然后根据返回的结果来设置: Client的Request的状态
//
// 1. bc.flushRequest
// 2. bc.setResponse
//
func (bc *BackendConn) loopReader(c *TBufferedFramedTransport, connOver *sync.WaitGroup) {
	go func() {
		defer connOver.Done()
		defer c.Close()

		lastTime := time.Now().Unix()
		// Active状态,或者最近5s有数据返回
		// 设计理由:服务在线,则请求正常发送;
		//         服务下线后,则期待后端服务的数据继续返回(最多等待5s)
		for bc.IsConnActive.Get() || (time.Now().Unix()-lastTime < 5) {
			// 读取来自后端服务的数据,通过 setResponse 转交给 前端
			// client <---> proxy <-----> backend_conn <---> rpc_server
			// ReadFrame需要有一个度? 如果碰到EOF该如何处理呢?

			// io.EOF在两种情况下会出现
			//
			resp, err := c.ReadFrame()
			lastTime = time.Now().Unix()
			if err != nil {
				err1, ok := err.(thrift.TTransportException)
				if !ok || err1.TypeId() != thrift.END_OF_FILE {
					log.ErrorErrorf(err, Red("[%s]ReadFrame From Server with Error: %v"), bc.service, err)
				}
				bc.flushRequests(err)
				break
			} else {

				bc.setResponse(nil, resp, err)
			}
		}

		bc.flushRequests(errors.New("BackendConn Timeout"))
	}()
}
示例#3
0
//
// 从RPC Backend中读取结果, ReadFrame读取的是一个thrift message
// 存在两种情况:
// 1. 正常读取thrift message, 然后从frame解码得到seqId, 然后得到request, 结束请求
// 2. 读取错误
//    将现有的requests全部flush回去
//
func (bc *BackendConnLB) loopReader(c *TBufferedFramedTransport) {
	go func() {
		defer c.Close()

		for true {
			// 坚信: EOF只有在连接被关闭的情况下才会发生,其他情况下, Read等操作被会被block住
			// EOF有两种情况:
			// 1. 连接正常关闭,最后数据等完整读取 --> io.EOF
			// 2. 连接异常关闭,数据不完整 --> io.ErrUnexpectedEOF
			//
			// rpc_server ---> backend_conn
			frame, err := c.ReadFrame() // 有可能被堵住

			if err != nil {

				err1, ok := err.(thrift.TTransportException)
				if !ok || err1.TypeId() != thrift.END_OF_FILE {
					log.ErrorErrorf(err, Red("ReadFrame From rpc_server with Error: %v\n"), err)
				}
				bc.flushRequests(err)
				break
			} else {
				bc.setResponse(nil, frame, err)
			}
		}
	}()
}
示例#4
0
// 配对 Request, resp, err
// PARAM: resp []byte 为一帧完整的thrift数据包
func (bc *BackendConnLB) setResponse(r *Request, data []byte, err error) error {
	//	log.Printf("#setResponse:  data: %v", data)
	// 表示出现错误了
	if data == nil {
		log.Printf("No Data From Server, error: %v\n", err)
		r.Response.Err = err
	} else {
		// 从resp中读取基本的信息
		typeId, method, seqId, err := DecodeThriftTypIdSeqId(data)

		// 解码错误,直接报错
		if err != nil {
			log.ErrorErrorf(err, "Decode SeqId Error: %v", err)
			return err
		}

		if typeId == MESSAGE_TYPE_STOP {
			// 不再接受新的输入
			// 直接来自后端的服务(不遵循: Request/Reply模型)
			bc.MarkConnActiveFalse()
			return nil
		}

		// 找到对应的Request

		req := bc.seqNumRequestMap.Pop(seqId)

		// 如果是心跳,则OK
		if typeId == MESSAGE_TYPE_HEART_BEAT {
			bc.hbLastTime.Set(time.Now().Unix())
			return nil
		}

		if req == nil {
			log.Errorf("#setResponse not found, seqId: %d", seqId)
			return nil
		} else {

			if req.Response.SeqId != seqId {
				log.Errorf("Data From Server, SeqId not match, Ex: %d, Ret: %d", req.Request.SeqId, seqId)
			}
			r = req
			r.Response.TypeId = typeId
			if req.Request.Name != method {
				data = nil
				err = req.NewInvalidResponseError(method, "conn_lb")
			}
		}
	}

	r.Response.Data, r.Response.Err = data, err
	// 还原SeqId
	if data != nil {
		r.RestoreSeqId()
	}

	r.Wait.Done()
	return err
}
示例#5
0
// Router负责监听zk中服务列表的变化
func (bk *Router) WatchServices() {
	var evtbus chan interface{} = make(chan interface{}, 2)

	// 1. 保证Service目录存在,否则会报错
	servicesPath := bk.topo.ProductServicesPath()
	_, e1 := bk.topo.CreateDir(servicesPath)
	if e1 != nil {
		log.PanicErrorf(e1, "Zk Path Create Failed: %s", servicesPath)
	}

	go func() {
		for true {
			// 无限监听
			services, err := bk.topo.WatchChildren(servicesPath, evtbus)

			if err == nil {
				bk.serviceLock.Lock()
				// 保证数据更新是有效的
				oldServices := bk.services
				bk.services = make(map[string]*BackService, len(services))
				for _, service := range services {
					log.Println("Found Service: ", Magenta(service))

					back, ok := oldServices[service]
					if ok {
						bk.services[service] = back
						delete(oldServices, service)
					} else {

						bk.addBackService(service)
					}
				}
				if len(oldServices) > 0 {
					for _, conn := range oldServices {
						// 标记下线(现在应该不会有新的请求,最多只会处理一些收尾的工作
						conn.Stop()
					}

				}

				bk.serviceLock.Unlock()

				// 等待事件
				<-evtbus
			} else {
				log.ErrorErrorf(err, "zk watch error: %s, error: %v\n",
					servicesPath, err)
				time.Sleep(time.Duration(5) * time.Second)
			}
		}
	}()

	// 读取zk, 等待
	log.Println("ProductName: ", Magenta(bk.topo.ProductName))
}
func (p *TBufferedFramedTransport) flushTransport(force bool) error {
	if p.nbuffered > 0 && (force || p.needFlush()) {
		// 这个如何控制呢?
		if err := p.Writer.Flush(); err != nil {
			log.ErrorErrorf(err, "FlushTransport Error, %v", err)
			return err
		}
		p.nbuffered = 0
		p.lastflush = time.Now().UnixNano()
	}
	return nil
}
//
// 先写入数据,然后再Flush Transport
//
func (p *TBufferedFramedTransport) FlushBuffer(force bool) error {
	size := p.Buffer.Len()

	// 没有有效的数据,直接返回
	if size == 0 {
		return nil
	}
	// TODO: 待优化
	force = true

	// 1. 将p.buf的大小以BigEndian模式写入: buf中
	buf := p.LenghW[:4]
	binary.BigEndian.PutUint32(buf, uint32(size))

	//	log.Printf("----> Frame Size: %d, %v\n", size, buf)
	// 然后transport中先写入: 长度信息
	_, err := p.Writer.Write(buf)
	if err != nil {
		return thrift.NewTTransportExceptionFromError(err)
	}

	// 2. 然后继续写入p.buf中的数据
	if size > 0 {
		var (
			n   int64
			err error
		)
		// 如果 err == io.ErrShortWrite, p.Writer中也有buffer, 因此可以不用考虑异常
		if n, err = p.Buffer.WriteTo(p.Writer); err != nil {
			log.ErrorErrorf(err, "Error Flushing Expect Write: %d, but %d\n",
				size, n)
			return thrift.NewTTransportExceptionFromError(err)
		}
		if n < int64(size) {
			log.Printf(Red("Buffer Write Not Finished"))
		}
	}

	p.nbuffered++

	// Buffer重新开始处理数据
	p.Buffer.Reset()

	// Flush Buffer
	return p.flushTransport(force)
}
示例#8
0
//
// 不断建立到后端的逻辑,负责: BackendConn#input到redis的数据的输入和返回
//
func (bc *BackendConn) Run() {

	for k := 0; !bc.IsMarkOffline.Get(); k++ {

		// 1. 首先BackendConn将当前 input中的数据写到后端服务中
		transport, err := bc.ensureConn()
		if err != nil {
			log.ErrorErrorf(err, "[%s]BackendConn#ensureConn error: %v", bc.service, err)
			return
		}

		connOver := &sync.WaitGroup{}
		c := NewTBufferedFramedTransport(transport, 100*time.Microsecond, 20)

		bc.MarkConnActiveOK() // 准备接受数据
		connOver.Add(1)
		bc.loopReader(c, connOver) // 异步(读取来自后端服务器的返回数据)
		// 2. 将 bc.input 中的请求写入 后端的Rpc Server
		err = bc.loopWriter(c) // 同步

		// 3. 停止接受Request
		bc.MarkConnActiveFalse()

		// 等待Conn正式关闭
		connOver.Wait()

		// 4. 将bc.input中剩余的 Request直接出错处理
		if err == nil {
			log.Printf(Red("[%s]BackendConn#loopWriter normal Exit..."), bc.service)
			break
		} else {
			// 对于尚未处理的Request, 直接报错
			for i := len(bc.input); i != 0; i-- {
				r := <-bc.input
				bc.setResponse(r, nil, err)
			}
		}
	}
}
示例#9
0
//
//
// NonBlock和Block的区别:
// NonBlock的 Request和Response是不需要配对的, Request和Response是独立的,例如:
//  ---> RequestA, RequestB
//  <--- RequestB, RequestA 后请求的,可以先返回
//
func (s *NonBlockSession) loopWriter(tasks <-chan *Request) error {
	for r := range tasks {
		// 1. tasks中的请求是已经请求完毕的,loopWriter负责将它们的数据写回到rpc proxy
		s.handleResponse(r)

		// 2. 将结果写回给Client
		_, err := s.TBufferedFramedTransport.Write(r.Response.Data)
		r.Recycle()
		if err != nil {
			log.ErrorErrorf(err, "SeqId: %d, Write back Data Error: %v\n", r.Request.SeqId, err)
			return err
		}

		//		typeId, sedId, _ := DecodeThriftTypIdSeqId(r.Response.Data)

		//		if typeId != MESSAGE_TYPE_HEART_BEAT {
		//			if sedId != s.lastSeqId {
		//				log.Errorf(Red("Invalid SedId for Writer: %d vs. %d"), sedId, s.lastSeqId)
		//			}
		//		}

		// log.Printf(Magenta("Task: %d"), r.Response.SeqId)

		// 3. Flush
		err = s.TBufferedFramedTransport.FlushBuffer(len(tasks) == 0) // len(tasks) == 0
		//		if err != nil {
		//			log.Debugf(Magenta("Write Back to Client/Proxy SeqId: %d, Error: %v"), r.Request.SeqId, err)
		//		} else {
		//			log.Debugf(Magenta("Write Back to Client/Proxy SeqId: %d"), r.Request.SeqId)
		//		}

		if err != nil {
			return err
		}
	}
	return nil
}
//
// go test proxy -v -run "TestBackend"
//
func TestBackend(t *testing.T) {

	// 作为一个Server
	transport, err := thrift.NewTServerSocket("127.0.0.1:0")
	assert.NoError(t, err)
	err = transport.Open() // 打开Transport
	assert.NoError(t, err)

	defer transport.Close()

	err = transport.Listen() // 开始监听
	assert.NoError(t, err)

	addr := transport.Addr().String()

	fmt.Println("Addr: ", addr)

	var requestNum int32 = 10

	requests := make([]*Request, 0, requestNum)

	var i int32
	for i = 0; i < requestNum; i++ {
		buf := make([]byte, 100, 100)
		l := fakeData("Hello", thrift.CALL, i+1, buf[0:0])
		buf = buf[0:l]

		req, _ := NewRequest(buf, false)

		req.Wait.Add(1) // 因为go routine可能还没有执行,代码就跑到最后面进行校验了

		assert.Equal(t, i+1, req.Request.SeqId, "Request SeqId是否靠谱")

		requests = append(requests, req)
	}

	go func() {
		// 客户端代码
		bc := NewBackendConn(addr, nil, "test", true)
		bc.currentSeqId = 10

		// 准备发送数据
		var i int32
		for i = 0; i < requestNum; i++ {
			fmt.Println("Sending Request to Backend Conn", i)
			bc.PushBack(requests[i])

			requests[i].Wait.Done()
		}

		// 需要等待数据返回?
		time.Sleep(time.Second * 2)

	}()

	go func() {
		// 服务器端代码
		tran, err := transport.Accept()
		if err != nil {
			log.ErrorErrorf(err, "Error: %v\n", err)
		}
		assert.NoError(t, err)

		bt := NewTBufferedFramedTransport(tran, time.Microsecond*100, 2)

		// 在当前的这个t上读写数据
		var i int32
		for i = 0; i < requestNum; i++ {
			request, err := bt.ReadFrame()
			assert.NoError(t, err)

			req, _ := NewRequest(request, false)
			assert.Equal(t, req.Request.SeqId, i+10)
			fmt.Printf("Server Got Request, and SeqNum OK, Id: %d, Frame Size: %d\n", i, len(request))

			// 回写数据
			bt.Write(request)
			bt.FlushBuffer(true)

		}

		tran.Close()
	}()

	fmt.Println("Requests Len: ", len(requests))
	for idx, r := range requests {
		r.Wait.Wait()

		// r 原始的请求
		req, _ := NewRequest(r.Response.Data, false)

		log.Printf(Green("SeqMatch[%d]: Orig: %d, Return: %d\n"), idx, req.Request.SeqId, r.Request.SeqId)
		assert.Equal(t, req.Request.SeqId, r.Request.SeqId)
	}
	log.Println("OK")
}
示例#11
0
func (p *ThriftRpcServer) Run() {
	//	// 1. 创建到zk的连接
	p.Topo = NewTopology(p.ProductName, p.ZkAddr)

	// 127.0.0.1:5555 --> 127_0_0_1:5555
	lbServiceName := GetServiceIdentity(p.FrontendAddr)

	exitSignal := make(chan os.Signal, 1)
	signal.Notify(exitSignal, syscall.SIGTERM, syscall.SIGINT, syscall.SIGKILL)

	// syscall.SIGKILL
	// kill -9 pid
	// kill -s SIGKILL pid 还是留给运维吧

	StartTicker(p.config.FalconClient, p.ServiceName)

	// 初始状态为不上线
	var state atomic2.Bool
	state.Set(false)
	stateChan := make(chan bool)

	// 注册服务
	evtExit := make(chan interface{})
	endpoint := RegisterService(p.ServiceName, p.FrontendAddr, lbServiceName,
		p.Topo, evtExit, p.config.WorkDir, p.config.CodeUrlVersion,
		&state, stateChan)

	// 3. 读取"前端"的配置
	var transport thrift.TServerTransport
	var err error

	isUnixDomain := false
	// 127.0.0.1:9999(以:区分不同的类型)
	if !strings.Contains(p.FrontendAddr, ":") {
		if rpc_utils.FileExist(p.FrontendAddr) {
			os.Remove(p.FrontendAddr)
		}
		transport, err = rpc_utils.NewTServerUnixDomain(p.FrontendAddr)
		isUnixDomain = true
	} else {
		transport, err = thrift.NewTServerSocket(p.FrontendAddr)
	}

	if err != nil {
		log.ErrorErrorf(err, Red("Server Socket Create Failed: %v"), err)
		panic(fmt.Sprintf("Invalid FrontendAddr: %s", p.FrontendAddr))
	}

	err = transport.Listen()
	if err != nil {
		log.ErrorErrorf(err, Red("Server Socket Open Failed: %v"), err)
		panic(fmt.Sprintf("Server Socket Open Failed: %s", p.FrontendAddr))
	}

	ch := make(chan thrift.TTransport, 4096)
	defer close(ch)

	// 强制退出? TODO: Graceful退出
	go func() {
		<-exitSignal
		evtExit <- true
		log.Info(Magenta("Receive Exit Signals...."))
		endpoint.DeleteServiceEndpoint(p.Topo)

		// 等待
		start := time.Now().Unix()
		for true {
			// 如果5s内没有接受到新的请求了,则退出
			now := time.Now().Unix()
			if now-p.lastRequestTime.Get() > 5 {
				log.Info(Red("Graceful Exit..."))
				break
			} else {
				log.Printf(Cyan("Sleeping %d seconds\n"), now-start)
				time.Sleep(time.Second)
			}
		}
		transport.Interrupt()
		transport.Close()
	}()

	go func() {
		var address string
		for c := range ch {
			// 为每个Connection建立一个Session
			socket, ok := c.(rpc_utils.SocketAddr)

			if ok {
				if isUnixDomain {
					address = p.FrontendAddr
				} else {
					address = socket.Addr().String()
				}
			} else {
				address = "unknow"
			}
			x := NewNonBlockSession(c, address, p.Verbose, &p.lastRequestTime)
			// Session独立处理自己的请求
			go x.Serve(p, 1000)
		}
	}()

	// 准备上线服务
	state.Set(true)
	stateChan <- true

	// Accept什么时候出错,出错之后如何处理呢?
	for {
		c, err := transport.Accept()
		if err != nil {
			break
		} else {
			ch <- c
		}
	}
}
示例#12
0
//
// go test proxy -v -run "TestSession"
//
func TestSession(t *testing.T) {
	// 作为一个Server
	transport, err := thrift.NewTServerSocket("127.0.0.1:0")
	err = transport.Open() // 打开Transport
	defer transport.Close()

	err = transport.Listen() // 开始监听
	assert.NoError(t, err)

	addr := transport.Addr().String()
	fmt.Println("Addr: ", addr)

	// 1. Fake Requests
	var requestNum int32 = 10
	requests := make([]*Request, 0, requestNum)
	var i int32
	for i = 0; i < requestNum; i++ {
		buf := make([]byte, 100, 100)
		l := fakeData("Hello", thrift.CALL, i+1, buf[0:0])
		buf = buf[0:l]

		req, _ := NewRequest(buf, true)

		req.Wait.Add(1) // 因为go routine可能还没有执行,代码就跑到最后面进行校验了

		assert.Equal(t, i+1, req.Request.SeqId, "Request SeqId是否靠谱")

		requests = append(requests, req)
	}

	// 2. 将请求交给BackendConn
	go func() {
		// 模拟请求:
		// 客户端代码
		bc := NewBackendConn(addr, nil, "test", true)
		bc.currentSeqId = 10

		// 上线 BackendConn
		bc.IsConnActive.Set(true)

		// 准备发送数据
		var i int32
		for i = 0; i < requestNum; i++ {
			fmt.Println("Sending Request to Backend Conn", i)
			bc.PushBack(requests[i])

			requests[i].Wait.Done()
		}

		// 需要等待数据返回?
		time.Sleep(time.Second * 2)
	}()

	server := &fakeServer{}
	go func() {
		// 服务器端代码
		tran, err := transport.Accept()
		defer tran.Close()
		if err != nil {
			log.ErrorErrorf(err, "Error: %v\n", err)
		}
		assert.NoError(t, err)

		// 建立一个长连接, 同上面的: NewBackendConn通信
		session := NewSession(tran, "", true)
		session.Serve(server, 6)

		time.Sleep(time.Second * 2)
	}()

	for i = 0; i < requestNum; i++ {
		fmt.Println("===== Before Wait")
		requests[i].Wait.Wait()
		fmt.Println("===== Before After Wait")

		log.Printf("Request: %d, .....", i)
		assert.Equal(t, len(requests[i].Request.Data), len(requests[i].Response.Data))
	}
}
示例#13
0
//
// 去ZK注册当前的Service
//
func RegisterService(serviceName, frontendAddr, serviceId string, topo *Topology, evtExit chan interface{},
	workDir string, codeUrlVerion string, state *atomic2.Bool, stateChan chan bool) *ServiceEndpoint {

	// 1. 准备数据
	// 记录Service Endpoint的信息
	servicePath := topo.ProductServicePath(serviceName)

	// 确保东西存在
	if ok, _ := topo.Exist(servicePath); !ok {
		topo.CreateDir(servicePath)
	}

	// 用来从zookeeper获取事件
	evtbus := make(chan interface{})

	// 2. 将信息添加到Zk中, 并且监控Zk的状态(如果添加失败会怎么样?)
	endpoint := NewServiceEndpoint(serviceName, serviceId, frontendAddr, workDir, codeUrlVerion)

	// deployPath

	// 为了保证Add是干净的,需要先删除,保证自己才是Owner
	endpoint.DeleteServiceEndpoint(topo)

	// 如果没有状态,或状态为true, 则上线
	if state == nil || state.Get() {
		endpoint.AddServiceEndpoint(topo)
	}

	go func() {

		for true {
			// Watch的目的是监控: 当前的zk session的状态, 如果session出现异常,则重新注册
			_, err := topo.WatchNode(servicePath, evtbus)

			if err == nil {
				// 如果成功添加Watch, 则等待退出,或者ZK Event
				select {
				case <-evtExit:
					return
				case <-stateChan:
					// 如何状态变化(则重新注册)
					endpoint.DeleteServiceEndpoint(topo)
					if state == nil || state.Get() {
						endpoint.AddServiceEndpoint(topo)
					}
				case e := <-evtbus:
					event := e.(topozk.Event)
					if event.State == topozk.StateExpired ||
						event.Type == topozk.EventNotWatching {
						// Session过期了,则需要删除之前的数据,
						// 因为当前的session不是之前的数据的Owner
						endpoint.DeleteServiceEndpoint(topo)

						if state == nil || state.Get() {
							endpoint.AddServiceEndpoint(topo)
						}

					}
				}

			} else {
				// 如果添加Watch失败,则等待退出,或等待timer接触,进行下一次尝试
				timer := time.NewTimer(time.Second * time.Duration(10))
				log.ErrorErrorf(err, "Reg Failed, Wait 10 seconds...., %v", err)
				select {
				case <-evtExit:
					return
				case <-timer.C:
					// pass
				}
			}

		}
	}()
	return endpoint
}
示例#14
0
// Session是同步处理请求,因此没有必要搞多个
func (s *Session) Serve(d Dispatcher, maxPipeline int) {
	defer func() {
		s.Close()
		log.Infof(Red("==> Session Over: %s, Total %d Ops"), s.RemoteAddress, s.Ops)
		if err := recover(); err != nil {
			log.Infof(Red("Catch session error: %v"), err)
		}
	}()

	for true {
		// 1. 读取请求
		request, err := s.ReadFrame()
		s.Ops += 1

		// 读取出错,直接退出
		if err != nil {
			err1, ok := err.(thrift.TTransportException)
			if !ok || err1.TypeId() != thrift.END_OF_FILE {
				log.ErrorErrorf(err, Red("ReadFrame Error: %v"), err)
			}
			// r.Recycle()
			return
		}

		var r *Request
		// 2. 处理请求
		r, err = s.handleRequest(request, d)
		if err != nil {
			// r.Recycle() // 出错之后也要主动返回数据
			log.ErrorErrorf(err, Red("handleRequest Error: %v"), err)
			r.Response.Err = err
		}

		// 3. 等待请求处理完毕
		s.handleResponse(r)

		// 4. 将结果写回给Client
		if s.verbose {
			log.Debugf("[%s]Session#loopWriter --> client FrameSize: %d",
				r.Service, len(r.Response.Data))
		}

		// 5. 将请求返回给Client, r.Response.Data ---> Client
		_, err = s.TBufferedFramedTransport.Write(r.Response.Data)
		r.Recycle() // 重置: Request

		if err != nil {
			log.ErrorErrorf(err, "Write back Data Error: %v", err)
			return
		}

		// 6. Flush
		err = s.TBufferedFramedTransport.FlushBuffer(true) // len(tasks) == 0
		if err != nil {
			log.ErrorErrorf(err, "Write back Data Error: %v", err)
			return
		}

		// r.Recycle()
	}
}
//
// 如何处理后端服务的变化呢?
//
func (s *BackService) WatchBackServiceNodes() {
	s.evtbus = make(chan interface{}, 2)
	servicePath := s.topo.ProductServicePath(s.serviceName)

	go func() {
		for !s.stop.Get() {
			serviceIds, err := s.topo.WatchChildren(servicePath, s.evtbus)

			if err == nil {
				// 如何监听endpoints的变化呢?
				addressMap := make(map[string]bool, len(serviceIds))

				for _, serviceId := range serviceIds {
					log.Printf(Green("---->Find Endpoint: %s for Service: %s"), serviceId, s.serviceName)
					endpointInfo, err := GetServiceEndpoint(s.topo, s.serviceName, serviceId)

					if err != nil {
						log.ErrorErrorf(err, "Service Endpoint Read Error: %v\n", err)
					} else {

						log.Printf(Green("---->Add endpoint %s To Service %s"),
							endpointInfo.Frontend, s.serviceName)

						if strings.Contains(endpointInfo.Frontend, ":") {
							addressMap[endpointInfo.Frontend] = true
						} else if s.productName == TEST_PRODUCT_NAME {
							// unix domain socket只在测试的时候可以使用(因为不能实现跨机器访问)
							addressMap[endpointInfo.Frontend] = true
						}
					}
				}

				for addr, _ := range addressMap {
					conn, ok := s.addr2Conn[addr]
					if ok && !conn.IsMarkOffline.Get() {
						continue
					} else {
						// 创建新的连接(心跳成功之后就自动加入到 s.activeConns 中
						s.addr2Conn[addr] = NewBackendConn(addr, s, s.serviceName, s.verbose)
					}
				}

				for addr, conn := range s.addr2Conn {
					_, ok := addressMap[addr]
					if !ok {
						conn.MarkOffline()

						// 删除: 然后等待Conn自生自灭
						delete(s.addr2Conn, addr)
					}
				}

				// 等待事件
				<-s.evtbus
			} else {
				log.WarnErrorf(err, "zk read failed: %s", servicePath)
				// 如果读取失败则,则继续等待5s
				time.Sleep(time.Duration(5) * time.Second)
			}

		}
	}()
}
示例#16
0
func (p *ThriftLoadBalanceServer) Run() {
	//	// 1. 创建到zk的连接

	// 127.0.0.1:5555 --> 127_0_0_1:5555

	exitSignal := make(chan os.Signal, 1)

	signal.Notify(exitSignal, syscall.SIGTERM, syscall.SIGINT, syscall.SIGKILL)
	// syscall.SIGKILL
	// kill -9 pid
	// kill -s SIGKILL pid 还是留给运维吧
	//

	// 注册服务
	evtExit := make(chan interface{})

	// 初始状态为不上线
	var state atomic2.Bool
	state.Set(false)
	stateChan := make(chan bool)

	serviceEndpoint := RegisterService(p.serviceName, p.frontendAddr, p.lbServiceName,
		p.topo, evtExit, p.config.WorkDir, p.config.CodeUrlVersion, &state, stateChan)

	//	var suideTime time.Time

	//	isAlive := true

	// 3. 读取后端服务的配置
	var transport thrift.TServerTransport
	var err error

	isUnixDomain := false
	// 127.0.0.1:9999(以:区分不同的类型)
	if !strings.Contains(p.frontendAddr, ":") {
		if rpc_utils.FileExist(p.frontendAddr) {
			os.Remove(p.frontendAddr)
		}
		transport, err = rpc_utils.NewTServerUnixDomain(p.frontendAddr)
		isUnixDomain = true
	} else {
		transport, err = thrift.NewTServerSocket(p.frontendAddr)
	}

	if err != nil {
		log.ErrorErrorf(err, "Server Socket Create Failed: %v", err)
		panic(fmt.Sprintf("Invalid FrontendAddress: %s", p.frontendAddr))
	}

	err = transport.Listen()
	if err != nil {
		log.ErrorErrorf(err, "Server Socket Create Failed: %v", err)
		panic(fmt.Sprintf("Binding Error FrontendAddress: %s", p.frontendAddr))
	}

	ch := make(chan thrift.TTransport, 4096)
	defer close(ch)

	// 等待后端服务起来
	waitTicker := time.NewTicker(time.Second)

	// 等待上线采用的策略:
	// 1. 检测到有效的Worker注册之后,再等5s即可像zk注册; 避免了Worker没有连接上来,就有请求过来
	// 2. 一旦注册之后,就不再使用该策略;避免服务故障时,lb频繁更新zk, 导致proxy等频繁读取zk
START_WAIT:
	for true {
		select {
		case <-waitTicker.C:
			if p.backendService.Active() <= 0 {
				log.Infof("Sleep Waiting for back Service to Start")
				time.Sleep(time.Second)
			} else {
				break START_WAIT
			}
		case <-exitSignal:
			// 直接退出
			transport.Interrupt()
			transport.Close()
			return
		}
	}

	log.Infof("Stop Waiting")
	// 停止: waitTicker, 再等等就继续了
	waitTicker.Stop()
	time.Sleep(time.Second * 5)

	log.Infof("Begin to Reg To Zk...")
	state.Set(true)
	stateChan <- true

	// 强制退出? TODO: Graceful退出
	go func() {
		<-exitSignal

		// 通知RegisterService终止循环
		evtExit <- true
		log.Info(Green("Receive Exit Signals...."))
		serviceEndpoint.DeleteServiceEndpoint(p.topo)

		start := time.Now().Unix()
		for true {
			// 如果5s内没有接受到新的请求了,则退出
			now := time.Now().Unix()
			if now-p.lastRequestTime.Get() > 5 {
				log.Printf(Red("[%s]Graceful Exit..."), p.serviceName)
				break
			} else {
				log.Printf(Cyan("[%s]Sleeping %d seconds before Exit...\n"),
					p.serviceName, now-start)
				time.Sleep(time.Second)
			}
		}

		transport.Interrupt()
		transport.Close()
	}()

	go func() {
		var address string
		for c := range ch {
			// 为每个Connection建立一个Session
			socket, ok := c.(rpc_utils.SocketAddr)

			if ok {
				if isUnixDomain {
					address = p.frontendAddr
				} else {
					address = socket.Addr().String()
				}
			} else {
				address = "unknow"
			}
			x := NewNonBlockSession(c, address, p.verbose, &p.lastRequestTime)
			// Session独立处理自己的请求
			go x.Serve(p.backendService, 1000)
		}
	}()

	// Accept什么时候出错,出错之后如何处理呢?
	for {
		c, err := transport.Accept()
		if err != nil {
			close(ch)
			break
		} else {
			ch <- c
		}
	}
}
示例#17
0
//
// 两参数是必须的:  ProductName, zkAddress, frontAddr可以用来测试
//
func (p *ProxyServer) Run() {

	var transport thrift.TServerTransport
	var err error

	log.Printf(Magenta("Start Proxy at Address: %s"), p.proxyAddr)
	// 读取后端服务的配置
	isUnixDomain := false
	if !strings.Contains(p.proxyAddr, ":") {
		if rpc_utils.FileExist(p.proxyAddr) {
			os.Remove(p.proxyAddr)
		}
		transport, err = rpc_utils.NewTServerUnixDomain(p.proxyAddr)
		isUnixDomain = true
	} else {
		transport, err = thrift.NewTServerSocket(p.proxyAddr)
	}
	if err != nil {
		log.ErrorErrorf(err, "Server Socket Create Failed: %v, Front: %s", err, p.proxyAddr)
	}

	// 开始监听
	//	transport.Open()
	transport.Listen()

	ch := make(chan thrift.TTransport, 4096)
	defer close(ch)
	defer func() {
		log.Infof(Red("==> Exit rpc_proxy"))
		if err := recover(); err != nil {
			log.Infof("Error rpc_proxy: %s", err)
		}
	}()
	go func() {
		var address string
		for c := range ch {
			// 为每个Connection建立一个Session
			socket, ok := c.(rpc_utils.SocketAddr)
			if isUnixDomain {
				address = p.proxyAddr
			} else if ok {
				address = socket.Addr().String()
			} else {
				address = "unknow"
			}
			x := NewSession(c, address, p.verbose)
			// Session独立处理自己的请求
			go x.Serve(p.router, 1000)
		}
	}()

	// Accept什么时候出错,出错之后如何处理呢?
	for {
		c, err := transport.Accept()
		if err != nil {
			log.ErrorErrorf(err, "Accept Error: %v", err)
			break
		} else {
			ch <- c
		}
	}
}
示例#18
0
//
// 数据: LB ---> backend services
//
// 如果input关闭,且loopWriter正常处理完毕之后,返回nil
// 其他情况返回error
//
func (bc *BackendConnLB) loopWriter() error {
	// 正常情况下, ok总是为True; 除非bc.input的发送者主动关闭了channel, 表示再也没有新的Task过来了
	// 参考: https://tour.golang.org/concurrency/4
	// 如果input没有关闭,则会block
	c := NewTBufferedFramedTransport(bc.transport, 100*time.Microsecond, 20)

	// bc.MarkConnActiveOK() // 准备接受数据
	// BackendConnLB 在构造之初就有打开的transport, 并且Active默认为OK

	defer func() {
		bc.hbTicker.Stop()
		bc.hbTicker = nil
	}()

	bc.loopReader(c) // 异步

	// 建立连接之后,就启动HB
	bc.hbTicker = time.NewTicker(time.Second)
	bc.hbLastTime.Set(time.Now().Unix())

	var r *Request
	var ok bool

	for true {
		// 等待输入的Event, 或者 heartbeatTimeout
		select {
		case <-bc.hbTicker.C:
			// 两种情况下,心跳会超时
			// 1. 对方挂了
			// 2. 自己快要挂了,然后就不再发送心跳;没有了心跳,就会超时
			if time.Now().Unix()-bc.hbLastTime.Get() > HB_TIMEOUT {
				// 强制关闭c
				c.Close()
				return errors.New("Worker HB timeout")
			} else {
				if bc.IsConnActive.Get() {
					// 定时添加Ping的任务
					r := NewPingRequest()
					bc.PushBack(r)

					// 同时检测当前的异常请求
					expired := microseconds() - REQUEST_EXPIRED_TIME_MICRO // 以microsecond为单位
					bc.seqNumRequestMap.RemoveExpired(expired)
				}
			}

		case r, ok = <-bc.input:
			if !ok {
				return nil
			} else {
				// 如果暂时没有数据输入,则p策略可能就有问题了
				// 只有写入数据,才有可能产生flush; 如果是最后一个数据必须自己flush, 否则就可能无限期等待
				//
				if r.Request.TypeId == MESSAGE_TYPE_HEART_BEAT {
					// 过期的HB信号,直接放弃
					if time.Now().Unix()-r.Start > 4 {
						log.Warnf(Red("Expired HB Signals"))
					}
				}
				// 先不做优化
				var flush = true // len(bc.input) == 0

				// 1. 替换新的SeqId(currentSeqId只在当前线程中使用, 不需要同步)
				r.ReplaceSeqId(bc.currentSeqId)
				bc.IncreaseCurrentSeqId()

				// 2. 主动控制Buffer的flush
				// 先记录SeqId <--> Request, 再发送请求
				// 否则: 请求从后端返回,记录还没有完成,就容易导致Request丢失
				bc.seqNumRequestMap.Add(r.Response.SeqId, r)
				c.Write(r.Request.Data)
				err := c.FlushBuffer(flush)

				if err != nil {
					bc.seqNumRequestMap.Pop(r.Response.SeqId)
					log.ErrorErrorf(err, "FlushBuffer Error: %v\n", err)

					// 进入不可用状态(不可用状态下,通过自我心跳进入可用状态)
					return bc.setResponse(r, nil, err)
				}
			}
		}

	}
	return nil
}