Probably the most well known example is file buffers. Since disk I/O (especially disk access) is way slower than memory I/O, it is worth reading from / writing to disk in large chunks at once, but processing typically happens in smaller steps. So a buffer collects the many smalll bytes into a large chunk for writing, or provides the data byte by byte from memory instead of turning to the disk each time.
But the same idea can be used in network / database traffic, basically anywhere where access to a specific source / sink of data has high latency or overhead, so it is worth reading /writing large amounts of data at once, but processing happens in smaller portions. Buffers can close the gap between these conflicting needs.
Buffers also play (or at least used to play) a role in graphic cards. Rendering a large image onto screen is a complex process, and even with a fast graphic card, it may take a noticeable amount of time, while the viewer could observe the flickering of new and changing graphical elements on the screen. To avoid this, and to make the switch between contiguous frames smoother, the graphic card uses double buffering: one of the buffers contain the actual frame shown on the screen, while the next frame is prepared in the other buffer, which is not visible. Once the new frame is ready, the buffers are switched: buffer 2 becomes the active, visible buffer and buffer 1 is freed for rendering the next frame. This technique was used in all graphic cards a decade ago or so - I don't know if it is still used though.
The implementation of a buffer is fundamentally very simple: you need a memory array storing the fundamental units of data (typically bytes / chars), and a pointer or iterator to keep track of where you are reading from / writing to inside the buffer. After every read / write, the pointer is moved forward accordingly. A read buffer is filled with data from the source prior to starting the processing, then once all the data has been processed, a new chunk of data is read and the pointer is reset to the beginning of the buffer again, so the processing can start over. This is all transparent to the caller of the buffer, often such a buffer is implemented as a delegate / proxy, providing the same interface as the real data source, so all the caller sees is that it is reading data from the source (a file, a network socket, a DB table). Of course, the caller may observe timeouts between subsequent reads/writes when the source is being accessed in the background.
A related concept is queues. A queue is a more structured collections containing elements of a specific type. The main difference between a buffer and a queue is that a queue may be accessed by multiple threads in parallel, some of which are pushing data into it, others are popping elements out of it. For a queue, elements are typically pushed to the end, and popped from the beginning, thus queues are often referred to as LIFO (Last In First Out) data structures. The typical usage of queues are in "producer-consumer" systems, where one or more threads / processes are producing some data, and other thread(s) are consuming the data. The queue serves to decouple producers from consumers and to simplify their interactions.