Golang writing a simple image server

Source: Internet
Author: User
Tags sprintf vars
This is a creation in Article, where the information may have evolved or changed.

Golang writing a simple image server

Image Server

The recent development process, encountered a problem, is a large number of fragmented image storage, finally I decided to study a simple image server to solve the image file storage performance problems. Here, write a blog post documenting the process of thought and the pits I've encountered.
We know that Linux storage files are not recommended to store a large number of files in a folder, so it is not only easy to consume the inode blocks of the system, it is also easy to get the file read and write speed down quickly.

Solution Solutions

Through the analysis of requirements, you can get a solution, is to make the file randomly distributed in different folders, considering the number of file clip file 1000 is a performance threshold, you can assign the file number Fileid, by the Fileid partition, you can avoid performance problems.
To increase the overall server continuity, I decided to use UInt64 as the file ID, which would provide a larger count interval and reduce the collision probability of the new Fileid.

Basic structure

The structure is simple:
Random Fileid Generator, Fileid to file path (storage path), JSON config file read, upload, download controller

Golang using JSON to make configuration files

It's worth writing here or more,

Random number generation

The random number generation section I chose the mt19937 library written by Seehuhn, project address: github.com/seehuhn/mt19937.
It is worth mentioning that this random number library to the document is not used, a simple look at the code, found that the correct usage should be:

    mt:=mt19937.New()    mt.Seed(time.Now().UnixNano())    8)    randuint64:=mt.Uint64()

Random Fileid Generator Code

funcMakeImageID()string{    mt:=mt19937.New()    mt.Seed(time.Now().UnixNano())    var buf = make([]byte, 8)    binary.BigEndian.PutUint64(buf, mt.Uint64())    return strings.ToUpper(hex.EncodeToString(buf))}

The Fileid I generated finally came in this form: the 6a778903ad673478,16 bit hexadecimal string, which is ideal for storing in a database.

Fileid goto File path

The use of a very ugly sprintf method, do not know whether this can have a more elegant wording. It is important to note that Golang does not substring the function of intercepting substrings, but rather uses slices to intercept the substrings. The concrete way is this: Substring=string[start:end]

Func Imageid2path (imageID string) string{returnFmt. Sprintf ("%s/%s/%s/%s/%s/%s/%s/%s/%s . jpg ", Conf. storage,imageid[0:2],imageid[2:4],imageid[4:6],imageid[6:8],imageid[8:Ten],imageid[Ten: A],imageid[ A: -],imageid[ -: -])}

JSON configuration file read

Golang in the best use of JSON configuration files, people good writing, machine or parsing, the official library fully supports the reading and writing of JSON, very useful.
The JSON structure I use is as follows:

{    "ListenAddr":"0.0.0.0:10086",    "Storage":"/var/www/html/image/storage"}

Parsing code:

//corresponding JSON structure  type  Config struct  {listenaddr string  Storage string }// Generate a global conf variable store read configuration  var  conf config//read configuration function  func  loadconf () {//Open file  r, err: = OS. Open ( "Config.json" ) if  err! = nil  {log. Fatalln (Err)}//decode JSON  decoder: = JSON. Newdecoder (r) Err = decoder. Decode (&conf) if  err! = nil  {log. Fatalln (Err)}}  

After calling loadconf (), you can use the configuration in conf anywhere.

Web Interface (GORILLA/MUX)

Base Route

Golang on the most simple-to-use URL router, I think is "Github.com/gorilla/mux".
To use this requires go get, forget to say, Golang reference third-party libraries need to use go get first download library code.

Create a new Web route r: = Mux. Newrouter()//This is to set the normal get path, handlefunc the first parameter is the URL, the second parameter is to respond to the function, and finally can be in the methods string to fill in the request you want to differentiate, currently I test can be used including get, POST, put and delete R. Handlefunc("/", Homehandler). Methods("GET") r. Handlefunc("/", Uploadhandler). Methods("POST")//In the URL you can enclose a variable in curly braces, which supports placement anywhere in the URL.    It is common in restapi to write the article ID, the user ID to the URL can be implemented in this way. R. Handlefunc("/{imgid}", Downloadhandler). Methods("GET") Err: = http. Listenandserve(conf. Listenaddr, R)

How do I extract the parameters in the URL? Use in the request handler function:

    mux.Vars(r)    imageid := vars["imgid"]

R is HTTP. Request

Download processing

The code is simple and easy to see

func Downloadhandler (w http . Responsewriter, R *http . Request) {vars: = Mux. Vars (r) imageID: = Vars[ "Imgid" ] if  len  ([]rune (imageID))! = 16  {w.write ([]byte  (" Error:imageid incorrect. "))    return } Imgpath: = Imageid2path (imageID) if ! FileExist (Imgpath) {w.write ([]byte  ( "Error:image not F        Ound. "))    return } http . Servefile (W, R, Imgpath)}  

Golang HTTP package, for the server to provide file download implemented a very good encapsulation, an HTTP. Servefile (W, R, FilePath) is done, where W and R are the parameters passed in the processing function, we only need to pass in as is, FilePath is required to provide to the client file, the rest of the HTTP library will be automatically processed, including Content-type and the like.

Upload processing

Func Uploadhandler (whttp. Responsewriter, R *http. Request) {//randomly generate a non-existent Fileidvar imgidstring     for{Imgid=makeimageid ()if! FileExist (Imageid2path (Imgid)) {Break}}//upload parameter is UploadFileR.parsemultipartform ( +<< -)file, _, Err: = R.formfile ("UploadFile")ifErr! = Nil {Log. PRINTLN (Err) w.write ([]byte("Error:upload Error."))return} deferfile. Close ()//detection file typeBuff: = make ([]byte, +) _, Err =file. Read (Buff)ifErr! = Nil {Log. PRINTLN (Err) w.write ([]byte("Error:upload Error."))return} filetype: =http. Detectcontenttype (Buff)iffiletype!="Image/jpeg"{W.write ([]byte("Error:not JPEG."))return}//Wrap file pointer    Log. Println (filetype)if_, Err =file. Seek (0,0); err!=nil{Log. PRINTLN (ERR)}//Create an entire storage tree in advance (if you do not create a storage tree, the following file creation will not succeed)    ifErr=buildtree (Imgid); err!=nil{Log. PRINTLN (ERR)}//Writes the file to the imageID specified locationF, err: = OS. OpenFile (Imageid2path (imgid), OS. O_wronly|os. O_create,0666)ifErr! = Nil {Log. PRINTLN (Err) w.write ([]byte("Error:save Error."))return} defer f.close () io. Copy (F,file) W.write ([]byte(Imgid))}

Summarize

Basic development is like this, very simple we use Golang to achieve a high-performance Web image server, Golang use its unique mechanism to achieve the implementation of high concurrency without too much special processing to complete the development of the program. If you use Golang correctly, you can easily do the high-performance parallel network programming that the common language is very cumbersome to handle.
Ps:golang http built-in high concurrency support, if you write a program to use go for high concurrency, you can use the Golang go keyword, in front of your function with a go flag, he will automatically go to the coprocessor run, very convenient, Regardless of how you create the thread, the Golang kernel automatically helps you do it.
Code
Code uploaded github:https://github.com/zjyl1994/quickimageserver
There's a chance I'll increase the ability to generate thumbnails in the cloud.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.